From 9b80b6621c888d551d2239853b6172668ed791c0 Mon Sep 17 00:00:00 2001 From: Richard Frith-Macdonald Date: Sat, 29 Oct 2005 09:23:09 +0000 Subject: [PATCH] More flexibility about the period over which stats are maintained Better differentiation between duration/noduration logging git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/performance/trunk@21901 72102866-910b-0410-8b05-ffd578937521 --- GSThroughput.h | 40 ++++- GSThroughput.m | 391 +++++++++++++++++++++++++++++++++++-------------- 2 files changed, 322 insertions(+), 109 deletions(-) diff --git a/GSThroughput.h b/GSThroughput.h index 8fea87c..7f8ba4b 100644 --- a/GSThroughput.h +++ b/GSThroughput.h @@ -64,13 +64,16 @@ + (void) tick; /** - * Add to the count of the number of transactions in the current second. - * Use this only if you are not logging event durations. + * Add to the count of the number of transactions in the current second.
+ * You may use this method only if the receiver was initialised with + * duration logging turned off. */ - (void) add: (unsigned)count; /** - * Adds a record for a single event of the specified duration. + * Adds a record for a single event of the specified duration.
+ * You may use this method only if the receiver was initialised with + * duration logging turned on. */ - (void) addDuration: (NSTimeInterval)length; @@ -79,6 +82,29 @@ */ - (NSString*) description; +/** + * Ends duration recording for the current event started by a matching + * call to -startDuration.
+ * You may use this method only if the receiver was initialised with + * duration logging turned on. + */ +- (void) endDuration; + +/** + * Initialises the receiver for duration logging for fifteen minute + * periods over the last twentyfour hours. + */ + - (id) init; + +/** + * Initialises the receiver to maintain stats over a particular time range, + * specifying whether duration statistics are to be maintained, or just + * event/transation counts. + */ +- (id) initWithDurations: (BOOL)aFlag + forPeriods: (unsigned)numberOfPeriods + ofLength: (unsigned)minutesPerPeriod; + /** * Return the name of this instance (as set using -setName:) */ @@ -89,6 +115,14 @@ */ - (void) setName: (NSString*)name; +/** + * Starts recording the duration of an event. This must be followed by + * a matching call to -endDuration.
+ * You may use this method only if the receiver was initialised with + * duration logging turned on. + */ +- (void) startDuration; + /** * Internal method called by +tick in order to update stats for this instance. */ diff --git a/GSThroughput.m b/GSThroughput.m index 1bbeb8e..47e4086 100644 --- a/GSThroughput.m +++ b/GSThroughput.m @@ -64,26 +64,42 @@ inline unsigned GSThroughputTimeTick() static NSHashTable *GSThroughputInstances = 0; static NSLock *GSThroughputLock = nil; +typedef struct { + unsigned cnt; // Number of events. + unsigned tick; // Start time +} CInfo; + typedef struct { unsigned cnt; // Number of events. NSTimeInterval max; // Longest duration NSTimeInterval min; // Shortest duration NSTimeInterval sum; // Total (sum of durations for event) - unsigned tick; -} Info; + unsigned tick; // Start time +} DInfo; typedef struct { - Info seconds[60]; - Info minutes[60]; - Info hours[24]; - unsigned second; - unsigned minute; - unsigned hour; - unsigned last; // last tick used - NSString *name; + void *seconds; + void *minutes; + void *periods; + BOOL supportDurations; + unsigned numberOfPeriods; + unsigned minutesPerPeriod; + unsigned second; + unsigned minute; + unsigned period; + unsigned last; // last tick used + NSTimeInterval started; // When duration logging started. + NSString *name; } Item; #define my ((Item*)&self[1]) +#define cseconds ((CInfo*)my->seconds) +#define cminutes ((CInfo*)my->minutes) +#define cperiods ((CInfo*)my->periods) +#define dseconds ((DInfo*)my->seconds) +#define dminutes ((DInfo*)my->minutes) +#define dperiods ((DInfo*)my->periods) + + (NSArray*) allInstances { NSArray *a; @@ -192,35 +208,43 @@ typedef struct { - (void) add: (unsigned)count { - my->seconds[my->second].cnt += count; + NSAssert(my->supportDurations == NO, @"configured for durations"); + cseconds[my->second].cnt += count; } - (void) addDuration: (NSTimeInterval)length { - if (my->seconds[my->second].cnt++ == 0) + DInfo *info; + + NSAssert(my->supportDurations == YES, @"not configured for durations"); + info = &dseconds[my->second]; + if (info->cnt++ == 0) { - my->seconds[my->second].min = length; - my->seconds[my->second].max = length; - my->seconds[my->second].sum = length; + info->min = length; + info->max = length; + info->sum = length; } else { - my->seconds[my->second].sum += length; - if (length > my->seconds[my->second].max) + info->sum += length; + if (length > info->max) { - my->seconds[my->second].max = length; + info->max = length; } - if (length < my->seconds[my->second].min) + if (length < info->min) { - my->seconds[my->second].min = length; + info->min = length; } } } - - (void) dealloc { [GSThroughputLock lock]; + if (my->seconds != 0) + { + NSZoneFree(NSDefaultMallocZone(), my->seconds); + } RELEASE(my->name); NSHashRemove(GSThroughputInstances, (void*)self); NSDeallocateObject(self); @@ -229,6 +253,7 @@ typedef struct { - (NSString*) description { + CREATE_AUTORELEASE_POOL(pool); NSString *n = my->name; NSMutableString *m; unsigned i; @@ -238,74 +263,174 @@ typedef struct { n = [super description]; } m = [n mutableCopy]; - if (my->second > 0) - { - [m appendString: @"\nCurrent minute:\n"]; - for (i = 0; i < my->second; i++) - { - Info *info = &my->seconds[i]; - NSTimeInterval ti = info->tick + baseTime; - [m appendFormat: @"%u, %g, %g, %g, %@\n", - info->cnt, info->max, info->min, info->sum, - [NSDate dateWithTimeIntervalSinceReferenceDate: ti]]; - } - } - - if (my->minute > 0) - { - [m appendString: @"\nCurrent hour:\n"]; - for (i = 0; i < my->minute; i++) - { - Info *info = &my->minutes[i]; - NSTimeInterval ti = info->tick + baseTime; - - [m appendFormat: @"%u, %g, %g, %g, %@\n", - info->cnt, info->max, info->min, info->sum, - [NSDate dateWithTimeIntervalSinceReferenceDate: ti]]; - } - } - - if (my->hour > 0) - { - [m appendString: @"\nCurrent day:\n"]; - for (i = 0; i < my->hour; i++) - { - Info *info = &my->hours[i]; - NSTimeInterval ti = info->tick + baseTime; - - [m appendFormat: @"%u, %g, %g, %g, %@\n", - info->cnt, info->max, info->min, info->sum, - [NSDate dateWithTimeIntervalSinceReferenceDate: ti]]; + if (my->supportDurations == YES) + { + if (my->second > 0) + { + [m appendString: @"\nCurrent minute:\n"]; + for (i = 0; i < my->second; i++) + { + DInfo *info = &dseconds[i]; + NSTimeInterval ti = info->tick + baseTime; + + [m appendFormat: @"%u, %g, %g, %g, %@\n", + info->cnt, info->max, info->min, info->sum, + [NSDate dateWithTimeIntervalSinceReferenceDate: ti]]; + } + } + + if (my->minute > 0) + { + [m appendString: @"\nCurrent period:\n"]; + for (i = 0; i < my->minute; i++) + { + DInfo *info = &dminutes[i]; + NSTimeInterval ti = info->tick + baseTime; + + [m appendFormat: @"%u, %g, %g, %g, %@\n", + info->cnt, info->max, info->min, info->sum, + [NSDate dateWithTimeIntervalSinceReferenceDate: ti]]; + } + } + + if (my->period > 0) + { + [m appendString: @"\nPrevious periods:\n"]; + for (i = 0; i < my->period; i++) + { + DInfo *info = &dperiods[i]; + NSTimeInterval ti = info->tick + baseTime; + + [m appendFormat: @"%u, %g, %g, %g, %@\n", + info->cnt, info->max, info->min, info->sum, + [NSDate dateWithTimeIntervalSinceReferenceDate: ti]]; + } + } + } + else + { + if (my->second > 0) + { + [m appendString: @"\nCurrent minute:\n"]; + for (i = 0; i < my->second; i++) + { + CInfo *info = &cseconds[i]; + NSTimeInterval ti = info->tick + baseTime; + + [m appendFormat: @"%u, %@\n", info->cnt, + [NSDate dateWithTimeIntervalSinceReferenceDate: ti]]; + } + } + + if (my->minute > 0) + { + [m appendString: @"\nCurrent period:\n"]; + for (i = 0; i < my->minute; i++) + { + CInfo *info = &cminutes[i]; + NSTimeInterval ti = info->tick + baseTime; + + [m appendFormat: @"%u, %@\n", info->cnt, + [NSDate dateWithTimeIntervalSinceReferenceDate: ti]]; + } + } + + if (my->period > 0) + { + [m appendString: @"\nPrevious periods:\n"]; + for (i = 0; i < my->period; i++) + { + CInfo *info = &cperiods[i]; + NSTimeInterval ti = info->tick + baseTime; + + [m appendFormat: @"%u, %@\n", info->cnt, + [NSDate dateWithTimeIntervalSinceReferenceDate: ti]]; + } } } + DESTROY(pool); return AUTORELEASE(m); } +- (void) endDuration +{ + NSAssert(my->started > 0.0, NSInternalInconsistencyException); + [self addDuration: (*tiImp)(NSDateClass, tiSel) - my->started]; + my->started = 0.0; +} + - (id) init +{ + return [self initWithDurations: YES + forPeriods: 96 + ofLength: 15]; +} + +- (id) initWithDurations: (BOOL)aFlag + forPeriods: (unsigned)numberOfPeriods + ofLength: (unsigned)minutesPerPeriod { NSCalendarDate *c; unsigned i; - for (i = 0; i < 24; i++) + if (numberOfPeriods < 1 || minutesPerPeriod < 1) { - my->hours[i].min = MAXDURATION; - } - for (i = 0; i < 60; i++) - { - my->seconds[i].min = MAXDURATION; - my->minutes[i].min = MAXDURATION; + DESTROY(self); + return nil; } + my->supportDurations = aFlag; + my->numberOfPeriods = numberOfPeriods; + my->minutesPerPeriod = minutesPerPeriod; my->last = GSThroughputTimeTick() - 1; c = [[NSCalendarDate alloc] initWithTimeIntervalSinceReferenceDate: lastTime]; my->second = [c secondOfMinute]; - my->minute = [c minuteOfHour]; - my->hour = [c hourOfDay]; + i = [c hourOfDay] * 60 + [c minuteOfHour]; + my->minute = i % minutesPerPeriod; + my->period = i / minutesPerPeriod; RELEASE(c); - my->seconds[my->second].tick = my->last; - my->minutes[my->minute].tick = my->last; - my->hours[my->hour].tick = my->last; + + i = 60 + minutesPerPeriod + numberOfPeriods; + if (my->supportDurations == YES) + { + DInfo *ptr; + + ptr = (DInfo*)NSZoneMalloc(NSDefaultMallocZone(), sizeof(DInfo) * i); + memset(ptr, '\0', sizeof(DInfo) * i); + my->seconds = ptr; + my->minutes = &ptr[60]; + my->periods = &ptr[60 + minutesPerPeriod]; + dseconds[my->second].tick = my->last; + dminutes[my->minute].tick = my->last; + dperiods[my->period].tick = my->last; + + for (i = 0; i < my->numberOfPeriods; i++) + { + dperiods[i].min = MAXDURATION; + } + for (i = 0; i < my->minutesPerPeriod; i++) + { + dminutes[i].min = MAXDURATION; + } + for (i = 0; i < 60; i++) + { + dseconds[i].min = MAXDURATION; + } + } + else + { + CInfo *ptr; + + ptr = (CInfo*)NSZoneMalloc(NSDefaultMallocZone(), sizeof(CInfo) * i); + memset(ptr, '\0', sizeof(CInfo) * i); + my->seconds = ptr; + my->minutes = &ptr[60]; + my->periods = &ptr[60 + minutesPerPeriod]; + dseconds[my->second].tick = my->last; + dminutes[my->minute].tick = my->last; + dperiods[my->period].tick = my->last; + } return self; } @@ -319,42 +444,33 @@ typedef struct { ASSIGN(my->name, name); } +- (void) startDuration +{ + NSAssert(my->supportDurations == YES && my->started == 0.0, + NSInternalInconsistencyException); + my->started = (*tiImp)(NSDateClass, tiSel); +} + - (void) update { unsigned tick = GSThroughputTimeTick(); + unsigned i; - while (my->last < tick) + if (my->supportDurations == YES) { - Info *info; - unsigned i; - - if (my->second++ == 59) + while (my->last < tick) { - info = &my->minutes[my->minute]; - for (i = 0; i < 60; i++) - { - Info *from = &my->seconds[i]; + DInfo *info; - info->cnt += from->cnt; - if (from->min < info->min) - { - info->min = from->min; - } - if (from->max > info->max) - { - info->max = from->max; - } - info->sum += from->sum; - } - if (my->minute++ == 59) + if (my->second++ == 59) { - info = &my->hours[my->hour]; + info = &dminutes[my->minute]; for (i = 0; i < 60; i++) { - Info *from = &my->minutes[i]; + DInfo *from = &dseconds[i]; info->cnt += from->cnt; - if (from->min > 0.0 && from->min < info->min) + if (from->min < info->min) { info->min = from->min; } @@ -364,31 +480,94 @@ typedef struct { } info->sum += from->sum; } - if (my->hour++ == 23) + if (my->minute++ == my->minutesPerPeriod) { + info = &dperiods[my->period]; + for (i = 0; i < my->minutesPerPeriod; i++) + { + DInfo *from = &dminutes[i]; + + info->cnt += from->cnt; + if (from->min > 0.0 && from->min < info->min) + { + info->min = from->min; + } + if (from->max > info->max) + { + info->max = from->max; + } + info->sum += from->sum; + } + if (my->period++ == my->numberOfPeriods) + { + my->period = 0; + } + info = &dperiods[my->period]; + info->cnt = 0; + info->max = 0.0; + info->min = MAXDURATION; + info->sum = 0.0; + info->tick = tick; + my->minute = 0; } - info = &my->hours[my->hour]; + info = &dminutes[my->minute]; info->cnt = 0; info->max = 0.0; info->min = MAXDURATION; info->sum = 0.0; info->tick = tick; + my->second = 0; } - info = &my->minutes[my->minute]; + info = &dseconds[my->second]; info->cnt = 0; info->max = 0.0; info->min = MAXDURATION; info->sum = 0.0; info->tick = tick; - } - info = &my->seconds[my->second]; - info->cnt = 0; - info->max = 0.0; - info->min = MAXDURATION; - info->sum = 0.0; - info->tick = tick; - my->last++; + my->last++; + } + } + else + { + while (my->last < tick) + { + CInfo *info; + + if (my->second++ == 59) + { + info = &cminutes[my->minute]; + for (i = 0; i < 60; i++) + { + info->cnt += cseconds[i].cnt; + } + if (my->minute++ == my->minutesPerPeriod) + { + info = &cperiods[my->period]; + for (i = 0; i < my->minutesPerPeriod; i++) + { + info->cnt += cminutes[i].cnt; + } + if (my->period++ == my->numberOfPeriods) + { + my->period = 0; + } + info = &cperiods[my->period]; + info->cnt = 0; + info->tick = tick; + my->minute = 0; + } + info = &cminutes[my->minute]; + info->cnt = 0; + info->tick = tick; + my->second = 0; + } + info = &cseconds[my->second]; + info->cnt = 0; + info->tick = tick; + + my->last++; + } } } @end