mirror of
https://github.com/gnustep/libs-performance.git
synced 2025-02-16 00:21:29 +00:00
Add basics of throughput monitoring class
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/performance/trunk@21897 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
67a0a037b3
commit
f23e1d4545
5 changed files with 460 additions and 9 deletions
|
@ -15,13 +15,16 @@ DOCUMENT_NAME=Performance
|
|||
Performance_INTERFACE_VERSION=0.1
|
||||
|
||||
Performance_OBJC_FILES += \
|
||||
GSCache.m
|
||||
GSCache.m \
|
||||
GSThroughput.m
|
||||
|
||||
Performance_HEADER_FILES += \
|
||||
GSCache.h
|
||||
GSCache.h \
|
||||
GSThroughput.h
|
||||
|
||||
Performance_AGSDOC_FILES += \
|
||||
GSCache.h
|
||||
GSCache.h \
|
||||
GSThroughput.h
|
||||
|
||||
# Optional Java wrappers for the library
|
||||
JAVA_WRAPPER_NAME = Performance
|
||||
|
|
21
GSCache.h
21
GSCache.h
|
@ -30,9 +30,14 @@
|
|||
#include <Foundation/NSArray.h>
|
||||
|
||||
/**
|
||||
* The GSCache class is used to maintain a cache of objects.<br />
|
||||
* When full, old objects are removed to make room for new ones
|
||||
* on a least-recently-used basis.<br />
|
||||
* The GSCache class is used to maintain a cache of objects in memory
|
||||
* for relatiovely rapid access.<br />
|
||||
* Typical usage might be to keep the results of a database query around
|
||||
* for a while in order to re-use them ... for instance when application
|
||||
* configuration is obtained from a database which might be updated while
|
||||
* the application is running.<br />
|
||||
* When the cache is full, old objects are removed to make room for new
|
||||
* ones on a least-recently-used basis.<br />
|
||||
* Cache sizes may be limited by the number of objects in the cache,
|
||||
* or by the memory used by the cache, or both. Calculation of the
|
||||
* size of items in the cache is relatively expensive, so caches are
|
||||
|
@ -50,7 +55,7 @@
|
|||
* Return all the current cache instances... useful if you want to do
|
||||
* something to all cache instances in your process.
|
||||
*/
|
||||
+ (NSArray*) allCaches;
|
||||
+ (NSArray*) allInstances;
|
||||
|
||||
/**
|
||||
* Return a report on all GSCache instances ... calls the [GSCache-description]
|
||||
|
@ -204,7 +209,13 @@
|
|||
* valid (has expired).<br />
|
||||
* If the method returns YES, then anObject will not be removed as it
|
||||
* normally would. This allows the delegate to change the cached item
|
||||
* or refresh it.
|
||||
* or refresh it.<br />
|
||||
* For instance, the delegate could replace the object
|
||||
* in the cache before returning YES in order to update the cached value
|
||||
* when its lifetime has expired.<br />
|
||||
* Another possibility would be for the delegate to return YES (in order
|
||||
* to continue using the existing object) and queue an asynchronous
|
||||
* database query to update the cache later.
|
||||
*/
|
||||
- (BOOL) shouldKeepItem: (id)anObject
|
||||
withKey: (NSString*)aKey
|
||||
|
|
|
@ -150,7 +150,7 @@ static void removeItem(GSCacheItem *item, GSCacheItem **first)
|
|||
item->prev = item->next = item;
|
||||
}
|
||||
|
||||
+ (NSArray*) allCaches
|
||||
+ (NSArray*) allInstances
|
||||
{
|
||||
NSArray *a;
|
||||
|
||||
|
|
99
GSThroughput.h
Normal file
99
GSThroughput.h
Normal file
|
@ -0,0 +1,99 @@
|
|||
/**
|
||||
Copyright (C) 2005 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Richard Frith-Macdonald <rfm@gnu.org>
|
||||
Date: October 2005
|
||||
|
||||
This file is part of the Performance Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$Date$ $Revision$
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_GSThroughput_H
|
||||
#define INCLUDED_GSThroughput_H
|
||||
|
||||
#include <Foundation/NSObject.h>
|
||||
#include <Foundation/NSArray.h>
|
||||
|
||||
/**
|
||||
* The GSThroughput class is used maintain statistics about the number
|
||||
* of events or the duration of operations in your software.
|
||||
*/
|
||||
@interface GSThroughput : NSObject
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the current throughput measuring objects ...
|
||||
* useful if you want to do to all instances in your process.
|
||||
*/
|
||||
+ (NSArray*) allInstances;
|
||||
|
||||
/**
|
||||
* Return a report on all GSThroughput instances ... calls
|
||||
* the [GSThroughput-description] * method of the individual
|
||||
* instances to get a report on each one.
|
||||
*/
|
||||
+ (NSString*) description;
|
||||
|
||||
/**
|
||||
* Instructs the minitoring system to use a timer at the specified interval
|
||||
* for keeping its idea of the current time up to date.
|
||||
*/
|
||||
+ (void) setTick: (NSTimeInterval)interval;
|
||||
|
||||
/**
|
||||
* Updates the monitoring system's notion of the current time.<br />
|
||||
* This should be called at the start of each (or more often) if
|
||||
* you want accurate monitoring by the second.
|
||||
*/
|
||||
+ (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.
|
||||
*/
|
||||
- (void) add: (unsigned)count;
|
||||
|
||||
/**
|
||||
* Adds a record for a single event of the specified duration.
|
||||
*/
|
||||
- (void) addDuration: (NSTimeInterval)length;
|
||||
|
||||
/**
|
||||
* Returns a string describing the status of the receiver for debug/reporting.
|
||||
*/
|
||||
- (NSString*) description;
|
||||
|
||||
/**
|
||||
* Return the name of this instance (as set using -setName:)
|
||||
*/
|
||||
- (NSString*) name;
|
||||
|
||||
/**
|
||||
* Sets the name of this instance.
|
||||
*/
|
||||
- (void) setName: (NSString*)name;
|
||||
|
||||
/**
|
||||
* Internal method called by +tick in order to update stats for this instance.
|
||||
*/
|
||||
- (void) update;
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
338
GSThroughput.m
Normal file
338
GSThroughput.m
Normal file
|
@ -0,0 +1,338 @@
|
|||
/* -*-objc-*- */
|
||||
|
||||
/** Implementation of GSThroughput for GNUStep
|
||||
Copyright (C) 2005 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Richard Frith-Macdonald <rfm@gnu.org>
|
||||
Date: October 2005
|
||||
|
||||
This file is part of the Performance Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$Date$ $Revision$
|
||||
*/
|
||||
|
||||
#include <Foundation/NSArray.h>
|
||||
#include <Foundation/NSString.h>
|
||||
#include <Foundation/NSData.h>
|
||||
#include <Foundation/NSDate.h>
|
||||
#include <Foundation/NSException.h>
|
||||
#include <Foundation/NSNotification.h>
|
||||
#include <Foundation/NSHashTable.h>
|
||||
#include <Foundation/NSMapTable.h>
|
||||
#include <Foundation/NSLock.h>
|
||||
#include <Foundation/NSAutoreleasePool.h>
|
||||
#include <Foundation/NSValue.h>
|
||||
#include <Foundation/NSDebug.h>
|
||||
#include <Foundation/NSSet.h>
|
||||
#include <Foundation/NSTimer.h>
|
||||
|
||||
#include "GSThroughput.h"
|
||||
|
||||
#define MAXDURATION 24.0*60.0*60.0
|
||||
|
||||
static Class NSDateClass = 0;
|
||||
static SEL tiSel = 0;
|
||||
static NSTimeInterval (*tiImp)(Class,SEL) = 0;
|
||||
|
||||
static NSTimer *theTimer = nil;
|
||||
static NSTimeInterval baseTime = 0;
|
||||
static NSTimeInterval lastTime = 0;
|
||||
|
||||
inline unsigned GSThroughputTimeTick()
|
||||
{
|
||||
return (lastTime - baseTime) + 1;
|
||||
}
|
||||
|
||||
|
||||
@implementation GSThroughput
|
||||
|
||||
static NSHashTable *GSThroughputInstances = 0;
|
||||
static NSLock *GSThroughputLock = nil;
|
||||
|
||||
typedef struct {
|
||||
unsigned cnt; // Number of events.
|
||||
NSTimeInterval max; // Longest duration
|
||||
NSTimeInterval min; // Shortest duration
|
||||
NSTimeInterval sum; // Total (sum of durations for event)
|
||||
} Info;
|
||||
|
||||
typedef struct {
|
||||
Info seconds[60];
|
||||
Info minutes[60];
|
||||
Info hours[24];
|
||||
unsigned second;
|
||||
unsigned minute;
|
||||
unsigned hour;
|
||||
unsigned last; // last tick used
|
||||
NSString *name;
|
||||
} Item;
|
||||
#define my ((Item*)&self[1])
|
||||
|
||||
+ (NSArray*) allInstances
|
||||
{
|
||||
NSArray *a;
|
||||
|
||||
[GSThroughputLock lock];
|
||||
a = NSAllHashTableObjects(GSThroughputInstances);
|
||||
[GSThroughputLock unlock];
|
||||
return a;
|
||||
}
|
||||
|
||||
+ (id) alloc
|
||||
{
|
||||
return [self allocWithZone: NSDefaultMallocZone()];
|
||||
}
|
||||
|
||||
+ (id) allocWithZone: (NSZone*)z
|
||||
{
|
||||
GSThroughput *c;
|
||||
|
||||
c = (GSThroughput*)NSAllocateObject(self, sizeof(Item), z);
|
||||
[GSThroughputLock lock];
|
||||
NSHashInsert(GSThroughputInstances, (void*)c);
|
||||
[GSThroughputLock unlock];
|
||||
return c;
|
||||
}
|
||||
|
||||
+ (NSString*) description
|
||||
{
|
||||
NSMutableString *ms;
|
||||
NSHashEnumerator e;
|
||||
GSThroughput *c;
|
||||
|
||||
ms = [NSMutableString stringWithString: [super description]];
|
||||
[GSThroughputLock lock];
|
||||
e = NSEnumerateHashTable(GSThroughputInstances);
|
||||
while ((c = (GSThroughput*)NSNextHashEnumeratorItem(&e)) != nil)
|
||||
{
|
||||
[ms appendFormat: @"\n%@", [c description]];
|
||||
}
|
||||
NSEndHashTableEnumeration(&e);
|
||||
[GSThroughputLock unlock];
|
||||
return ms;
|
||||
}
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (GSThroughputInstances == 0)
|
||||
{
|
||||
NSDateClass = [NSDate class];
|
||||
tiSel = @selector(timeIntervalSinceReferenceDate);
|
||||
tiImp
|
||||
= (NSTimeInterval (*)(Class,SEL))[NSDateClass methodForSelector: tiSel];
|
||||
baseTime = lastTime = (*tiImp)(NSDateClass, tiSel);
|
||||
GSThroughputLock = [NSLock new];
|
||||
GSThroughputInstances
|
||||
= NSCreateHashTable(NSNonRetainedObjectHashCallBacks, 0);
|
||||
[self setTick: 1.0];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void) setTick: (NSTimeInterval)interval
|
||||
{
|
||||
[GSThroughputLock lock];
|
||||
if (theTimer != nil)
|
||||
{
|
||||
[theTimer invalidate];
|
||||
theTimer = nil;
|
||||
}
|
||||
if (interval > 0.0)
|
||||
{
|
||||
theTimer = [NSTimer scheduledTimerWithTimeInterval: interval
|
||||
target: self
|
||||
selector: @selector(tick)
|
||||
userInfo: 0
|
||||
repeats: YES];
|
||||
}
|
||||
[GSThroughputLock unlock];
|
||||
}
|
||||
|
||||
+ (void) tick
|
||||
{
|
||||
NSTimeInterval now;
|
||||
NSHashEnumerator e;
|
||||
GSThroughput *i;
|
||||
|
||||
[GSThroughputLock lock];
|
||||
/*
|
||||
* If the clock has been reset so that time has gone backwards,
|
||||
* we adjust the baseTime so that lastTime >= baseTime is true.
|
||||
*/
|
||||
now = (*tiImp)(NSDateClass, tiSel);
|
||||
if (now < lastTime)
|
||||
{
|
||||
baseTime -= (lastTime - now);
|
||||
}
|
||||
lastTime = now;
|
||||
e = NSEnumerateHashTable(GSThroughputInstances);
|
||||
while ((i = (GSThroughput*)NSNextHashEnumeratorItem(&e)) != nil)
|
||||
{
|
||||
[i update];
|
||||
}
|
||||
NSEndHashTableEnumeration(&e);
|
||||
|
||||
[GSThroughputLock unlock];
|
||||
}
|
||||
|
||||
- (void) add: (unsigned)count
|
||||
{
|
||||
my->seconds[my->second].cnt += count;
|
||||
}
|
||||
|
||||
- (void) addDuration: (NSTimeInterval)length
|
||||
{
|
||||
if (my->seconds[my->second].cnt++ == 0)
|
||||
{
|
||||
my->seconds[my->second].min = length;
|
||||
my->seconds[my->second].max = length;
|
||||
my->seconds[my->second].sum = length;
|
||||
}
|
||||
else
|
||||
{
|
||||
my->seconds[my->second].sum += length;
|
||||
if (length > my->seconds[my->second].max)
|
||||
{
|
||||
my->seconds[my->second].max = length;
|
||||
}
|
||||
if (length < my->seconds[my->second].min)
|
||||
{
|
||||
my->seconds[my->second].min = length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[GSThroughputLock lock];
|
||||
RELEASE(my->name);
|
||||
NSHashRemove(GSThroughputInstances, (void*)self);
|
||||
NSDeallocateObject(self);
|
||||
[GSThroughputLock unlock];
|
||||
}
|
||||
|
||||
- (NSString*) description
|
||||
{
|
||||
NSString *n = my->name;
|
||||
|
||||
if (n == nil)
|
||||
{
|
||||
n = [super description];
|
||||
}
|
||||
// FIXME
|
||||
return n;
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < 24; i++)
|
||||
{
|
||||
my->hours[i].min = MAXDURATION;
|
||||
}
|
||||
for (i = 0; i < 60; i++)
|
||||
{
|
||||
my->seconds[i].min = MAXDURATION;
|
||||
my->minutes[i].min = MAXDURATION;
|
||||
}
|
||||
my->last = GSThroughputTimeTick() - 1;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString*) name
|
||||
{
|
||||
return my->name;
|
||||
}
|
||||
|
||||
- (void) setName: (NSString*)name
|
||||
{
|
||||
ASSIGN(my->name, name);
|
||||
}
|
||||
|
||||
- (void) update
|
||||
{
|
||||
unsigned tick = GSThroughputTimeTick();
|
||||
|
||||
// FIXME
|
||||
while (my->last < tick)
|
||||
{
|
||||
Info *info;
|
||||
unsigned i;
|
||||
|
||||
if (my->second++ == 59)
|
||||
{
|
||||
info = &my->minutes[my->minute];
|
||||
for (i = 0; i < 60; i++)
|
||||
{
|
||||
Info *from = &my->seconds[i];
|
||||
|
||||
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)
|
||||
{
|
||||
info = &my->hours[my->hour];
|
||||
for (i = 0; i < 60; i++)
|
||||
{
|
||||
Info *from = &my->minutes[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->hour++ == 23)
|
||||
{
|
||||
}
|
||||
info = &my->hours[my->hour];
|
||||
info->cnt = 0;
|
||||
info->max = 0.0;
|
||||
info->min = MAXDURATION;
|
||||
info->sum = 0.0;
|
||||
}
|
||||
info = &my->minutes[my->minute];
|
||||
info->cnt = 0;
|
||||
info->max = 0.0;
|
||||
info->min = MAXDURATION;
|
||||
info->sum = 0.0;
|
||||
}
|
||||
info = &my->seconds[my->second];
|
||||
info->cnt = 0;
|
||||
info->max = 0.0;
|
||||
info->min = MAXDURATION;
|
||||
info->sum = 0.0;
|
||||
|
||||
my->last++;
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
Loading…
Reference in a new issue