/* Simple benchmark program. Copyright (C) 1998 Free Software Foundation, Inc. Written by: Adam Fedor Modified: Richard Frith-Macdonald Modified: Nicola Pero This file is part of the GNUstep Base 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. */ #include #include #include #define MAX_COUNT 100000 #define START_TIMER sTime = [NSDate date] #define END_TIMER eTime = [NSDate date] #define PRINT_TIMER(str) printf(" %-20s\t %6.3f \t %6.3f\n", str, \ [eTime timeIntervalSinceDate: sTime], \ [eTime timeIntervalSinceDate: sTime]/baseline) #define PRINT_TIMER_NO_BASELINE(str) \ printf(" %-20s\t %6.3f \t %6.3f\n", str, \ [eTime timeIntervalSinceDate: sTime] - baseline, \ [eTime timeIntervalSinceDate: sTime]/baseline - 1) #define AUTO_START id pool = [NSAutoreleasePool new] #define AUTO_END [pool release] NSDate *sTime = nil; NSDate *eTime = nil; /* Set to a baseline to null out speed of runtime */ NSTimeInterval baseline = 0.0; NSZone *myZone; Class rootClass; Class stringClass; IMP cstring; @interface MyObject : NSObject @end @implementation MyObject @end @implementation MyObject (Category) - (id) self { return [super self]; } @end void bench_object() { int i; id obj; objc_mutex_t mutex; AUTO_START; START_TIMER; for (i = 0; i < MAX_COUNT*10; i++) { [rootClass class]; } END_TIMER; baseline = [eTime timeIntervalSinceDate: sTime]; PRINT_TIMER("Baseline: 10 method calls\t\t"); START_TIMER; for (i = 0; i < MAX_COUNT; i++) { /* Ten class methods with the more common class names */ id i; i = [NSObject class]; i = [NSString class]; i = [NSDictionary class]; i = [NSArray class]; i = [NSData class]; i = [NSUserDefaults class]; i = [NSMutableArray class]; i = [NSFileManager class]; i = [NSMutableString class]; i = [NSMutableDictionary class]; } END_TIMER; PRINT_TIMER("Class: 10 class method calls\t\t"); obj = [MyObject new]; START_TIMER; for (i = 0; i < MAX_COUNT * 10; i++) { id i; i = [obj self]; } END_TIMER; PRINT_TIMER_NO_BASELINE("Category: 10 super calls\t\t"); START_TIMER; for (i = 0; i < MAX_COUNT; i++) { /* Corresponding look ups */ id i; i = NSClassFromString (@"NSObject"); i = NSClassFromString (@"NSString"); i = NSClassFromString (@"NSDictionary"); i = NSClassFromString (@"NSArray"); i = NSClassFromString (@"NSData"); i = NSClassFromString (@"NSUserDefaults"); i = NSClassFromString (@"NSMutableArray"); i = NSClassFromString (@"NSFileManager"); i = NSClassFromString (@"NSMutableString"); i = NSClassFromString (@"NSMutableDictionary"); } END_TIMER; PRINT_TIMER("Function: 10 NSClassFromStr\t\t"); START_TIMER; myZone = NSCreateZone(2048, 2048, 1); for (i = 0; i < MAX_COUNT; i++) { void *mem = NSZoneMalloc(myZone, 32); NSZoneFree(myZone, mem); } NSRecycleZone(myZone); END_TIMER; PRINT_TIMER("Function: 1 zone alloc/free\t\t"); START_TIMER; myZone = NSCreateZone(2048, 2048, 0); for (i = 0; i < MAX_COUNT; i++) { void *mem = NSZoneMalloc(myZone, 32); NSZoneFree(myZone, mem); } NSRecycleZone(myZone); END_TIMER; PRINT_TIMER("Function: 1 zone2alloc/free\t\t"); myZone = NSDefaultMallocZone(); START_TIMER; for (i = 0; i < MAX_COUNT; i++) { void *mem = NSZoneMalloc(myZone, 32); NSZoneFree(myZone, mem); } END_TIMER; PRINT_TIMER("Function: 1 def alloc/free\t\t"); START_TIMER; myZone = NSCreateZone(2048, 2048, 1); for (i = 0; i < MAX_COUNT; i++) { obj = [[rootClass allocWithZone: myZone] init]; [obj release]; } NSRecycleZone(myZone); END_TIMER; PRINT_TIMER("NSObject: 1 zone all/init/rel\t\t"); START_TIMER; myZone = NSCreateZone(2048, 2048, 0); for (i = 0; i < MAX_COUNT; i++) { obj = [[rootClass allocWithZone: myZone] init]; [obj release]; } NSRecycleZone(myZone); END_TIMER; PRINT_TIMER("NSObject: 1 zone2all/init/rel\t\t"); myZone = NSDefaultMallocZone(); START_TIMER; for (i = 0; i < MAX_COUNT; i++) { obj = [[rootClass allocWithZone: myZone] init]; [obj release]; } END_TIMER; PRINT_TIMER("NSObject: 1 def all/init/rel\t\t"); obj = [rootClass new]; START_TIMER; for (i = 0; i < MAX_COUNT*10; i++) { [obj retain]; [obj release]; } END_TIMER; PRINT_TIMER("NSObject: 10 retain/rel\t\t"); [obj release]; obj = [rootClass new]; START_TIMER; for (i = 0; i < MAX_COUNT*10; i++) { [obj autorelease]; [obj retain]; } END_TIMER; PRINT_TIMER("NSObject: 10 autorel/ret\t\t"); [obj release]; START_TIMER; for (i = 0; i < MAX_COUNT*10; i++) { [rootClass instancesRespondToSelector: @selector(hash)]; } END_TIMER; PRINT_TIMER("ObjC: 10 inst responds to sel\t\t"); mutex = objc_mutex_allocate(); START_TIMER; for (i = 0; i < MAX_COUNT*10; i++) { objc_mutex_lock(mutex); objc_mutex_unlock(mutex); } END_TIMER; PRINT_TIMER("ObjC: 10 objc_mutex_lock/unl\t\t"); objc_mutex_deallocate(mutex); obj = [NSLock new]; START_TIMER; for (i = 0; i < MAX_COUNT*10; i++) { [obj lock]; [obj unlock]; } END_TIMER; PRINT_TIMER("NSLock: 10 lock/unlock\t\t"); [obj release]; AUTO_END; } void bench_array() { int i; id array; NSString *strings[MAX_COUNT]; AUTO_START; for (i = 0; i < MAX_COUNT; i++) { char buf1[100]; sprintf(buf1, "str%0d", i); strings[i] = [stringClass stringWithCString: buf1]; } printf("NSArray\n"); array = [NSMutableArray arrayWithCapacity: 16]; START_TIMER; for (i = 0; i < MAX_COUNT*10; i++) { [array addObject: strings[i/10]]; } END_TIMER; PRINT_TIMER("NSArray (10 addObject:)\t\t"); START_TIMER; for (i = 0; i < MAX_COUNT/100; i++) { [array indexOfObject: strings[i]]; } END_TIMER; PRINT_TIMER("NSArray (1/100 indexOfObj)\t\t"); START_TIMER; for (i = 0; i < MAX_COUNT/100; i++) { [array indexOfObjectIdenticalTo: strings[i]]; } END_TIMER; PRINT_TIMER("NSArray (1/100 indexIdent)\t\t"); START_TIMER; for (i = 0; i < 1; i++) { [array makeObjectsPerformSelector: @selector(hash)]; } END_TIMER; PRINT_TIMER("NSArray (once perform)\t\t"); AUTO_END; } void bench_dict() { int i; NSMutableDictionary *dict; id obj2; NSString *keys[MAX_COUNT/10]; NSString *vals[MAX_COUNT/10]; AUTO_START; for (i = 0; i < MAX_COUNT/10; i++) { char buf1[100], buf2[100]; sprintf(buf1, "key%0d", i); sprintf(buf2, "val%0d", i); keys[i] = [stringClass stringWithCString: buf1]; vals[i] = [stringClass stringWithCString: buf2]; } printf("NSDictionary\n"); dict = [NSMutableDictionary dictionaryWithCapacity: 16]; START_TIMER; for (i = 0; i < MAX_COUNT/10; i++) { int j; for (j = 0; j < 10; j++) { [dict setObject: vals[i] forKey: keys[i]]; } } END_TIMER; PRINT_TIMER("NSDict (1 setObject:) \t\t"); START_TIMER; for (i = 0; i < MAX_COUNT; i++) { int j; for (j = 0; j < 10; j++) { [dict objectForKey: keys[i/10]]; } } END_TIMER; PRINT_TIMER("NSDict (10 objectFor:) \t\t"); START_TIMER; for (i = 0; i < MAX_COUNT*10; i++) { [dict count]; } END_TIMER; PRINT_TIMER("NSDictionary (10 count)\t\t"); obj2 = [dict copy]; START_TIMER; for (i = 0; i < 10; i++) { [dict isEqual: obj2]; } END_TIMER; PRINT_TIMER("NSDict (ten times isEqual:)\t\t"); AUTO_END; } void bench_str() { int i; NSString *str; NSMutableString *ms; id plist; NSString *plstr; Class arc = [NSArchiver class]; Class una = [NSUnarchiver class]; Class ser = [NSSerializer class]; Class des = [NSDeserializer class]; Class md = [NSMutableDictionary class]; AUTO_START; [[md new] release]; plist = [NSDictionary dictionaryWithObjectsAndKeys: @"Value1", @"Key1", @"", @"Key2", [NSArray array], @"Key3", [NSArray arrayWithObjects: @"Array1 entry1", @"Array1 entry2", [NSArray arrayWithObjects: @"Array2 entry1", @"Array2 entry2", nil], [NSDictionary dictionary], [NSDictionary dictionaryWithObjectsAndKeys: @"Value", @"Key", nil], nil], @"Key4", [NSDictionary dictionary], @"Key5", [NSDictionary dictionaryWithObjectsAndKeys: @"Value", @"Key", nil], @"Key6", [NSData data], @"Key7", [NSData dataWithBytes: "hello" length: 5], @"Key8", nil]; plstr = [plist description]; printf("NSString\n"); START_TIMER; for (i = 0; i < MAX_COUNT; i++) { str = [[stringClass alloc] initWithFormat: @"Hello %d", i]; RELEASE(str); } END_TIMER; PRINT_TIMER("NSString (1 initWithFormat:) \t"); ms = [NSMutableString stringWithCapacity: 0]; START_TIMER; for (i = 0; i < MAX_COUNT; i++) { [ms appendFormat: @"%d", i]; } END_TIMER; PRINT_TIMER("NSString (1 appendFormat:) \t\t"); START_TIMER; for (i = 0; i < MAX_COUNT; i++) { str = [stringClass stringWithCString: "hello world"]; } END_TIMER; PRINT_TIMER("NSString (1 cstring:) \t\t"); START_TIMER; for (i = 0; i < MAX_COUNT*10; i++) { [str length]; } END_TIMER; PRINT_TIMER("NSString (10 length) \t\t"); START_TIMER; for (i = 0; i < MAX_COUNT*10; i++) { [str copy]; } END_TIMER; PRINT_TIMER("NSString (10 copy) "); str = @"ConstantString"; START_TIMER; for (i = 0; i < MAX_COUNT*10; i++) { [str copy]; } END_TIMER; PRINT_TIMER("NSString (10 copy) <@'ConstantString'> "); str = [[NSString alloc] initWithCStringNoCopy: (char *)[str cString] length: [str length] freeWhenDone: NO]; START_TIMER; for (i = 0; i < MAX_COUNT*10; i++) { [str copy]; } END_TIMER; PRINT_TIMER("NSString (10 copy) "); str = [[NSString alloc] initWithCStringNoCopy: (char *)[str cString] length: [str length] freeWhenDone: YES]; START_TIMER; for (i = 0; i < MAX_COUNT*10; i++) { [str copy]; } END_TIMER; PRINT_TIMER("NSString (10 copy) "); str = [stringClass stringWithCString: "hello world"]; START_TIMER; for (i = 0; i < MAX_COUNT*10; i++) { [str hash]; } END_TIMER; PRINT_TIMER("NSString (10 hash) "); str = @"ConstantString"; START_TIMER; for (i = 0; i < MAX_COUNT*10; i++) { [str hash]; } END_TIMER; PRINT_TIMER("NSString (10 hash) <@'ConstantString'> "); START_TIMER; for (i = 0; i < MAX_COUNT/100; i++) { id arp = [NSAutoreleasePool new]; [plist description]; [arp release]; } END_TIMER; PRINT_TIMER("NSString (1/100 mkplist) \t\t"); START_TIMER; for (i = 0; i < MAX_COUNT/1000; i++) { [plstr propertyList]; } END_TIMER; PRINT_TIMER("NSString (1/1000 plparse)\t\t"); START_TIMER; for (i = 0; i < MAX_COUNT/1000; i++) { id arp = [NSAutoreleasePool new]; NSString *s = [plist description]; id p = [s propertyList]; if ([p isEqual: plist] == NO) printf("Argh 1\n"); if ([s isEqual: plstr] == NO) printf("Argh 2\n"); [arp release]; } END_TIMER; PRINT_TIMER("NSString (1/1000 plcomp)\t\t"); START_TIMER; for (i = 0; i < MAX_COUNT/100; i++) { NSData *d = [ser serializePropertyList: plist]; [des deserializePropertyListFromData: d mutableContainers: NO]; } END_TIMER; PRINT_TIMER("NSString (1/100 ser/des)\t\t"); [NSDeserializer uniquing: YES]; START_TIMER; for (i = 0; i < MAX_COUNT/100; i++) { NSData *d = [ser serializePropertyList: plist]; [des deserializePropertyListFromData: d mutableContainers: NO]; } END_TIMER; PRINT_TIMER("NSString (1/100 ser/des - uniquing)\t"); [NSDeserializer uniquing: NO]; START_TIMER; for (i = 0; i < MAX_COUNT/100; i++) { NSData *d = [arc archivedDataWithRootObject: plist]; [una unarchiveObjectWithData: d]; } END_TIMER; PRINT_TIMER("NSString (1/100 arc/una)\t\t"); AUTO_END; } void bench_date() { int i; id d; AUTO_START; Class dateClass = [NSCalendarDate class]; printf("NSCalendarDate\n"); START_TIMER; for (i = 0; i < MAX_COUNT/10; i++) { d = [[dateClass alloc] init]; [d description]; [d dayOfYear]; [d minuteOfHour]; [d release]; } END_TIMER; PRINT_TIMER("NSCalendarDate (various)\t\t"); AUTO_END; } void bench_data() { int i; id d, o; AUTO_START; Class dataClass = [NSData class]; printf("NSData\n"); START_TIMER; for (i = 0; i < MAX_COUNT/10; i++) { d = [[dataClass alloc] initWithContentsOfFile:@"benchmark.m"]; [d length]; o = [d copy]; [o release]; o = [d mutableCopy]; [o release]; [d release]; } END_TIMER; PRINT_TIMER("NSData (various)\t\t\t"); AUTO_END; } int main(int argc, char *argv[], char **env) { id pool; #if LIB_FOUNDATION_LIBRARY || defined(GS_PASS_ARGUMENTS) [NSProcessInfo initializeWithArguments:argv count:argc environment:env]; #endif /* * Cache classes to remove overhead of objc runtime class lookup from * the benchmark. */ rootClass = [NSObject class]; stringClass = [NSString class]; pool = [NSAutoreleasePool new]; printf(" Test \t\t\t\t time (sec) \t index\n"); bench_object(); bench_str(); bench_array(); bench_dict(); bench_date(); bench_data(); AUTO_END; return 0; }