From 17557402f332c982e73967537ee6b12f69a203a7 Mon Sep 17 00:00:00 2001 From: Jens Ayton Date: Sat, 1 Jan 2011 12:56:21 +0000 Subject: [PATCH] Added profiling for JS vector and quaternion conversion functions (debug builds only). Ensured callObjC() for void-return methods always returns undefined. git-svn-id: http://svn.berlios.de/svnroot/repos/oolite-linux/trunk@3944 127b21dd-08f5-0310-b4b7-95ae10353056 --- src/Core/Debug/OOJSConsole.m | 4 +- src/Core/Scripting/OOJSQuaternion.m | 67 ++++++++++++++++++++++++++++- src/Core/Scripting/OOJSVector.m | 63 +++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 4 deletions(-) diff --git a/src/Core/Debug/OOJSConsole.m b/src/Core/Debug/OOJSConsole.m index 7133566f..3e2d6d2d 100644 --- a/src/Core/Debug/OOJSConsole.m +++ b/src/Core/Debug/OOJSConsole.m @@ -5,7 +5,7 @@ OOJSConsole.m Oolite Debug OXP -Copyright (C) 2007-2010 Jens Ayton +Copyright (C) 2007-2011 Jens Ayton Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -697,7 +697,7 @@ static JSBool ConsoleCallObjCMethod(OOJS_NATIVE_ARGS) } OOJSPauseTimeLimiter(); - jsval result; + jsval result = JSVAL_VOID; BOOL OK = OOJSCallObjCObjectMethod(context, object, [object jsClassName], argc, OOJS_ARGV, &result); OOJSResumeTimeLimiter(); diff --git a/src/Core/Scripting/OOJSQuaternion.m b/src/Core/Scripting/OOJSQuaternion.m index 1318d8d2..baa8977b 100644 --- a/src/Core/Scripting/OOJSQuaternion.m +++ b/src/Core/Scripting/OOJSQuaternion.m @@ -192,6 +192,63 @@ BOOL JSValueToQuaternion(JSContext *context, jsval value, Quaternion *outQuatern } +#if OO_DEBUG + +typedef struct +{ + OOUInteger quatCount; + OOUInteger entityCount; + OOUInteger arrayCount; + OOUInteger protoCount; + OOUInteger failCount; +} QuaternionStatistics; +static QuaternionStatistics sQuaternionConversionStats; + + +@implementation PlayerEntity (JSQuaternionStatistics) + +// :setM quatStats PS.callObjC("reportJSQuaternionStatistics") +// :quatStats + +- (NSString *) reportJSQuaternionStatistics +{ + QuaternionStatistics *stats = &sQuaternionConversionStats; + + OOUInteger sum = stats->quatCount + stats->entityCount + stats->arrayCount + stats->protoCount; + double convFac = 100.0 / sum; + + return [NSString stringWithFormat: + @"quaternion-to-quaternion conversions: %lu (%g %%)\n" + " entity-to-quaternion conversions: %lu (%g %%)\n" + " array-to-quaternion conversions: %lu (%g %%)\n" + " prototype-to-zero conversions: %lu (%g %%)\n" + " failed conversions: %lu (%g %%)\n" + " total: %lu", + (long)stats->quatCount, stats->quatCount * convFac, + (long)stats->entityCount, stats->entityCount * convFac, + (long)stats->arrayCount, stats->arrayCount * convFac, + (long)stats->protoCount, stats->protoCount * convFac, + (long)stats->failCount, stats->failCount * convFac, + (long)sum]; +} + + +- (void) clearJSQuaternionStatistics +{ + memset(&sQuaternionConversionStats, 0, sizeof sQuaternionConversionStats); +} + +@end + +#define COUNT(FIELD) do { sQuaternionConversionStats.FIELD++; } while (0) + +#else + +#define COUNT(FIELD) do {} while (0) + +#endif + + BOOL JSObjectGetQuaternion(JSContext *context, JSObject *quaternionObj, Quaternion *outQuaternion) { OOJS_PROFILE_ENTER @@ -209,6 +266,7 @@ BOOL JSObjectGetQuaternion(JSContext *context, JSObject *quaternionObj, Quaterni private = JS_GetInstancePrivate(context, quaternionObj, &sQuaternionClass, NULL); if (private != NULL) // If this is a (JS) Quaternion... { + COUNT(quatCount); *outQuaternion = *private; return YES; } @@ -216,6 +274,7 @@ BOOL JSObjectGetQuaternion(JSContext *context, JSObject *quaternionObj, Quaterni // If it's an entity, use its orientation. if (OOJSIsMemberOfSubclass(context, quaternionObj, JSEntityClass())) { + COUNT(entityCount); Entity *entity = JS_GetPrivate(context, quaternionObj); *outQuaternion = [entity orientation]; return YES; @@ -241,6 +300,8 @@ BOOL JSObjectGetQuaternion(JSContext *context, JSObject *quaternionObj, Quaterni outQuaternion->y = dVal; if (!JS_ValueToNumber(context, arrayZ, &dVal)) return NO; outQuaternion->z = dVal; + + COUNT(arrayCount); return YES; } } @@ -251,14 +312,16 @@ BOOL JSObjectGetQuaternion(JSContext *context, JSObject *quaternionObj, Quaterni Quaternion.prototype)... NOTE: it would be prettier to do this at the top when we handle normal - Vector3Ds, but it's a rare case which should be kept off the fast path. + Quaternions, but it's a rare case which should be kept off the fast path. */ if (JS_InstanceOf(context, quaternionObj, &sQuaternionClass, NULL)) { + COUNT(protoCount); *outQuaternion = kZeroQuaternion; return YES; } + COUNT(failCount); return NO; OOJS_PROFILE_EXIT @@ -491,7 +554,7 @@ static JSBool QuaternionConstruct(OOJS_NATIVE_ARGS) free(private); OOReportJSBadArguments(context, NULL, NULL, argc, OOJS_ARGV, @"Could not construct quaternion from parameters", - @"Vector, Entity or array of four numbers"); + @"Quaternion, Entity or array of four numbers"); return NO; } } diff --git a/src/Core/Scripting/OOJSVector.m b/src/Core/Scripting/OOJSVector.m index 79751fc2..3563ea0b 100644 --- a/src/Core/Scripting/OOJSVector.m +++ b/src/Core/Scripting/OOJSVector.m @@ -214,6 +214,64 @@ BOOL JSValueToVector(JSContext *context, jsval value, Vector *outVector) } +#if OO_DEBUG + +typedef struct +{ + OOUInteger vectorCount; + OOUInteger entityCount; + OOUInteger arrayCount; + OOUInteger protoCount; + OOUInteger failCount; +} VectorStatistics; +static VectorStatistics sVectorConversionStats; + + +@implementation PlayerEntity (JSVectorStatistics) + +// :setM vectorStats PS.callObjC("reportJSVectorStatistics") +// :vectorStats + +- (NSString *) reportJSVectorStatistics +{ + VectorStatistics *stats = &sVectorConversionStats; + + OOUInteger sum = stats->vectorCount + stats->entityCount + stats->arrayCount + stats->protoCount; + double convFac = 100.0 / sum; + if (sum == 0) convFac = 0; + + return [NSString stringWithFormat: + @" vector-to-vector conversions: %lu (%g %%)\n" + " entity-to-vector conversions: %lu (%g %%)\n" + " array-to-vector conversions: %lu (%g %%)\n" + "prototype-to-zero conversions: %lu (%g %%)\n" + " failed conversions: %lu (%g %%)\n" + " total: %lu", + (long)stats->vectorCount, stats->vectorCount * convFac, + (long)stats->entityCount, stats->entityCount * convFac, + (long)stats->arrayCount, stats->arrayCount * convFac, + (long)stats->protoCount, stats->protoCount * convFac, + (long)stats->failCount, stats->failCount * convFac, + (long)sum]; +} + + +- (void) clearJSVectorStatistics +{ + memset(&sVectorConversionStats, 0, sizeof sVectorConversionStats); +} + +@end + +#define COUNT(FIELD) do { sVectorConversionStats.FIELD++; } while (0) + +#else + +#define COUNT(FIELD) do {} while (0) + +#endif + + BOOL JSObjectGetVector(JSContext *context, JSObject *vectorObj, Vector *outVector) { OOJS_PROFILE_ENTER @@ -232,6 +290,7 @@ BOOL JSObjectGetVector(JSContext *context, JSObject *vectorObj, Vector *outVecto private = JS_GetInstancePrivate(context, vectorObj, &sVectorClass, NULL); if (private != NULL) { + COUNT(vectorCount); *outVector = *private; return YES; } @@ -239,6 +298,7 @@ BOOL JSObjectGetVector(JSContext *context, JSObject *vectorObj, Vector *outVecto // If it's an entity, use its position. if (OOJSIsMemberOfSubclass(context, vectorObj, JSEntityClass())) { + COUNT(entityCount); Entity *entity = JS_GetPrivate(context, vectorObj); *outVector = [entity position]; return YES; @@ -259,6 +319,7 @@ BOOL JSObjectGetVector(JSContext *context, JSObject *vectorObj, Vector *outVecto JS_ValueToNumber(context, arrayY, &y) && JS_ValueToNumber(context, arrayZ, &z)) { + COUNT(arrayCount); *outVector = make_vector(x, y, z); return YES; } @@ -275,10 +336,12 @@ BOOL JSObjectGetVector(JSContext *context, JSObject *vectorObj, Vector *outVecto */ if (JS_InstanceOf(context, vectorObj, &sVectorClass, NULL)) { + COUNT(protoCount); *outVector = kZeroVector; return YES; } + COUNT(failCount); return NO; OOJS_PROFILE_EXIT