Reputation: 99
I'm doing pixel processing and when I call an empty Objective-C method, it uses 25% more CPU.
Furthermore another strange occurrence is if I have another Obj-C function call in that method that never gets called, it increases the CPU usage by an extra 10%.
Here's the code I'm calling:
- (void)addLeftCorner:(struct Position)p top:(BOOL)top {
if (top) {
[blackBorderLock lock];
[topLeftAllyMinionCorners addObject:[NSValue valueWithBytes:&p objCType:@encode(struct Position)]];
[blackBorderLock unlock];
} else {
[blackBorderLock lock];
[bottomLeftAllyMinionCorners addObject:[NSValue valueWithBytes:&p objCType:@encode(struct Position)]];
[blackBorderLock unlock];
}
}
- (void) processPixel:(uint8_t *)pixel x:(int)x y:(int)y{
//Assume multithreaded
if (pixel[0] == 0 && pixel[1] == 0 && pixel[2] == 0) {
//Check if top left border
if (x < imageData.imageWidth-1) {
if (y < imageData.imageHeight-1) { //Check for top left bar
//Check bottom right pixel
uint8_t *bottomRightPixel = pixel + (imageData.imageWidth + 1)*4;
if (bottomRightPixel[2] == 81 && bottomRightPixel[1] == 162 && bottomRightPixel[0] == 230) {
uint8_t *rightPixel = pixel + (1)*4;
if (rightPixel[0] == 0 && rightPixel[1] == 0 && rightPixel[2] == 0) {
uint8_t *bottomPixel = pixel + (imageData.imageWidth)*4;
if (bottomPixel[0] == 0 && bottomPixel[1] == 0 && bottomPixel[2] == 0) {
struct Position p;p.x=x;p.y=y;
[self addLeftCorner:p top:true];
}
}
}
}
if (y > 0) { //Check for bottom left bar
//Check top right pixel
uint8_t *topRightPixel = pixel + (-imageData.imageWidth + 1)*4;
if (topRightPixel[2] == 40 && topRightPixel[1] == 80 && topRightPixel[0] == 114) {
uint8_t *rightPixel = pixel + (1)*4;
if (rightPixel[0] == 0 && rightPixel[1] == 0 && rightPixel[2] == 0) {
uint8_t *topPixel = pixel - (imageData.imageWidth)*4;
if (topPixel[0] == 0 && topPixel[1] == 0 && topPixel[2] == 0) {
struct Position p;p.x=x;p.y=y;
[self addLeftCorner:p top:false];
}
}
}
}
}
}
}
In running this, the addLeftCorner never gets called yet if I comment it out, I get an extra 10% CPU usage. Also just calling the method processPixel takes 25% CPU usage alone.
Why is this? Is there a way to optimize it? I'd like to get that 35% CPU back.
Upvotes: 0
Views: 314
Reputation: 2495
TL;DR - You will want to investigate the use of NSObject -methodForSelector: as a means of avoiding Objective-C runtime overhead. Use this judiciously.
-
There's some terminology that comes from Smalltalk that is useful in keeping a mental model of what's really going on. We generally refer to invoking a method rather than calling a function in recognition that a dynamic language like Objective-C resolves function addresses at runtime, every time, in response to the kind of object that is the receiver of the message.
This dynamic dispatch is at the heart of the polymorphism of dynamic languages. And while the Objective-C runtime goes to almost superhuman lengths to make method invocation as efficient as possible, it will never ever be as efficient as a direct function call.
Most of the time, method invocation inefficiencies don't matter. The usually small loss of efficiency is swamped by human interaction with the application. But for computational kernels like image processing, the inefficiencies will become apparent.
By using NSObject -methodForSelector:, you can resolve the method into a function address once, and after that skip the runtime lookup. Study the documentation carefully. Make sure you understand what a SEL is and what an IMP is. Calling a method as a function requires two extra arguments, self and _cmd. Make sure you understand what they are and how they're used.
Most of all, make sure that profiling absolutely proves that bypassing the runtime like this is necessary. Based on your description of the problem, I'm not completely convinced you're seeing exactly what the issue is. But you're the one who knows your software best.
You'll be preventing the possibility of polymorphism of the objects you're using this method/function with, so it kind of sets this aspect of your design in concrete, without the usual flexibility of a dynamic language.
Upvotes: 2