256 [NSThread detachNewThreadSelector:@selector(watchdogTimerThread)
266#ifndef MOZ_TRACE_JSCALLS
267#warning Profiling is enabled, but MOZ_TRACE_JSCALLS is disabled, so only native functions will be profiled.
270static BOOL sProfiling = NO;
271static BOOL sTracing = NO;
272static OOJSProfileStackFrame *sProfileStack = NULL;
273static NSMapTable *sProfileInfo;
274static double sProfilerOverhead;
275static double sProfilerTotalNativeTime;
276static double sProfilerTotalJavaScriptTime;
277static double sProfilerEntryTimeLimit;
281@interface OOTimeProfile (Private)
283- (void) setTotalTime:(
double)value;
284- (void) setNativeTime:(
double)value;
285#ifdef MOZ_TRACE_JSCALLS
286- (void) setJavaScriptTime:(
double)value;
288- (void) setProfilerOverhead:(
double)value;
289- (void) setExtensionTime:(
double)value;
290- (void) setProfileEntries:(NSArray *)value;
292- (NSDictionary *) propertyListRepresentation;
297@interface OOTimeProfileEntry (Private)
299- (id) initWithCName:(const
char *)name;
300#ifdef MOZ_TRACE_JSCALLS
301- (id) initWithJSFunction:(JSFunction *)function context:(JSContext *)context;
306- (NSDictionary *) propertyListRepresentation;
311void OOJSBeginProfiling(BOOL trace)
313 assert(sProfiling == NO);
316 sProfileInfo = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks, NSObjectMapValueCallBacks, 100);
317 sProfilerOverhead = 0.0;
318 sProfilerTotalNativeTime = 0.0;
319 sProfilerTotalJavaScriptTime = 0.0;
327 OOLog(
@"script.javaScript.trace",
@"%@",
@">>>> Beginning trace.");
333OOTimeProfile *OOJSEndProfiling(
void)
340 assert(sProfiling && sProfileStack == NULL);
344 OOTimeProfile *result = [[OOTimeProfile alloc] init];
346 [result setTotalTime:OOHighResTimeDeltaInSeconds(sProfilerStartTime, now)];
347 [result setNativeTime:sProfilerTotalNativeTime];
348#ifdef MOZ_TRACE_JSCALLS
349 [result setJavaScriptTime:sProfilerTotalJavaScriptTime];
351 [result setProfilerOverhead:sProfilerOverhead];
354 [result setExtensionTime:currentTimeLimit - sProfilerEntryTimeLimit];
356 [result setProfileEntries:[NSAllMapTableValues(sProfileInfo) sortedArrayUsingSelector:@selector(compareBySelfTimeReverse:)]];
361 OOLog(
@"script.javaScript.trace",
@"%@",
@"<<<< End of trace.");
366 NSFreeMapTable(sProfileInfo);
376BOOL OOJSIsProfiling(
void)
381void OOJSBeginTracing(
void);
382void OOJSEndTracing(
void);
383BOOL OOJSIsTracing(
void);
386static void UpdateProfileForFrame(
OOHighResTimeValue now, OOJSProfileStackFrame *frame);
389#ifdef MOZ_TRACE_JSCALLS
390static void CleanUpJSFrame(OOJSProfileStackFrame *frame)
396static void TraceEnterJSFunction(JSContext *context, JSFunction *
function, OOTimeProfileEntry *profileEntry)
398 NSMutableString *name = [NSMutableString stringWithFormat:@"%@(", [profileEntry function]];
399 BOOL isNative = JS_GetFunctionNative(context,
function) != NULL;
400 NSString *frameTag =
nil;
401 NSString *logMsgClass =
nil;
406 JSStackFrame *frame = NULL;
410 JSPropertyDescArray properties = { 0 , NULL };
416 if (JS_FrameIterator(context, &frame) != NULL)
418 if (JS_IsConstructorFrame(context, frame))
420 [name insertString:@"new " atIndex:0];
423 if (JS_GetFrameThis(context, frame, &
this))
425 [name appendFormat:@"this: %@", OOJSDescribeValue(context, this, YES)];
429 scope = JS_GetFrameScopeChain(context, frame);
430 if (scope != NULL && JS_GetPropertyDescArray(context, scope, &properties))
432 for (i = 0; i < properties.length; i++)
434 JSPropertyDesc *prop = &properties.array[i];
435 if (prop->flags & JSPD_ARGUMENT)
437 if (!first) [name appendFormat:
@", "];
440 [name appendFormat:
@"%@: %@", OOStringFromJSValueEvenIfNull(context, prop->id), OOJSDescribeValue(context, prop->value, YES)];
449 logMsgClass =
@"script.javaScript.trace.JS";
454 logMsgClass =
@"script.javaScript.trace.NW";
457 [name appendString:@")"];
458 OOLog(logMsgClass,
@">> %@ [%@]", name, frameTag);
463static void FunctionCallback(JSFunction *
function, JSScript *script, JSContext *context,
int entering)
465 if (
EXPECT(!sProfiling))
return;
469 if (!sTracing && JS_GetFunctionNative(context,
function) != NULL)
return;
473 NSAutoreleasePool *pool = [NSAutoreleasePool new];
478 OOTimeProfileEntry *entry = NSMapGet(sProfileInfo,
function);
481 entry = [[OOTimeProfileEntry alloc] initWithJSFunction:function context:context];
482 NSMapInsertKnownAbsent(sProfileInfo,
function, entry);
489 TraceEnterJSFunction(context,
function, entry);
493 OOJSProfileStackFrame *frame = malloc(
sizeof(OOJSProfileStackFrame));
494 assert(frame != NULL);
496 *frame = (OOJSProfileStackFrame)
498 .back = sProfileStack,
502 .total = &sProfilerTotalJavaScriptTime,
503 .cleanup = CleanUpJSFrame
506 sProfileStack = frame;
511 assert(sProfileStack != NULL && sProfileStack->cleanup == CleanUpJSFrame);
513 UpdateProfileForFrame(start, sProfileStack);
520 sProfilerOverhead += currentOverhead;
529 if (
EXPECT(!sProfiling))
return;
533 OOLog(
@"script.javaScript.trace.ON",
@">> %s [ON]",
function);
537 *frame = (OOJSProfileStackFrame)
539 .back = sProfileStack,
541 .function =
function,
543 .total = &sProfilerTotalNativeTime
545 sProfileStack = frame;
551 if (
EXPECT(!sProfiling))
return;
554 NSAutoreleasePool *pool = [NSAutoreleasePool new];
565 assert(sProfileStack != NULL);
567 done = (sProfileStack == frame);
568 UpdateProfileForFrame(now, sProfileStack);
578 sProfilerOverhead += currentOverhead;
591static void UpdateProfileForFrame(
OOHighResTimeValue now, OOJSProfileStackFrame *frame)
593 sProfileStack = frame->back;
595 OOTimeProfileEntry *entry = NSMapGet(sProfileInfo, frame->key);
598 entry = [[OOTimeProfileEntry alloc] initWithCName:frame->function];
599 NSMapInsertKnownAbsent(sProfileInfo, frame->key, entry);
605 [entry addSampleWithTotalTime:time selfTime:selfTime];
607 *(frame->total) += selfTime;
608 if (sProfileStack != NULL) sProfileStack->subTime += time;
610 if (frame->cleanup != NULL) frame->cleanup(frame);
616@implementation OOTimeProfile
626- (NSString *) description
628 double totalTime = [
self totalTime];
630 NSMutableString *result = [NSMutableString stringWithFormat:
631 @"Total time: %g ms\n"
632 "JavaScript: %g ms, native: %g ms\n"
633 "Counted towards limit: %g ms, excluded: %g ms\n"
634 "Profiler overhead: %g ms",
636 [
self javaScriptTime] * 1000.0, [
self nativeTime] * 1000.0,
637 [
self nonExtensionTime] * 1000.0, [
self extensionTime] * 1000.0,
638 [
self profilerOverhead] * 1000.0];
640 NSArray *profileEntries = [
self profileEntries];
641 NSUInteger i,
count = [profileEntries count];
644 [result appendString:@"\n NAME T COUNT TOTAL SELF TOTAL% SELF% SELFMAX"];
645 for (i = 0; i <
count; i++)
649 OOTimeProfileEntry *entry = [profileEntries objectAtIndex:i];
651 double totalPc = [entry totalTimeSum] * 100.0 / totalTime;
652 double selfPc = [entry selfTimeSum] * 100.0 / totalTime;
654 [result appendFormat:@"\n%60s %c%7lu %8.2f %8.2f %5.1f %5.1f %8.2f",
655 [[entry function] UTF8String],
656 [entry isJavaScriptFrame] ? 'J' : 'N',
657 (unsigned long)[entry hitCount], [entry totalTimeSum] * 1000.0, [entry selfTimeSum] * 1000.0, totalPc, selfPc, [entry selfTimeMax] * 1000.0];
671- (void) setTotalTime:(
double)value
677- (double) javaScriptTime
679#ifdef MOZ_TRACE_JSCALLS
680 return _javaScriptTime;
682 return _totalTime - _nativeTime;
687#ifdef MOZ_TRACE_JSCALLS
688- (void) setJavaScriptTime:(
double)value
690 _javaScriptTime = value;
701- (void) setNativeTime:(
double)value
707- (double) extensionTime
709 return _extensionTime;
713- (void) setExtensionTime:(
double)value
715 _extensionTime = value;
719- (double) nonExtensionTime
721 return _totalTime - _extensionTime;
725- (double) profilerOverhead
727 return _profilerOverhead;
731- (void) setProfilerOverhead:(
double)value
733 _profilerOverhead = value;
737- (NSArray *) profileEntries
739 return _profileEntries;
743- (void) setProfileEntries:(NSArray *)value
745 if (_profileEntries != value)
747 [_profileEntries release];
748 _profileEntries = [value retain];
753- (jsval) oo_jsValueInContext:(JSContext *)context
759- (NSDictionary *) propertyListRepresentation
761 NSArray *profileEntries = [
self profileEntries];
762 NSMutableArray *convertedEntries = [NSMutableArray arrayWithCapacity:[profileEntries count]];
763 NSEnumerator *entryEnum =
nil;
764 OOTimeProfileEntry *entry =
nil;
765 for (entryEnum = [profileEntries objectEnumerator]; (entry = [entryEnum nextObject]); )
767 [convertedEntries addObject:[entry propertyListRepresentation]];
770 return [NSDictionary dictionaryWithObjectsAndKeys:
771 profileEntries, @"profiles",
772 [NSNumber numberWithDouble:[
self totalTime]], @"totalTime",
773 [NSNumber numberWithDouble:[
self javaScriptTime]], @"javaScriptTime",
774 [NSNumber numberWithDouble:[
self nativeTime]], @"nativeTime",
775 [NSNumber numberWithDouble:[
self extensionTime]], @"extensionTime",
776 [NSNumber numberWithDouble:[
self nonExtensionTime]], @"nonExtensionTime",
777 [NSNumber numberWithDouble:[
self profilerOverhead]], @"profilerOverhead",
784@implementation OOTimeProfileEntry
786- (id) initWithCName:(const
char *)name
788 NSAssert(sProfiling,
@"Can't create profile entries while not profiling.");
790 if ((
self = [super init]))
794 _function = [[NSString stringWithUTF8String:name] retain];
803- (id) initWithJSFunction:(JSFunction *)function context:(JSContext *)context
805 if ((
self = [
self initWithCName:NULL]))
809 _jsFunction =
function;
811 NSString *funcName =
nil;
812 JSString *jsName = JS_GetFunctionId(_jsFunction);
813 if (jsName != NULL) funcName = [OOStringFromJSString(context, jsName) retain];
814 else funcName =
@"<anonymous>";
817 NSString *location =
nil;
818 if (JS_GetFunctionNative(context,
function) == NULL)
820 JSStackFrame *frame = NULL;
821 if (JS_FrameIterator(context, &frame) != NULL)
829 _function = [[NSString alloc] initWithFormat:@"(%@) %@", location, funcName];
831 else _function = [funcName retain];
852 _totalTimeSum += totalTime;
853 _selfTimeSum += selfTime;
854 _totalTimeMax = fmax(_totalTimeMax, totalTime);
855 _selfTimeMax = fmax(_selfTimeMax, selfTime);
859- (NSString *) description
861 if (_hitCount == 0)
return [NSString stringWithFormat:@"%@: --", _function];
864 float totalTimeSum = _totalTimeSum * 1000.0;
865 float selfTimeSum = _selfTimeSum * 1000.0;
866 float totalTimeMax = _totalTimeMax * 1000.0;
867 float selfTimeMax = _selfTimeMax * 1000.0;
869 if (totalTimeSum == selfTimeSum && totalTimeMax == selfTimeMax)
873 return [NSString stringWithFormat:@"%@: 1 time, %g ms", _function, totalTimeSum];
877 return [NSString stringWithFormat:@"%@: %lu times, total %g ms, avg %g ms, max %g ms", _function, _hitCount, totalTimeSum, totalTimeSum / _hitCount, totalTimeMax];
884 return [NSString stringWithFormat:@"%@: 1 time, %g ms (self %g ms)", _function, totalTimeSum, selfTimeSum];
888 return [NSString stringWithFormat:@"%@: %lu times, total %g ms (self %g ms), avg %g ms (self %g ms), max %g ms, max self %g ms", _function, _hitCount, totalTimeSum, selfTimeSum, totalTimeSum / _hitCount, selfTimeSum / _hitCount, totalTimeMax, selfTimeMax];
894- (NSString *) function
900- (NSUInteger) hitCount
906- (double) totalTimeSum
908 return _totalTimeSum;
912- (double) selfTimeSum
918- (double) totalTimeAverage
920 return _hitCount ? (_totalTimeSum / _hitCount) : 0.0;
924- (double) selfTimeAverage
926 return _hitCount ? (_selfTimeSum / _hitCount) : 0.0;
930- (double) totalTimeMax
932 return _totalTimeMax;
936- (double) selfTimeMax
942- (BOOL) isJavaScriptFrame
945 return _jsFunction != NULL;
952- (NSComparisonResult) compareByTotalTime:(OOTimeProfileEntry *)other
954 return -[
self compareByTotalTimeReverse:other];
958- (NSComparisonResult) compareByTotalTimeReverse:(OOTimeProfileEntry *)other
960 double selfTotal = [
self totalTimeSum];
961 double otherTotal = [other totalTimeSum];
963 if (selfTotal < otherTotal)
return NSOrderedDescending;
964 if (selfTotal > otherTotal)
return NSOrderedAscending;
965 return NSOrderedSame;
969- (NSComparisonResult) compareBySelfTime:(OOTimeProfileEntry *)other
971 return -[
self compareBySelfTimeReverse:other];
975- (NSComparisonResult) compareBySelfTimeReverse:(OOTimeProfileEntry *)other
977 double selfTotal = [
self selfTimeSum];
978 double otherTotal = [other selfTimeSum];
980 if (selfTotal < otherTotal)
return NSOrderedDescending;
981 if (selfTotal > otherTotal)
return NSOrderedAscending;
982 return NSOrderedSame;
986- (jsval) oo_jsValueInContext:(JSContext *)context
992- (NSDictionary *) propertyListRepresentation
994 return [NSDictionary dictionaryWithObjectsAndKeys:
996 [NSNumber numberWithUnsignedInteger:[
self hitCount]], @"hitCount",
997 [NSNumber numberWithDouble:[
self totalTimeSum]], @"totalTimeSum",
998 [NSNumber numberWithDouble:[
self selfTimeSum]], @"selfTimeSum",
999 [NSNumber numberWithDouble:[
self totalTimeAverage]], @"totalTimeAverage",
1000 [NSNumber numberWithDouble:[
self selfTimeAverage]], @"selfTimeAverage",
1001 [NSNumber numberWithDouble:[
self totalTimeMax]], @"totalTimeMax",
1002 [NSNumber numberWithDouble:[
self selfTimeMax]], @"selfTimeMax",
1003 [NSNumber numberWithBool:[
self isJavaScriptFrame]], @"isJavaScriptFrame",