Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: Threads not running in parallel

I'm writing a game in Android/OpenGL and am attempting to separate my OpenGL (render) logic from my game update logic, by running each on its own thread in order to improve performance.

I managed to get each running on its own thread, however according to the Tracer in the DDMS, the threads are still running sequentially (world is my game update thread):

See url as I don't have image privileges: http://img849.imageshack.us/img849/9688/capturegff.png

The threads don't seem to execute code at the same time. I initialise the world thread as follows:

public class World implements Runnable {

    Thread thread;

    public World(...) {
    ...
        // Initialise the player/ball objects
        initialiseObjects();

        thread = new Thread(this, "World");
        thread.start();
}
}

I've implemented my own synchronisation between the two threads. Using an approach similar to that in Replica Island, I have two render buffers: the update thread (should ideally) write to the one of the buffers while the render thread is reading the other buffer. The buffer contains the information needed for the renderer to draw each sprite. Once the update thread has finished updating its buffer and the renderer has finished drawing, they swap buffers and the process repeats.

In code from the game update thread (similar code in the render thread):

    currBuffer.write();
    player.draw(currBuffer.getNext());

   ball.draw(currBuffer.getNext());

    if (particleEffect != null) {
        particleEffect.draw(currBuffer);
    }

    currBuffer.finished();

    while(otherBuffer.isFinished() == false) {
        //otherBuffer is finished once the render thread has finished drawing
    }

    DrawBuffer tempBuffer = currBuffer;
    currBuffer = otherBuffer;
    otherBuffer = tempBuffer;

    currBuffer.changed();
    while(otherBuffer.isChanged() == false) {
        //otherBuffer is changed once the render thread has also swapped buffered
    }

I can't see how the above code could lead to the sequential execution of threads, though I've never attempted multi-threading before so it's possible I'm doing something fundamentally wrong. My attempt to speed up the game have made it noticably slower and far less smooth. Any idea why the threads aren't running in parallel?

UPDATE: The issue was my phone's processor was only single core. I was sure the Incredible S was dual core but alas it's only single. I tried it on the S2 and it indeed ran the threads in parallel.

However, what then is the advantage of multi-threading if only the newer phones on the market support it? I don't understand how Replica Island managed better performance on older, single core phones by implementing multi-threading. Surely the added overhead in synchronising between threads should lead to slower performance if there isn't a second core to take advantage of?

The multi-threading led to slower performance on the single core due to having to generate the buffer that's then passed to the draw thread. On the dual core, it was 5-10% faster, though at about 500 sprites the update cycle took longer than the draw cycle again due to the buffer, thus limiting the speed gains. Obviously with optimisation I can improve that but the question becomes whether it's worth supporting multi-threading at the expense of single core processors. Is it possible to determine a phone's processors in order to determine whether to use multi-threading or not at runtime?

like image 807
awr Avatar asked Dec 11 '12 02:12

awr


1 Answers

Well, technically, 1 CPU runs only one code segment at a time. Your OS scheduler changes processes/threads in a fraction of milliseconds which gives you the illusion of running multiple processes at the same time.

A way to notify runtime that your thread is done for now is calling Thread.yield. There is a busy loop in your code which does not help your situation. It keeps the CPU busy w/o doing anything.

while(otherBuffer.isFinished() == false)

you should use Loks instead of busy loop or you can try calling Thread.yield inside that while loop for an initial performance boost. Btw, also take a look at semaphore which is the simplest solution for such producer-consumer problems. If you want to keep your current codebase, you can use a lock per buffer.

like image 57
yigit Avatar answered Nov 13 '22 08:11

yigit