Modifying StandardGame to increase GameTaskQueue throughput

As I understand it, if you have set StandardGame to have a limited framerate, it loops through the update cycle, sleeps for a while, and then repeats.



This works fine, but my app is multi-threaded, and makes heavy use of the GameTaskQueue system to pass code to the GL thread for execution in the future. By default, those queues are set to only execute one item per call to execute() - which is good, because it spreads around the queued items over time, reducing lag if several slow calls are being made. However, its not so good if you frequently have a large number of very simple calls being passed to the queue, since they may end up waiting a long time before executing, even though they could all be done at once.



So here is my question: why not make use of the time normally spent sleeping at the end of the update cycle to call items in the update queue? The implementation would be pretty simple, just executing items off the queue until either its empty, or enough time has passed, something like this (modifying the existing code from StandardGame):


         // Fixed framerate End
         if (preferredTicksPerFrame >= 0) {
            GameTaskQueue queue = GameTaskQueueManager.getManager().getQueue(GameTaskQueue.UPDATE);
            frames++;
            frameDurationTicks = timer.getTime() - frameStartTick;
            while (frameDurationTicks < preferredTicksPerFrame) {
               if(!queue.isEmpty())
               {
                  queue.execute();
               }
               else
               {
                  long sleepTime = ((preferredTicksPerFrame - frameDurationTicks) * 1000) / timer.getResolution();
                  try {
                     Thread.sleep(sleepTime);
                  } catch (InterruptedException exc) {
                     logger.log(Level.SEVERE,
                                      "Interrupted while sleeping in fixed-framerate",
                                      exc);
                  }
               }
               frameDurationTicks = timer.getTime() - frameStartTick;
            }



(This also requires adding an isEmpty() call to GameTaskQueue).

I tried this and saw significant improvements to a few places in my app - is there any reason not to do this?

The only reason I can think of is that perhaps having the sleep in there allows other tasks on other threads to execute, particularly on single core machines?

Hmm… thats a good point that I hadn't thought of. Standard game does call Thread.yield() right afterwards though, at the least.

But I think that if you are depending on the opengl thread to have largish down-times where it is sleeping, then you probably shouldn't be throwing large numbers of complicated tasks it's way. On the other hand, if you are sending it lots of tasks, it shouldn't become a bottle neck if it can avoid it.



You can modify this strategy a little further so that it plays nicely with vsync, too. From what I can tell, with vsync enabled, a call to Renderer.displayBackBuffer() will block for approximately the amount of time that standard game would normally be spending sleeping, waiting for the monitor, and only then display and return. This is the expected behaviour with vsync enabled, and we wouldn't want to be using our own software frame rate limiting mechanism at the same time. But - we could still make a best effort attempt to execute queued tasks before letting vsync take over, if we can guess at how long vsync will normally wait and be sure we don't take more time than that.



So something like this:



while (time < expectedTimePerFrame*.75 &! queue.isEmpty())
       queue.execute

Display.displayBackBuffer()



This can easily be combined with the normal sleeping behaviour so that the if vsync is not enabled, then the game will attempt to sleep for the requisite amount of time.

Personally I think GameTaskQueue does its job exactly as it should.  If you want to add better control for throughput into that queue I would think it best to add that support externally.  For example a thread that interjects tasks into the queue at a slower rate or keeps too many things from stacking up in the queue.  This give you the ability as the developer to decide how you want to integrate with the queue versus us trying to make it support all of these conditions directly for you.



Don't get me wrong, I definitely agree your ideas have merit, I just prefer to have a more modular design and let that be handled at a higher level.

darkfrog, I agree with you in principle. But I don't think it is currently possible to accomplish what I want to without changing StandardGame's behavior, slightly.



StandardGame controls the only means of access to the GL thread (as it should), and I want to increase the throughput of code executing in that thread, not reduce it, without having an impact on the framerate.



As it currently stands, the only way to execute code in the GL thread (as I understand it) is through the GameTaskQueue, and that queue operates in only two modes: execute everything, no matter how long it takes, at each cycle, or execute just one thing, even if it is part of a set of many simple things, at each cycle.



Since I am depending on GameTaskQueueManager.update(), and StandardGame.executeInGl() to execute the small peices of code that have to occur in the GL thread, I find that I am calling it quite often with small, fast jobs.



As a result of only at most one queue item being executed per frame, I sometimes have a series of simple tasks being executed from one or more other threads take several frames before completing, instead of returning immediately. This becomes especially a problem when I have one thread blocking while it waits for code to executeInGL, while a second thread schedules several tasks for future execution in the Update queue.



By making the small changes I mentioned above, I was able to significantly reduce loading times in particular, from several seconds, to less than one second.

If you wanted to allow for this kind of optimization while still allowing for the previous behaviour of StandardGame, perhaps this could be added as a setting in GameTaskQueue? For example, the queue currently can be set to execute all items, or to execute only one. What if it also had a setting to try to execute as many as it can within a certain time period, on a best effort basis?

Have already given my thoughts to this design and backed it up by posting code in another thread.



Simply, you need to do throttling…