barton@contel0 ( R+D Software Test ENG) (10/23/90)
Goal: Time critical code should perform as well as C code, while retaining the advantages of object-oriented design. Time-critical code in our system includes polling of hardware devices at a 10mS interval, and processing which will be on the normal path of execution for peak volume of data items (phone calls). Coding guidelines: 1. Declare the receiver of a method to be a specific type object, rather than an "id". This allows static binding of methods at compile time, saving most of the 20uS overhead of dynamic lookup. Examples: c_Dpom *vo_self = (c_Dpom *)self; P_Connect *vo_pktid= (P_Connect *)ao_pktid; 2. Don't use inherited methods. They cannot be statically bound. Inherited data is ok. 3. Don't nest method invocations, since the intermediate results are of type "id". Explicitly declare the intermediate variables. Example: replace this: [vo_class2 m_status:[vo_class1 m_status]]; with some_value = [vo_class1 m_status]; [vo_class2 m_status:some_value]; 4. Avoid Stepstone library objects such as String, Collection, etc, since these do not follow the guidelines given above. Code your own objects, and re-use them. 5. Avoid using methods for simple instance variable access, for code within the object. Just directly access the instance variable. Example: Pair of enqueue and dequeue methods, for an event object to/from an event queue reduced from 200uS to 30uS (on our SPARC processor board) by following these guidelines. The queue was re-implemented as a simple fixed size array, and explicit head and tail pointers are maintained, rather than using a subclass of ordered collection. I estimate 5-10 messenger calls were eliminated, each of which takes about 20uS. This kind of coding raises all kinds of questions: Could Stepstone provide an alternate version of runtime and ICpak101 libraries, which was optimized for speed? Could static binding be improved to recognize the type of the receiver just from a cast, rather than the data declaration? Can the inherited methods be static bound, in code where static (compile-time) analysis shows that there is no method over-ride done by the sub-classes? Does anyone have any other suggestions for speed improvement, which are specific to the Objective-C language (as opposed to just general-purpose good-programming practices)? On un-related issues: Can the .h files be enhanced to declare certain methods as internal or private to an object? I frequently have the case where the public interface is only a few methods, but for modularity reasons I have a dozen internal methods. At present they are all listed in the header, with only a comment to protect them from another programmer attempting to use them. If the function names the objc pre-processor generated were changed from "_23_class" (for example) to "_23_class_my_method_name" it would make them more readable, especially in dbxtools where the function name is displayed. matt
cox@stpstn.UUCP (Brad Cox) (10/26/90)
In article <129@contel0> barton@contel0.UUCP (Matthew Barton - R+D Software eng) writes: | Does anyone have any other suggestions for speed improvement, | which are specific to the Objective-C language (as opposed to | just general-purpose good-programming practices)? The approach you outlined seems quite sound, and admirably researched. I occasionally use another one that is based on the following terminology. I think of Objective-C objects as providing chip-level objects on top of a C substrate that has always provided block-level objects (subroutines) and gate-level objects (macros). Thus when designing something, I think as a hardware designer might, at each step thinking about whether this might be best packaged as a gate-level object, a block-level object, a chip-level object, etc. For example, when building a time-critical Queue class, I decided that for clients for whom enqueing/dequeueing might be time-critical, a block-level (subroutine-based) interface should be provided in addition to the conventional chip-level (message-based) interface for clients for whom purity and polymorphism were preferable. So my Queue class looks like this: @interface Queue:ListBasedCollection ... -enqueue:aQueueMember { return (id)enqueue((QUEUE*)self, (MEMBER*)aQueueMember); } @end EXPORT QUEUE* enqueue(QUEUE* aQueue; MEMBER* aQueueMember) { ... } In other words, the enqueue() subroutine corresponds to a chip designer who decides to package the chip's functionality, not only as a chip, but also as a resuable cel. Clients outside his own company would use the functionality through the chip-level interface. By packaging his work not only as a chip, but also as a block (a cel) would allow experts within his company to reuse the functionality through the lower-level, more complicated, more efficient, less pluggable block-level interface. -- Brad Cox; cox@stepstone.com; CI$ 71230,647; 203 426 1875 The Stepstone Corporation; 75 Glen Road; Sandy Hook CT 06482
andyk@kermit.UUCP (Andy Klapper) (10/30/90)
In article <129@contel0> barton@contel0.UUCP (Matthew Barton - R+D Software eng) writes: >Goal: Time critical code should perform as well as C code, while retaining the >advantages of object-oriented design. > >Coding guidelines: > >2. Don't use inherited methods. They cannot be statically bound. >Inherited data is ok. NOT TRUE !! Inherited methods can be statically bound just like methods defined in the class that calls it ! The following code fragment when compiled will show this. file -> One.h #import "Object.h" @interface One : Object {} - aOneMethod; @end file -> Two.h #import "One.h" @interface Two : One {} - testMethod; @end file -> Two.m #import "Two.h" @implementation Two - testMethod { [(Two *) self aOneMethod]; // Note: self must be cast to a type for // static binding to work. This is VERY // dangerous as a sub class that over rides // the aOneMethod would not work as expected. } @end >3. Don't nest method invocations, since the intermediate results are of >type "id". Explicitly declare the intermediate variables. > Example: replace this: > [vo_class2 m_status:[vo_class1 m_status]]; > > with > > some_value = [vo_class1 m_status]; > [vo_class2 m_status:some_value]; > Also NOT TRUE !!! as long as the type of vo_class1 is known, and the sBind switch is set this will work. Add the following lines to the above example to show that this will work as well. file -> One.h add the method prototype - createOne; file -> Two.m add to testMethod the line [[(Two *) self createOne] aOneMethod]; NOTE: Both of these examples were run on a Sun 3 under Sun OS 4.0.3 with the current released version of Objective-C. If anybody would like the full examples I can Email them to you. >4. Avoid Stepstone library objects such as String, Collection, etc, >since these do not follow the guidelines given above. >Code your own objects, and re-use them. > The ICpak101 libraries were designed to be generalized reusable components. When you get to the optimization phase you should optimize the methods that will help you the most to optimize. For example Stepstone created a new Set class (HashSet) as part of ICpak201 because the performance of a general purpose Set class was not good enough. > >This kind of coding raises all kinds of questions: > Could Stepstone provide an alternate version of runtime and ICpak101 > libraries, which was optimized for speed? We could, but then we should offer several different versions of each class. Each version would have to be optimized for a different set of conditions. For example Stepstone should then provide different optimized versions of osort (one optimized for the case of random data, one optimized for data that is already mostly sorted ...). The point being that algorithmic changes get you more bang for the buck, but tend to be VERY application specific. > > Could static binding be improved to recognize the type of the receiver > just from a cast, rather than the data declaration? This is already the case. In a future release the compiler will also allow for static binding to class objects and to super inside of class methods. > Can the > inherited methods be static bound, in code where static (compile-time) > analysis shows that there is no method over-ride done by > the sub-classes? Given the way that static binding is implemented in Objective-C, where the method is defined is of no concern. > > Does anyone have any other suggestions for speed improvement, > which are specific to the Objective-C language (as opposed to > just general-purpose good-programming practices)? I am currently working on a new section/appendix for the Objective-C manual that deals with optimizing Objective-C code for speed. (I may be able to send you a working copy if you want (I'd have to check first)). Here are a couple things that I think you missed. 1) The 'methodFor:' method provides a way of getting an implementation (function) pointer for an object, selector pair at runtime. The 'methodFor:' method allows for a little more flexibility in your code. For example this mechanism allows you to define a uniform collection that is optimized with the knowledge that all of it's elements are of the same time. Static binding will only allow you to define a collection that contains all objects of a specific type because the type of the receiver has to be determined at compile time. 2) You have not mentioned anything about memory allocation and freeing. Alot of time can be spent allocating and freeing objects in an Objective-C program. You may want to cache some objects for reuse or use objects allocated off of the stack. When allocating objects off of the stack there are a couple of things that you ought to know. One, the data in an object allocated off of the stack is NOT initialized. The user is responsible for initializing the data themselves (- initialize is the most common way). Two, the current release of the compiler does not properly set an attribute bit that prevents the free method from trying to call 'free()' to free the memory used by the object. (The next release will) What this means is that if the initialization routine creates any additional objects you will have to create a new free method that will release them, but not self. > >On un-related issues: I will pass you suggestions on. > > matt -- The Stepstone Corporation Andy Klapper 75 Glen Rd. andyk@stepstone.com Sandy Hook, CT 06482 uunet!stpstn!andyk (203) 426-1875 fax (203)270-0106