iphone 3GS / OS 3.0 performance issue?

hey all…

i’m just reaching out to see if anyone else has experienced performance issues using oF 006 and iPhone OS 3.0 / 3GS. i have a project involving a particle system + accelerometer that has been running quite smoothly on a first generation iPhone with OS 2.2.1. This same project when run on an iPhone 3GS with OS 3.0 exhibits a visible stutter.

i haven’t yet tried to install OS 3.0 on the first gen iPhone to try to isolate a hardware / software issue. i realize that the graphics hardware on the 3GS is different than the predecessors, although most reports have been of a significant performance boost, rather than a degradation.

i could explain more about my specific code if necessary, but i was just wondering if other people have shared my experience with their own work.

regards,
-robert

Hi Robert, I saw no difference in performance when I upgraded my iPhone 3g to os3.0. However when I tried a few of my ofw apps on an iPhone 3gs the speed increase was phenomenal to say the least. Both my gold dust and meshmerizer were running about double the fps and super smooth. So probably somethig unique to your setup. If you find out lt us know what it is.

i have one app that occasionally runs WAY slower than it did on my old iphone, but often runs much faster. I haven’t been able to figure out what exactly is going on though. Assumed it was with the phone, but maybe it’s some strange bug…

Not really a solution, but when I jacked up the frame rate parameter to 120 or 240 fps the 3GS performance got much better…faster than on the first gen iPhone. I realize that the framerate parameter is more of a speed limit, but 60 fps should have been fine.

With golddust, did you simply install the existing binary on the 3GS or did you recompile with the OS 3.0 SDK as well?

-r

interesting. Actually the framerate is not so much a cap on the speed, but it sets the frequency of the timer which calls the update and draw (NSTimer).

btw, I recompiled with SDK 3 and ran on my existing iphone 3G, (which gave same performance as before), and in a separate experiment tried the OS 2.2 binary on an iphone 3GS, which ran waay faster. I did not try the OS3 binary on a 3GS.

right, i knew that…the frameRate initializes a repeating NSTimer at 1/frameRate seconds. i was referring to zach’s comments at an oF knitting circle…regarding the framerate parameter not really *boosting* the performance, but setting a requested playback rate.

regardless, 1/60 seconds should have been fine…as it had been on the first gen iPhone with OS 2.2.

i’ll try a 2.2 binary of my app on the 3GS and let you know what i find.

Hey, an interesting side note:

iPhone 3G Processor Speed: 412MHz
iPod Touch 2nd Gen Processor Speed: 532MHz
iPhone 3G S Processor Speed: 600MHz (according to T-Mobile Netherlands)

iPhone 3G/iPod Touch RAM: 128MB (?)
iPhone 3G S Memory: 256MB (also from T-Mobile Netherlands)

Posting this from my iPod Touch 2nd Gen (still on OS 2.2.1, Jailbroken)

I haven’t been able to completely solve this yet, but I’ve found some documentation of others reporting similar issues. There are some variability in the reports, so I’m not sure if they are all explicitly related.

Best guess currently is that this is an SDK3.0 / OS3.0 / 3GS issue. There has been some discussion https://devforums.apple.com/thread/16515?start=25&tstart=0 on Apple’s dev forums that the issue is relieved in beta versions of the SDK (the specifics of which are under NDA).

The (mostly) successful workaround has been to abandon the NSTimer method for controlling the frame rate in ofxiPhone’s iPhoneAppDelegate in favor of dropping the timerLoop into a separate thread which is throttled by a sleep command. An iPhone 2G (2.2.1) and 3GS (3.0) are both performing at 50fps. I was previously able to occasionally able to achieve 60fps, but if I overran the NSTimer my framerate dropped to 30fps.

The other contributing issue (on the 3GS/3.0) is a drop in framerate during and after the display of a UIAlertView. Specifically, I’m displaying an alert view over the EAGLview, then dismissing it (and releasing the alert view instance) but the frame rate stays at 40fps. Sporadically the framerate will return to 50fps, but I haven’t isolated the causality.

This same alert view code on the iPhone 2G will initially drop the frame rate to 30fps during the “pop” animation, but then quickly returns to 50fps, even while it’s still composited over the EAGLview.

Confusing the matter is that I initially had the application *always* display an alert view at launch (asking if the user would like to restore the game state). It’s likely that this clouded my earlier findings. The app on the 3GS performs at full speed after launch when an alert view is not displayed…and continues to perform optimally until an alert view appears.

In the meantime, worst-case 40fps using NSthread vs 30fps using NSTimer is an acceptable performance gain (for this specific application). I understand that the overhead of running the timerLoop in another thread may degrade performance for CPU intensive programs.

Below are the changes to ofxiPhone iPhoneAppDelegate.mm:

Add this method:

  
  
-(void) timerLoopThreaded:(id*)sender {  
	// create autorelease pool in case anything needs it  
	NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];  
	  
	// SET CURRENT GL CONTEXT FOR THREAD  
	[EAGLContext setCurrentContext:iPhoneGlobals.glView.context];  
	  
	double begin_time; // RC: testing alternative loop method  
	while(!kill_loop)  
	{  
		iPhoneGlobals.iPhoneOFWindow->timerLoop();  
		  
		// throttle the loop for desired framerate  
		double sleep = (1.0/framerate) - (((double)CFAbsoluteTimeGetCurrent()) - begin_time);  
		if(sleep>0.0) [ NSThread sleepForTimeInterval:sleep];   
		double end_time = (double)CFAbsoluteTimeGetCurrent();       
		//float fps = (1.0 / (end_time-begin_time));       
		begin_time = end_time;  
	}  
	  
	// release pool  
	[pool release];  
}  
  

Add this line at the bottom of applicationDidFinishLaunching:

  
  
[NSThread detachNewThreadSelector:@selector(timerLoopThreaded:) toTarget:self withObject:nil];  
  

Comment out the existing implementation of setFrameRate and add this substitute:

  
  
-(void) setFrameRate:(float)rate {  
	framerate = rate;  
}  
  

Update applicationWillTerminate:

  
  
-(void) applicationWillTerminate:(UIApplication *)application {  
	[timer invalidate];  
	kill_loop = true;  
}  
  

Finally, add in some instance variable declarations to iPhoneAppDelegate.h:

  
  
@interface iPhoneAppDelegate : NSObject <UIApplicationDelegate> {  
	NSTimer			*timer;  
	float				framerate;  
	bool				kill_loop;  
}  
  

I’m still hunting for the cause of the slowdown on the 3GS. I certainly welcome any advice or warning on the above NSThread implementation. In the meantime I’m going to look for other ways to optimize my logic and drawing code further.

cheers!
-robert

ps. UI stuff has to happen on the main thread. I had to modify my implementation of the ofxUIAlertView wrapper to ensure this. Of course, this is my wrapper and I don’t think anyone else is using it…so this is just for posterity:

  
  
void ofxiPhoneAlertView::show(){  
	// UI events need to occur on the main thread.  
    [alertViewDelegate performSelectorOnMainThread:@selector(show) withObject:nil waitUntilDone:NO];  
}  
  

Hey robert, thanks for all the in depth tests and info!

At the beginning of ofxiPhone (at the beginning of the year), I read on a forum somewhere some guy reporting up to 5fps more performance using the NSThread+sleep approach instead of NSTimer. So I tried it out at the time and had it like that for a while but didn’t see any gain (i can’t say I stress tested it though). Later many people on the forum debunked his theory too so I dropped it as it was a bit more complex and I chose the much simpler route of NSTimer. But what you are saying now 40fps vs 30fps is a HUGE difference so definitely worth considering. Though having the loop in a separate thread is gonna complicate matters a bit, especially for beginners, so I personally would be reluctant to make it the default behavior in ofxiPhone. But if we are gonna see some serious performance gain I definitely would want some of that action too :stuck_out_tongue: So maybe we could make it optional? E.g. in testApp::setup() call ofUpdateInSeparateThread(); or something like that. This can only be called in setup and if you don’t call it an NSTimer is setup, if you do call it the NSThread is setup. (I generally like having a safe & simple route which compromises speed for ease of use, but at the call of a function you can get a much faster but more dangerous implementation but sharing the same API. e.g. ofxMSAShape3D::setSafeMode(bool) )

You say this only happens on the 3GS? so I can’t test it (have a 3G). if you find out any more info as to why this is happening let us know.

P.S. I noticed that (and its well documented actually), that having any UIView over an EAGLView really really slows down BOTH views. You can see how sluggish the sliders (UISlider) are in my Gold Dust and Meshmerizer. And it doesn’t make a difference if the background of the UIView is completely opaque. It doesn’t even matter if you don’t actually do anything in your update or draw anything. Just the simple act of flushing opengl really slows down the UIViews. For this reason I added ofSetFrameRate(0) to cancel the NSTimer (its in the SVN), and thats what I use in MSA Remote now when the menu is up, and the sliders are nice and smooth.

memo:

so far it seems confined to the 3GS. i haven’t tried to put OS 3.0 on my 2G to isolate a hardware/software source of the issue. unfortunately, i’m limited to my own experience and what i’ve read from others. i believe that the 2G and 3G share the same hardware as far as CPU/GPU go.

i didn’t have to change any of my app otherwise to support the NSThread. everything i did was contained in the iPhoneAppDelegate class. however, i also see the merit in implementing a toggle to set the desired method. as i found, there may also be unintended consequences for other addons and such.

as far as the performance gain, i would caution that there are several variables here. i think the 30fps may have had to do with the NSTimer overrunning and only catching every other trigger at 60fps where the thread just chuggs along. however, for me and this app, i’ll take it.

pps. i notice that on the 2G…the alert view animation studders…however on the 3GS it’s super smooth. as noted though, after the animation is finished, the 2G ramps quickly back up to 50fps, even with the compositing (although i skip most of the game logic in update() while an alert view is visible). during the display of the alert view on the 3GS the frame rate drops to 40fps, and then stays there even after the view is dismissed (and eventually discarded).

that’s the crux of my issue…i can deal with the performance hit while compositing, but am flummoxed that the poor frame rate persists until the application is relaunched (sans alert view).

Hey, btw how do you measure and read the fps of your apps? It seems every method I can think of actually has a non-negligable effect on the performance in true quantum observer effect style. I don’t want to display text on the actual iphone app itself, so in very ghetto style I do:
if(ofGetFrameNum()%120==0) printf("%f\n", ofGetFrameRate());

which is possibly even worse cos it needs to be running via xcode :s

I was originally using NSLog with ofGetFrameRate() on a double tap.

Currently, I’m just displaying the ofGetFrameRate() as text…and am accepting that there will be a performance hit. However, at this point I’m really just trying to compare iPhone OS 2.2 / 2G and OS 3.0 / 3GS…and figure that each platform will have to deal with the same code and a similar performance hit.

In my case, I’m not looking for a deviation of ±1fps, but a 10fps hit in my worst case scenario. The overhead of the framerate display doesn’t seem to affect this.

Even with the text fps display the app can get 55fps (±5) on the 2G and 60fps on the 3GS.

So, not entirely scientific, but I feel accurate enough for comparison.

btw, here’s the snippet I’m using. Don’t judge me :slight_smile:

  
  
	// display the Frame Rate in debug mode  
	if(debugMode){  
		string fpsmsg = "";  
        { std::ostringstream ss;  
            ss << fixed << setprecision(1) << ofGetFrameRate() << " fps";  
            fpsmsg += ss.str();  
        }  
	ofSetColor(200,200,200);  
        ttf.drawString(fpsmsg, 10, 20);  
	}  
  

ok fair enough, (btw do you know of ofToString(float f, int precision); ?)

I’ve just come to a point where i’m trying to squeeze every last ounce of performance out of a new app, and I also noticed that my app is constantly freezing a bit (for a frame or two) every second or so. A bit like the visible stutter you were mentioning. It is very annoying and I’m trying to get to the bottom of it but can’t figure it out. I don’t think i’ve noticed this before. I’m on 3.0.1 OS iPhone 3G. The app is a particle system with about 5K particles and VBOs for size, color, position etc. (very similar to gold dust). I’ve removed all interaction from accelerometer / touch etc. to try and isolate the problem but with no luck at the moment.

this is what I’m using now for a rough FPS check:

  
  
#define kFPSMult	4  
	// draw a green bar width of fps  
	glColor4f(0, 1, 0, 1);  
	ofRect(0, 0, ofGetFrameRate() * kFPSMult, 20);  
	glColor4f(0, 0, 0, 1);  
	// draw a line every 10 fps  
	for(int x=(kFPSMult * 10); x<ofGetWidth(); x+=(kFPSMult * 10)) {  
		ofLine(x, 0, x, x % (kFPSMult * 30) == 0 ? 30 : 20);		// draw a taller line every 30fps  
	}  
  

I’ve tried your threading code and my observations are a bit confusing (btw I’ve added your mods with #ifdefs and put it on the SVN if you want to check it out. by default the loops use NSTimer, by #defining a var it uses NSThread. Doing it like this for now for testing).

Using the NSTimer, my fps bar is pretty much solidy on 30fps, fluctuating around a little bit. But clearly I can see my particles are stuttering, almost freezing for a frame or two every second or so. But this is not really observable in the fps bar. Maybe because ofGetFrameRate() averages over the last second, so those stutters are lost.

Using the NSThread, my fps bar is jumping erraticly between 30-45fps. So that looks like a massive fps increase. BUT visible the particles look like they are stuttering a lot more. So i’m not sure what to think!

if you figure anything else out lemme know!

Uysin

the stutter i’m experiencing is constant…so i suppose that it’s not really a stutter, but just poor frame rate. the onscreen elements stutter as in they don’t move smoothly as they should at 60fps…but i’m not getting a hiccup every 1-2 sec like you describe.

how is the performance of your app if you enable Airplane mode, or disable Notifications?

i tried your fps bar, and in optimal situations my app is steady at 60fps…drifting down to 55fps when a lot of sprites are created, but it comes back up again. on the 3GS the fps bar goes steady at 40fps during and after the first alert view is visible.

so, i don’t know what to make of your findings…the bar is very responsive, but not swinging wildly by ±15fps at all.

how is your app working on OS 2.2?
(ps. read the OS 3.1 dev beta forums regarding timer loops)

ok, so I added the threading properly. You can now call a global function to enable the update/draw to run in a separate thread. You need to call it in testApp::setup() and before any ofSetFrameRate()

  
iPhoneEnableLoopInThread() (declared in ofxiPhone.h)  

also I changed the sleep calculation to use mach_absolute_time() as it’s supposed to be the bolox for accuracy. But still i’m having problems. I wrote a tiny little test app which does the exact same amount of calculations and drawing every frame, and it pushes the device quite hard. I’ve tried with NSTimer and NSThread, compiling for OS 3.0, 2.2, 2.2.1 but always get the same thing. It’s freezing for a split second every second or so. (It seems a lot worse with NSThread).

I posted more info and example app on my blog in case anyone has an answer. I’d be curious to see how it performs on your 3GS (you’l probably have to push number of columns quite high to bring it to its knees)
http://www.memo.tv/looping-via-nsthread-vs-nstimer