my app running really slow, NSTimer tweaking?

Discussion in 'iOS Programming' started by mymac1, May 9, 2010.

  1. mymac1 macrumors newbie

    Joined:
    Jul 28, 2009
    #1
    Hi,
    I am running my application in the iphone simulator and it is running really slow.
    I have adapted the original code which is generated within the default openGL code as below:

    - (void)startAnimation {
    self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:0.0000001f target:self selector:mad:selector(gameLoop) userInfo:nil repeats:YES];
    }

    As you can see I have set the timer interval to 0.0000001f in an attempt to speed up the program, however the program takes as long as it takes.
    As the iphone is quite a fast modern device,
    what could I do to speed up my sluggish code and is there a way of determining which part of my code is using up the most CPU cycles?

    Thanks in advance
    m1
     
  2. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #2
    1) Do not schedule a timer with that sort of frequency. That's basically madness!

    2) Use Instruments (documentation online) to work out what's taking time.
     
  3. mymac1 thread starter macrumors newbie

    Joined:
    Jul 28, 2009
    #3
    testing program bottlenecks

    Hi,
    I has a look at the 'instruments' software and looks really good, although will take some time to work it out.
    I have also found the 'shark' program which I extracted some info from my application, some of the things which stand out are as here:

    88.0% 88.0% Unknown Library 0x74f2380 [2.5KB]
    0.0% 88.0% Unknown Library 0x74f18b0 [2.5KB]
    0.0% 78.8% GLRendererFloat gldDestroyQuery
    0.0% 78.8% GLEngine 0x311359b [1.5KB]
    0.0% 78.8% GLEngine 0x317b75d [729B]
    0.0% 78.8% GLEngine 0x317ba36 [1.4KB]
    0.0% 78.8% OpenGLES glDrawArrays

    Not entirely certain but it looks like the 'glDrawArrays' could possibly using up most of the time (specifically it's sub-processes as listed near top)..

    The part of my program code which calls this and is visibly slow looks like this:

    for(int n=0; n<MAX_SPRITES; n++){
    glLoadIdentity(); //reset translations
    glTranslatef(24,18,0); //position, ready to draw any sprite

    // position specific sprite as per coords
    glTranslatef(mySprites[n].xCoord, mySprites[n].yCoord,0);

    glVertexPointer(2,GL_FLOAT,0,spritevertices);
    // set graphic to draw atlas texture coords in array locn xx
    glTexCoordPointer(2,GL_FLOAT,0, uvFrames[xx]);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // draw a quad

    }

    The maximum sprites is around 72 and so glDrawArrays is called this number of times each cycle.
    In addition my background layers and some other stuff call this around 3-4 times each cycle. So all in around 75 times.

    PS: my mac's cpu fan begins to speed up after running the iphone simulator for while with my program, indicating a CPU intensive operation taking place on the iphone simulator.

    Thanks again!
     
  4. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #4
    It is worth noting that the simulator is only an API level simulation: it makes no attempt to simulate the iPhone in terms of CPU or memory limitations. If it's slow on your Mac in the simulator prepare for it to be glacial on a real device.
     
  5. neonenergy macrumors newbie

    Joined:
    Aug 8, 2007
    #5

    Wow, what's 0.0000001f? Is that unit for femtosecond? That would be something like 10^22 times a second.

    As I understand NSTimer spawns a separate thread for each time it clocks, so what you may be doing is saturating your processor and memory due to the insane amount of threads.

    In this case it may be better to raise that timer instead of lowering it.
     
  6. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #6
    NSTimeInterval is measured in seconds. 0.0000001f is 1E-7, which is 0.1 microseconds, or 100 nanoseconds.

    It's still crazy, because it's asking for a 10 MHz rate, i.e. 10 million calls per second to the gameLoop selector. As if there were a display technology that could support that.
     
  7. Cromulent macrumors 603

    Cromulent

    Joined:
    Oct 2, 2006
    Location:
    The Land of Hope and Glory
    #7
    Plan for the future :).
     
  8. mymac1 thread starter macrumors newbie

    Joined:
    Jul 28, 2009
    #8
    Hehe :D yeah, I think its running so fast it is going back in time and slowing down. A sort of 'melting clock' effect.

    I tried increasing the NSTimer firing to help prevent so many threads running.
    Strange thing is that it doesnt even slow even at 1/60th of a second everything looks the same :eek:
    The thread or routine is clogging up somewhere and still stumped.

    Could it have something to do with the frequent calling any of the glLoadIdentity, glTranslatef, glVertexPointer, glTexCoordPointer and glDrawArrays?
    Are any of these considered state changes (I've read state changes are expensive to the CPU).

    The test tool seems to think glDrawArrays might have some link but its not immediately obvious..

    Thanks again!
    m1
     
  9. firewood macrumors 604

    Joined:
    Jul 29, 2003
    Location:
    Silicon Valley
    #9
    You are calling your draw routine faster than it can execute. If you draw routine is taking 1/10th of a second, trying to start it more often than every 0.1 second won't do anything.

    Remove things (less sprites, smaller draw arrays, simpler drawing modes, etc.) from your draw routine until you figure out what's taking up so much time.
     
  10. neonenergy macrumors newbie

    Joined:
    Aug 8, 2007
    #10
    Ohh, that f indicates a float. :rolleyes::p
     
  11. mymac1 thread starter macrumors newbie

    Joined:
    Jul 28, 2009
    #11
    Thread spawning

    Interesting about the NSTimer, so it doesnt really wait till the 'gameloop' finishes, just sort of triggers a call to game loop each interval?

    Could this also apply other subroutine methods?
    Does the program wait untill one subroutine is done before moving on to the next, or might it instead just trigger each one in sequence and hope that I have some setup for managing multiple threads?

    Thanks again,
    m1
     
  12. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #12
    I have never seen anything that suggests NSTimer spawns a thread. Got any documentation showing that?
     
  13. neonenergy macrumors newbie

    Joined:
    Aug 8, 2007
    #13
    Sorry, I was mistaken and got it mixed up with NSThread functionality. I did some searching through documentation and the web and there doesn't seem to be any mention of threading in NSTimer other than a few hints during the initialization. I guess when initialized it runs in a separate thread, scheduling on the main thread's run loop.

    The documentation is kind of vague. I would like to know how it really works.
     
  14. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #14
    This statement doesn't make any sense. You can't schedule a thread to run on a runloop.

    My understanding is that you schedule a NSTimer on a NSRunLoop. If you don't specify one the main run loop is used. At no level does this imply a thread. The run loop sits looping round and round sleeping at the end of every iteration. Each time through it processes any events (mouse clicks, key presses, mouse moves through tracking rectangles etc) and if a timer has become valid it fires it. Note that run loops have modes: a NSTimer may not fire if you schedule it on the normal modes if the run loop is in a tighter tracking mode (drags for example).

    I would note I wrote all that in terms of desktop Cocoa but the iPhone implementation is likely to be very similar. Also it was all written from memory.

    We all might (me included) want to read this...

    Edit: so I read the article I linked and it basically confirmed everything I said above. Things to note: timers fire in the run loop so if your timer method takes a long time to execute you effectively block the run loop. Which blocks event processing. So don't do it. Also only one timer fires per run loop so if you are scheduling two timers you want to fire very frequently you'll get odd issues most likely. All this says to me that for games use a single NSTimer or NSThreads...
     
  15. firewood macrumors 604

    Joined:
    Jul 29, 2003
    Location:
    Silicon Valley
    #15
    Nope.

    An NSTimer really just figures out what to run next after you are done with everything else (in that timers run loop), except that it can wait the proper amount of time if there is nothing else to do (in a low power state if there are no other threads, etc.)

    An NSTimer will do nothing while that run loop is busy. (Except, if it fires, be immediately ready with the next thing to run as soon as the current stuff finishes.)

    So an NSTimer is really for waiting and slowing stuff down (without polling and wasting battery life). Not for speeding anything up.
     
  16. mymac1 thread starter macrumors newbie

    Joined:
    Jul 28, 2009
    #16
    I had tried something earlier and answered my own question re the subroutines (using nslogs to display some informative text and provide timestamps), confirming that one has to finish before the other starts. I did read something about multi-threading but it's a totally different beast, one best left sleeping for now.

    so to come back off the tangent and back to my original problem, there is something slowing down my program.
    The NSlog captures I used indicate that the refresh-display routine is the one causing all the fuss. Only when comment out the code so that a bare minimum is left, it doesnt help.
    Also some info re the post I made Yesterday 08:47 AM, this indicates that glDrawarrays could be an issue as these take up most of the time (as expected but should not slow program down so much).
     
  17. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #17
    So you need to go and read up on what could slow that method down. I suspect that there are ways you can setup the data into it to go faster...
     
  18. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #18
    Go below the bare minimum. Go all the way to nothing. Every time the timer fires, it calls a method that does nothing. And I do mean nothing. Write a specific do-nothing method that immediately returns.

    The program won't draw anything. If it does, then the obvious problem is that when you think it's doing nothing, it's really doing something. You need to find what that is.

    If the program draws nothing and still runs slow, then the problem obviously isn't related to the timer or the eliminated drawing. To find out what, run Instruments and figure out where the time is being spent. It shouldn't be in your do-nothing method, because that's doing nothing. If it is, then maybe you didn't change the timer to a reasonable rate.

    Employ a basic problem-solving strategy: successive elimination.

    Eliminate the entire thing that you think is the problem, then run the program again. If the problem still exists, then whatever you eliminated can't be contributing to the problem. That means you need to eliminate something else, and keep doing that until the problem disappears.

    The main thing to be careful with is that eliminating the entire thing really does eliminate the entire thing. I like to add code to throw an exception in the first statement of a method that should never be executed (or in plain C, call the abort() function). So if it does get executed, I can see the error immediately, rather than being fooled into thinking it's not running.

    If, after eliminating the entire thing, the problem goes away, then you know that the problem is somewhere in the entire thing you eliminated. So sub-divide the entire thing into two parts, eliminate the second one, and repeat the problem-finding process.

    Eventually you'll get a small enough range of code that you can use the debugger.
     
  19. mymac1 thread starter macrumors newbie

    Joined:
    Jul 28, 2009
    #19
    My refreshview method/routine is much like as follows:

    refreshview
    draw background
    render sprites
    draw foreground
    draw buttons


    the draw background and foreground code is similar and looks like:
    Code:
    	glLoadIdentity();													//reset transformation matrix
    	glVertexPointer(2,GL_FLOAT,0,foregroundVerts);						//point to background vertices
    	glTexCoordPointer(2,GL_FLOAT,0, uvForegrounds[0]);					//point to background graphics
    	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);							// draw a quad

    Previously I reduced the number of sprites to just one, and program was still slow, however when I commented out the draw foreground code, things improved.

    My testing previously seems to indicate glDrawArrays is taking time, could it be the way I am setting up the vertex and texcoord pointers?
    Or perhpaps the setup of the const GLfloats?

    the data in the foreground verts and uvForegrounds are similar to each other and used interchangeably.

    Code:
    const GLfloat foregroundVerts[8]={
    		0.0f,  320.0f,		//top left
    		480.0f,   320.0f,	//top right
    		0.0f, 0.0f,			//bottom left
    		480.0f,  0.0f,		//bottom right
    	};
    
    
    const GLfloat uvForegrounds[4][8] = { 
    		/*  no.     left,      top ,    right,     top ,   left,    bottom,    right,    bottom   */
    		/*----------------------------------------------------------------------------------------*/
    		/*00000*/ 0.00000f, 1.00000f, 0.23389f, 1.00000f, 0.00000f, 0.68848f, 0.23389f, 0.68848f,
    		/*00001*/ 0.23389f, 1.00000f, 0.46875f, 1.00000f, 0.23389f, 0.68750f, 0.46875f, 0.68750f,
    		/*00002*/ 0.00000f, 0.68750f, 0.23438f, 0.68750f, 0.00000f, 0.37598f, 0.23438f, 0.37598f,
    		/*00003*/ 0.23438f, 0.68750f, 0.46826f, 0.68750f, 0.23438f, 0.37598f, 0.46826f, 0.37598f,
    	};
    as you can see, I have one size of foreground specified by the 8 x,y pairs of vertices and I have four different foreground/background images, change by updating the [] in the glTexCoordPointer line.

    Thanks,
     
  20. PhoneyDeveloper macrumors 68040

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #20
    You mention in the first post that your app is running slow in the Sim. Are you testing this only on the Sim? If so you need to test on real hardware. It's well known that the performance of openGL is better, in some cases, on hardware than on the Sim.
     
  21. mymac1 thread starter macrumors newbie

    Joined:
    Jul 28, 2009
    #21
    slow app, problem with glDrawArrays

    Hi Again,
    Still mulling over this subject after some time out.
    point of note, I have an old project which runs fast, while the newer one is running a bit slow and is not immediately obvious what the problem is.

    I think that the problem is somewhere in the openGL pipeline and has something do do with the data I am presenting.
    For example opengl seems to prefer smaller quads and uses up less cpu time than those with bigger vertice coordinates.
    i.e I have two methods, one refreshes 100 sprites each of 32x32 in size and they are rendered a lot faster as a whole in contrast to a single 480x320 quad which takes many times longer for some reason.

    I'm trying to think what is different between my projects, some things which I think could be potential issues:

    my vertice and uv coord data is stored in a separate .h file instead of being included in the 'drawview' method.

    Vertices are specified with more digits after the decimal point of the GLfloat.


    Using opengl to rotate the screen, this is set-up once at the beginning of the program. further renders appear automatically rendered.

    Much of the opengl setup code has been moved to the beginning of the program and called once only (previously the template's 'drawview' contained most the opengl setup code).

    ----
    your thoughts?

    Thanks in advance
    m1
     
  22. softwareguy256 macrumors regular

    Joined:
    Jun 5, 2010
  23. mymac1 thread starter macrumors newbie

    Joined:
    Jul 28, 2009
    #23
    hi,
    tried running in release, not much different.
    Definitely an opengl pipeline thing, there isnt any more code beyond a glDrawArrays call which I can change, so either have setup openGL wrongly, missing something or presenting the data in a way that it doesnt like very much.

    Sort of thinking that I am trying to push a boulder through a garden hose, or perhaps the hose is pinched somewhere or both!
     

Share This Page