views:

248

answers:

2

I'm playing with the GLGravity example to figure out some of the performance nuances related to dealing with the accelerometer.

Here's the problem code:

- (void)accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration
{
    static int accelCallCount;
    accelCallCount++;
    if (accelCallCount % 100 == 0) {
     NSLog(@"accelCallCount:%d", accelCallCount);
    }

    //Use a basic low-pass filter to only keep the gravity in the accelerometer values
    accel[0] = acceleration.x * kFilteringFactor + accel[0] * (1.0 - kFilteringFactor);
    accel[1] = acceleration.y * kFilteringFactor + accel[1] * (1.0 - kFilteringFactor);
    accel[2] = acceleration.z * kFilteringFactor + accel[2] * (1.0 - kFilteringFactor);

    //Update the accelerometer values for the view
    [glView setAccel:accel];
}

This code runs very slowly. Visually, I can tell that the movement of the teapot becomes very delayed, and it just gets slower and slower. Eventually the teapot's movements are easily 2+ minutes delayed from the time I actually moved the device.

The output in the Debugger Console does show some delay, too, but it's not too much. It's nearly (but not quite) twice as slow as it should be.

2009-11-27 02:18:58.874 GLGravity[419:207] accelCallCount:100
2009-11-27 02:19:00.507 GLGravity[419:207] accelCallCount:200
2009-11-27 02:19:02.174 GLGravity[419:207] accelCallCount:300

Accelerometer callbacks seem to pile up, though, in some kind of queue. So what starts off as being not-too-bad quickly becomes unbearably slow.

This problem disappears, however, if I just move the declaration of accelCallCount to the header file and declare it as an instance var:

int accelCallCount;

Why does this fix it?

On a related note, whether I use this code or the "fixed" (accelCallCount as an ivar) code, the whole thing also slows down if I touch the screen. Why might that be?

A: 

You get lots of events coming through, and they are all being processed in the delegate method itself at present, on the main thread. If your message to glView is expensive as well, the system will be processing that and incoming events will be queuing up.

An option might be to batch up the events in the delegate call, then periodically process them and take the summary result and then update the display. That should give the main thread time to handle touch events as well.

So for example, add the events to an array in the delegate method, with as little code as possible in there (make the array pre-allocated block that you loop over using head and tail indexes), then every n events, deach a thread to process them and have that post back to the main thread with the glView update values (or even better, keep a background thread alive that does the processing periodically, protecting the data with a semaphore if needed).

Also, you can set the updateInterval on the accelerometer object, maybe you just need to slow it down?

As for the instance vs method static... my guess is that the instance var will be accessible all the time without overhead, but the static within the method will be comparatively expensive to access. But that is noteworthy and something I will have to watch out for as well.

Hope this helps.

theLastNightTrain
Thanks for the answer! Actually, the message to glView should be extremely quick. "accel" is actually just an @property with an @synthesize'd setter.Batching up the events is exactly what I hoped to do with my "if (accelCallCount % 100 == 0)" line -- since I read the accelerometer at 100 Hz, I wanted to get something printed to the Debugger Console about once per second.I don't actually want to handle touch events; touches should do nothing right now. Yet they still slow down the app.
Elliot
So you only print to debugger every second which is fine but what about batching up all the filter processing too? Also does it need to be updated at 100Hz? The max iPhone screen refresh rate is about 50fps. Perhaps batch 4 updates and process those at 25Hz.For the touch events have you tried disabling touch events in the view? (uiview.userInteractionEnabled) (sorry I haven't looked at that example so maybe this suggestion already covered!).
theLastNightTrain
A: 

Reduce the accelerometer frequency.

I reduced it to 50.0 hz and the acceleration update events stopped building up, thus improving the rendering speed. At 50hz the app runs perfect (the iPhone cannot render at 100hz anyways).

#define kAccelerometerFrequency     50.0 // Hz
Colin