• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Objective-C question
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Objective-C question


  • Subject: Re: Objective-C question
  • From: "Louis C. Sacha" <email@hidden>
  • Date: Wed, 5 May 2004 17:54:24 -0700

Hello...

Just to inject a little reality into this -- your results don't reflect the actual results someone should expect by accessing iVars of a class directly instead of through accessors (note: it is NOT a good idea to bypass accessors for ivars that are pointers to objects, and doing so even with values makes significant assumptions about the implementation of the class). While I agree that there are situations where it is beneficial to access values stored in an instance variable directly, your numbers sound like manufacturer benchmarks :)

First, the test just measures the raw read/write access to the variable. This is equivalent to saying that given the speed that data can be read from the hard drive, it should be possible to convert an hour of DV video to mpeg2 in about 15 minutes, as opposed to the 7 or so hours it takes when I'm running bitvice on a 450Mhz G4 Cube. Even if I had a faster hard drive, it wouldn't make a significant amount of difference in the total time. Anything else that you do (calculations, etc...) will add to the time spent on each iteration, and as the amount of additional processing increases, the effect of the difference in speed from the read/write of variables decreases.

Second, it is very unlikely that a situation where this kind of access is required would require such a small memory footprint. It is far more likely that a large number of records/objects will be accessed, and this implies a larger effect on performance due to memory management.

A modified version of your test is at the end of this message, that shows some of these effects in action. I used an array of objects instead of just a single object, ran a number of tests varying the array size and the number of loops (although the total number of get/set iterations was kept constant at 100 million).

/*
I used -Os for these tests... on a dual 800 Mhz G4 w/ 1.5 GB RAM
model size is the array size, loopCount is the number of external loops
I had to retype these into the email, since I couldn't copy/paste since it was run on a different computer. So, it's possible there's a typo, even though I double checked them.
The faster result for tDirect with modelSize=100 compared to modelSize=1 is accurate.
Each line is the result of a seperate test run, with the indicated values used to modelSize and loopCount.

modelSize = 1; loopCount = 100000000; tDirect = 1.14s, tAccessors = 13.56s (100000000 iterations)...
modelSize = 100; loopCount = 1000000; tDirect = 1.02s, tAccessors = 14.01s (100000000 iterations)...
modelSize = 10000; loopCount = 10000; tDirect = 2.45s, tAccessors = 15.74s (100000000 iterations)...
modelSize = 100000; loopCount = 1000; tDirect = 8.67s, tAccessors = 23.82s (100000000 iterations)...
modelSize = 1000000; loopCount = 100; tDirect = 15.42s, tAccessors = 28.05s (100000000 iterations)...

modelSize = 10000000; loopCount = 10; test has exited due to signal 11 (SIGSEGV). :)
*/

My modified version still doesn't do anything with the values other than setting them and getting them. The difference in these results is caused by the overhead from simply accessing the objects/structs from a standard C array (not an NSArray) and the necessary memory management for a larger model. The difference between the two methods is more or less constant, and if any real work was actually done in the loop, the % difference in speed would drop even more significantly.

Also, note that the roughly constant 13 second difference in the total times is for 100 million set/get iterations. That's a lot of iterations :) So even though 13 seconds sounds like a big difference, if you drop the number of total iterations to 1 million, the difference in total time is only 0.131s (from a test using modelSize= 1000; loopCount = 1000; with the output accuracy bumped up to 3 decimal places).


Anyway, the code follows... Louis


#import <Foundation/Foundation.h>


@interface MyClass : NSObject { @public int x; }
- (int) getX;
- (void) setX: (int) anInt;
@end
@implementation MyClass
- (int) getX {return x;}
- (void) setX: (int) anInt { x = anInt; }
@end

typedef struct { @defs(MyClass); } ClassStr;

int main(int argc, char **argv)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

unsigned modelSize = 1000000;
unsigned loopCount = 100;

double t1, t2;
NSDate *startDate;

NSLog(@"starting - building models");

MyClass *obj[modelSize];
ClassStr *cs[modelSize];

unsigned i;
for (i=0; i<modelSize; i++)
{
obj[i] = [[MyClass alloc] init];
cs[i] = (ClassStr *) obj[i];
}


NSLog(@"beginning tests");
unsigned j,k;

startDate = [NSDate date];
for(j=0; j<loopCount; j++)
{
for (k=0; k<modelSize; k++)
{
cs[k]->x = j;
}
for (k=0; k<modelSize; k++)
{
j = cs[k]->x;
}
}
t1 = - [startDate timeIntervalSinceNow];

startDate = [NSDate date];
for(j=0; j<loopCount; j++)
{
for (k=0; k<modelSize; k++)
{
[obj[k] setX: j];
}
for (k=0; k<modelSize; k++)
{
j = [obj[k] getX];
}
} t2 = - [startDate timeIntervalSinceNow];


NSLog(@"tDirect =%.2fs, tAccessors = %.2fs (%d iterations)", t1, t2, loopCount*modelSize);

[pool release];
return 0;
}



Classes give you much more than just encapsulation. They give you all sorts of useful memory management features, convenient inheritance of methods and a way to make your code more readable. There are many good reasons for using these features and the other benefits of classes even if you care nothing for encapsulation.

On the other hand it is worth noting that Objective-C classes are not without cost. Consider the code for blah.m attached to the end of this mail. It makes an object and then uses @defs() to make a C structure with the same layout. Here's the output:

Direct took 0.68s, methods took 9.10s for 100000000 loops

Reading and writing the instance variable many times using direct access records 6.8ns per loop on a 1.25GHz G4 whereas using methods to get and set the same instance variable takes 91ns per loop, thirteen times slower. There is clearly a large cost associated with making the method calls themselves, and worse the disruption of processor flow by having to make calls to objc_msgSend all the time means that the compiler's optimisation phase is much less effective; in this test I deliberately forced the compiler not to optimise around these calls and removing the 'volatile' directive drops the direct access loop to 1.8ns, 50 time faster than method access. In many cases where dealing with large bodies of data the overhead of using method access to instance variables is unacceptable.

Nicko
...
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.


References: 
 >Objective-C question (From: Chuck Soper <email@hidden>)
 >Re: Objective-C question (From: Fritz Anderson <email@hidden>)
 >Re: Objective-C question (From: Chuck Soper <email@hidden>)
 >Re: Objective-C question (From: j o a r <email@hidden>)
 >Re: Objective-C question (From: Scott Thompson <email@hidden>)
 >Re: Objective-C question (From: Ondra Cada <email@hidden>)
 >Re: Objective-C question (From: Scott Thompson <email@hidden>)
 >Re: Objective-C question (From: Ondra Cada <email@hidden>)
 >Re: Objective-C question (From: Nicko van Someren <email@hidden>)

  • Prev by Date: Re: A couple of NSFont questions
  • Next by Date: Re: Array operators (was: Custom canRemove binding)
  • Previous by thread: Re: Objective-C question
  • Next by thread: Re: Objective-C question
  • Index(es):
    • Date
    • Thread