[comp.sys.next] speed of access methods vs. object_getInstanceVar

scott@mcs-server.gac.edu (Scott Hess) (01/08/91)

In article <4755@media-lab.MEDIA.MIT.EDU> simsong@daily-bugle.media.mit.edu (Simson L. Garfinkel) writes:
   I was interested as to whether it is faster to access the instance variables of an object via accessor methods or via the object_getInstanceVariable() function, so I did a test.

I just did some quick testing to verify a point.  In the case of
object_getInstanceVariable(), the function follows the isa instance
variable to find the class of the object.  Then, it searches that
data structure to find the offset of the variable.  Meanwhile, the
method version can access the variable directly (as if it were a structure,
which is how the method will see it), with the overhead being in the
lookup of the method.  Since methods are compiled into SELs for
identification, and each class keeps a lookup table of frequently called
methods, this is fairly fast.

In the simple case given by Simson, this is all that happens.  Either
method of access is fairly close.  The advantage of the accessor method
really shows, though, when subclasses are used.  I took the sample code,
and subclassed MyObject with MyNewObject, and then subclassed MyNewObject
with MyNewNewObect.  Both subclasses did not have any new variables
or methods.  The times for both routines stayed approxiametely constant.

But, when I added 3 new instance variables of type int to each of the
subclasses, the time for the object_getInstanceVariable() version shot
up almost 3x!  The time using the accessor method stayed about the same.
The reason is that, in this case, object_getInstanceVariable() must first
search through the first isa pointer, but cannot find the variable there.
Then, it must go to the superclass, search its variable list, and not find
it there, either.  Lastly, it gets to MyObject, and finds the variable there,
and returns it.

Meanwhile, the first call to getX will cause the IMP for getX's SEL to be
placed in MyNewNewObject's cache, and from then on it will be quickly
found.

The moral of the story?  Use accessor methods.  In most cases, they
are not that slow if they are used enough - if they aren't used enough
to stay in the cache, you probably shouldn't be worrying that much about
a couple cycles, because it won't add up.

One last thing.  In some cases, you can use +(IMP)instanceMethodFor:(SEL)aSel;
to get a function which can be used instead of a method call.  This
should only be used inside loops, or other fairly safe places where the
object isn't going to change class.  It would not be too good to use
an IMP gotten for Responder on a Button . . . anyhow, I just did a test.
I added a call to get the IMP for getX to Simson's code, and a argument
-i to check for when this should be called.  The result?  Execution time
was cut to approxiamately 35% of what is was for the ti -m case.  This
is, of course, due to removal of the cache search from the cycle.

Hopefully, this helps someone out there.  One never knows :-).  Well,
it helps me, so I figured I'd post this to the net at large.  Later . . .

--
scott hess                      scott@gac.edu
Independent NeXT Developer	GAC Undergrad
<I still speak for nobody>
"Tried anarchy, once.  Found it had too many constraints . . ."
"Buy `Sweat 'n wit '2 Live Crew'`, a new weight loss program by
Richard Simmons . . ."

preston@LL.MIT.EDU (Steven Preston) (01/12/91)

Newsgroups: comp.sys.next

scott@mcs-server.gac.edu (Scott Hess) writes:
> The moral of the story?  Use accessor methods.  In most cases, they
> are not that slow if they are used enough - if they aren't used enough
> to stay in the cache, you probably shouldn't be worrying that much about
> a couple cycles, because it won't add up.

Actually, as I understand it, methods get added to a cache, but are
never removed.  The cache size is expanded (doubled) whenever it
becomes 3/4 full, but the cache is never contracted.