Question

I have these functions in Objective-C:

-(void)emptyFunction
{
    NSTimeInterval startTime = [[NSDate date] timeIntervalSinceReferenceDate];

    float b;
    for (int i=0; i<1000000; i++) {
        b = [self returnNr:i];
    }

    NSTimeInterval endTime = [[NSDate date] timeIntervalSinceReferenceDate];

    double elapsedTime = endTime - startTime;
    NSLog(@"1. %f", elapsedTime);
}

-(float)returnNr:(float)number
{
    return number;
}

and

-(void)sqrtFunction
{
    NSTimeInterval startTime = [[NSDate date] timeIntervalSinceReferenceDate];

    float b;
    for (int i=0; i<1000000; i++) {
        b = sqrtf(i);
    }

    NSTimeInterval endTime = [[NSDate date] timeIntervalSinceReferenceDate];

    double elapsedTime = endTime - startTime;
    NSLog(@"2. %f", elapsedTime);
}

When I call them, in any order, it prints in console the following:

2014-01-13 12:23:00.458 RapidTest[443:70b] 1. 0.011970
2014-01-13 12:23:00.446 RapidTest[443:70b] 2. 0.006308

How is this happening? How can sqrtf() function be twice as faster than a function that just returns a value? I know sqrtf() works on bits with assembly language and such, but faster than just a return? How is it possible?

Was it helpful?

Solution

Calling [self returnNr:i] is not the same as simply calling a C function. Instead you're sending a message to self, which gets translated to the equivalent in C:

objc_msgSend(self, @selector(returnNr:), i);

This will eventually call your returnNr: implementation, but there's some overhead involved. For more details on what's going on in objc_msgSend see objc_msgSend tour or Let's build objc_msgSend

[edit] Also see An Illustrated History of objc_msgSend, which shows how the implementation changed over time. Executing the code from your Q will have resulted in different results on different platform versions because of improvements / trade-offs made during the evolution of objc_msgSend.

OTHER TIPS

Your benchmark is flawed.

First, in both cases a compiler may optimize your loop as follows:

for (int i=0; i<1000000-1; i++) {
    [self returnNr:i];
}
float b = [self returnNr:i];

respectively:

for (int i=0; i<1000000-1; i++) {
    sqrtf(i);
}
float b = sqrtf(i);

Then, IFF the compiler can deduce that the statement sqrtf(i) has no side effect (other than returning a value), it may further optimize as follows:

float b = sqrtf(1000000-1);

It's very likely that clang will apply this optimization, though it's implementation dependent.

See also: Do C and C++ optimizers typically know which functions have no side effects?

In case of Objective-C method invocations a compiler has far less optimization opportunities, and it will very likely always assume that a method call might have a possible side effect and must be called always. Thus, the second optimization will likely not applied in an optimized build.

Additionally, your approach to measure the elapsed time is by far not accurate enough. You should use the mach timer to get a precise absolute time. And you need to execute a number of "runs" and take the minimum of the runs.

Your Obj-C method

-(float)returnNr:(float)number
{
    return number;
}

first gets compiled to C-function and then it is executed, and sqrtf() is a C-function.

Hence C-functions will be faster as compared to Objective-C methods.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top