views:

537

answers:

1

Hello!

I would like to add some automated performance test to my Objective-C application. (This is a game, so that I would like to see the current performance of key parts of the engine by simply running a set of tests.) To do this I want to write some timing support routine, something like this:

- (void) benchmarkSelector: (SEL) msg onObject: (id) target
{
    // run the selector thousands of times, print detailed stats
}

The problem is that I am interested in milliseconds and I am afraid that calling performSelector in the benchmarking code would skew the results quite a bit. How would you go around this? Should I go down to objc_msgSend?

+4  A: 

Use methodForSelector:, which returns a function pointer to the actual implementation, like so:

IMP methodImp = [target methodForSelector:msg];
for (int i=0; i<1000; ++i) {
    NSTimeInterval start = [NSDate timeIntervalSinceReferenceDate];
    methodImp(target, msg);

    NSTimeInterval duration = [NSDate timeIntervalSinceReferenceDate] - start;
    // Do something with duration
}

Note that this strategy is useful for measuring the actual runtime of a method, but if you're going to be calling it with standard Objective-C message-passing syntax, then it might be just as relevant to include the message-passing overhead in your measurements.

Also, note that if the method actually takes any other parameters, you should cast the result of methodForSelector: to a function pointer with the appropriate parameters, to avoid unexpected conversion of floats to doubles, etc. See the NSObject Class Reference for more information and examples.

BJ Homer
You are right about including the message-passing overhead, but I was worried that the performSelector: could take ‘a lot’ longer than simply sending the message. After writing the code it does not look that bad – and if I wanted to, I could always back to the IMP. Thank you.
zoul
Wouldn't you get better results if you used uint64_t start = mach_absolute_time();uint64_t duration = mach_absolute_time() - start;which gives you nanoseconds instead of seconds?
micmoo
NSTimeInterval is a double. The result is expressed in terms of seconds, but has sub-millisecond precision. Since the OP is looking for milliseconds, I think it's good enough. But yes, mach_absolute_time() would work too.
BJ Homer