Multithread performance

Hey, I’m playing with Multithread in jme and I’m having unexpected results when running two or more threads parallely. I isolated the code in a simple structured main method, so I can solve the issue. Bellow, is a simple code that I did which executes a callable which runs for 15 seconds, and it counts +1 each hundredth:



[java]

public static void main(String[] args) {

ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1);

//executes the callable

exec.submit(new Callable<Object>() {



private long initialTime, lastTime, currentTime;

private int count;



public Object call() throws Exception {

initialTime = System.currentTimeMillis();

System.out.println("Started " + initialTime + “ms”);

while (currentTime < 15000) {

currentTime = System.currentTimeMillis() - initialTime;

if (currentTime != lastTime) {

lastTime = currentTime;

if (currentTime % 100 == 0) {

count++;

}

}

}

System.out.println("Terminated " + currentTime + “ms " + count + " times”);

return null;

}

});

[/java]



and the result is fine, the count was increased 15 times as expected:



output:

[java]

Started at 0ms

Terminated at 15000ms 150 times

[/java]



But when I executes two or more threads, the performance decreases a bit, and the result is not expected :



[java]

ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(2);

//executes the firstcallable

exec.submit(new Callable<Object>() {



private long initialTime, lastTime, currentTime;

private int count;



public Object call() throws Exception {

System.out.println("Started at " + initialTime + “ms”);

initialTime = System.currentTimeMillis();

while (currentTime < 15000) {

currentTime = System.currentTimeMillis() - initialTime;

if (currentTime != lastTime) {

lastTime = currentTime;

if (currentTime % 100 == 0) {

count++;

}

}

}

System.out.println("Terminated at " + currentTime + “ms " + count + " times”);

return null;

}

});

//executes the second callable

exec.submit(new Callable<Object>() {



private long initialTime, lastTime, currentTime;

private int count;



public Object call() throws Exception {

System.out.println("Started at " + initialTime + “ms”);

initialTime = System.currentTimeMillis();

while (currentTime < 15000) {

currentTime = System.currentTimeMillis() - initialTime;

if (currentTime != lastTime) {

lastTime = currentTime;

if (currentTime % 100 == 0) {

count++;

}

}

}

System.out.println("Terminated at " + currentTime + “ms " + count + " times”);

return null;

}

});

[/java]



output:

[java]

Started at 0ms

Started at 0ms

Terminated at 15000ms 145 times

Terminated at 15000ms 149 times

[/java]



I’m trying to figure it out because in rhythm game I’m doing, I update the red buttons each hundredth (for example, in a interval of 1 minute, the buttons have to be updated 600 hundredths). But the buttons are updated less times than expected. Those are the red buttons :



http://i.imgur.com/eNZvR.png



-Cheers

There is only so much CPU to go around. When one thing loops and hogs it, another thing won’t get it. From the above, I’d guess you have two cores at least or I’d have expected the performance to be much worse… about half, actually. The fact that you only lose a few loop iterations is pretty good.



Why are you updating the buttons 600 times in a minute? Still, 10 updates a second is not very much… but a busy loop may not be the best way to do it.



Can you explain more about what you are trying to accomplish? I’ve done near real-time apps that played sync’ed audio and midi music before and didn’t have to gobble up 100% of a CPU to do it.

1 Like

Thanks for the input.


Why are you updating the buttons 600 times in a minute?


The buttons have to be updated according to the music ok? Then I update the buttons every hundredth. When I mean "update the buttons", I mean that I "move" the buttons to the left every update, and every update I'm moving them 2% to the left. First I position the buttons at the right positions in sequence, I find the position by divinding the time of the button in sequence by 50 (it's a random number that worked :)). For example: To put the button at 1:45, I set its initial position on the right = 1:45 / 50 = 105000 / 50 = 2100%. I've tested other values too. Here's how I add the combo buttons like the image above:

[java]
Combo combo = new Combo(3000, "some combo");
Combo combo2 = new Combo(4000, "some combo 2");
sequenceBar.addCombo(combo);
sequenceBar.addCombo(combo2);
sequenceBar.start();
[/java]

It position the combo button 1 in 0:03 and the button 2 in 0:04. For now, I'm using just one thread to handle the sequence bar, but the result is not expected, it should finishes with 150 callings, because the loop repeats every hundredth:

"SequenceUpdateCallable took 15001ms to finishes with 149 callings."

The "15000" is a music duration of 15 seconds.

Did you get it?

Also, if you see the game I’m having as motivation I think you’ll get it better : http://hub.jmonkeyengine.org/groups/beta-1-game-contest/forum/topic/wip-rhythm-game-contest-entry/?topic_page=2&num=15#post-150497

I think you are doing it backwards, though. Anything that is depending on “number of loop iterations” but is really trying to simulate time is always going to be a problem. Especially when you could just use time.



Maybe don’t bother with a second thread at all and on update() just put the things where they are supposed to be based on the current time. All of your timing problems will disappear.

1 Like

Yeah, I thought Timer could be the simplest solution at first, I used it first, but it had the same behavior as the callables are having now, but I changed Timer to Callables because Timer is not Multithread and it might reduces the game performance?

Just doing the few division operations required to figure out where your buttons should go on each update - even if there are ten of them on screen - isn’t going to make a dent in your framerate. In fact, it’s probably faster than the cost of submitting a callable to an executor (depending on which executor you use)

1 Like

Yeah. Thank you guys. I changed to Timer again and the result was like I wanted :smiley: :smiley: :smiley: :smiley: :smiley: :smiley: . I was using Timer wrong before…Btw hopefully this doesn’t decrease the framerate as long as the game grows ;).

It’s working like a charm with Timer :D. The algorithm that i did positions the “move bars” (the red spheres) in right position in “rhythm track” (where the move bars travels left). Then when I start the Timer thread, the move bars starts traveling left. I do like this:



[java]

rhythmTrack.addMoveBar(3000);

rhythmTrack.addMoveBar(4000);

rhythmTrack.addMoveBar(15000);

rhythmTrack.addMoveBar(60000);

rhythmTrack.start();

[/java]



It positions 4 move bars in right side. The parameter is the time in long where the move bars will be positioned, and I calculate the position by : time / 50 +"%". Then the positions in example above are respectively : 60%, 80%, 300% and 1200% (these are the positions that the move bars are positioned starting from the middle).



What do you guys thinks about this :)?

@pspeed said:
I’ve done near real-time apps that played sync’ed audio and midi music before and didn’t have to gobble up 100% of a CPU to do it.


Have you by chance already done a retard / advance sound feature for your apps? If yes, it was built with OpenAL? Still didn't find any OpenAL references about it :/.

This was home brew Java recording software I was working on many years ago using the JavaSound stuff. Nothing really relevant otherwise to this discussion.

Anyway thanks. Btw I found the main key to do that. It’s org.lwjgl.openal.AL11.AL_SEC_OFFSET :). I’ll take a look into this ;).

glauco, how about you cut up your sound into multiple files that you play after another? You could also make your own AudioData class that dynamically loads the data from the audio files instead of the default jME3 AudioData thats allocated for a file.

Sorry. I’m trying to understand what do you mean about “cut up your sound into multiple files that you play after another”. What I wanna do is like a “skip back” and “skip forward” feature. Is this what do u mean?



EDIT: skip not the entire music, just the seconds / miliseconds…

EDIT 2: <You could also make your own AudioData class that dynamically loads the data from the audio files instead of the default jME3 AudioData thats allocated for a file.



Yeah. Nice.

@normen and @pspeed and @nehon : sorry for bothering you guys, but such stuff that I was looking for already exist (poorly expressed words xD). I can express my words better in Portuguese :P. This is the method :



[java]

audioNode.setTimeOffset(float timeOffset);

[/java]



Now I can proceed with my game . The solution was really easy. I don’t believe I spent days trying to figure it out. It’s because this was my first sound experience in jME :).



@nehon: Do you remember that discurssion in another thread that we were talking about it? Do you thought I meant a “decrease / increase speed” ok? My bad!. When you said something like “Kirill said it’s awful complicated to implement!” I thought I was lost :P.



-glaucomardano

setTimeOffset does not do what you want i’m afraid

afaik it just postpone the beginning of the audio file for some time.

What I can do is more or less the sound sequencer editor in blender, where when the player clicks on a part of the sequencer, it plays the sound at the exactly milisecons. Doesn’t this method do that? I’ve just tested the TestWav.java and I thought it did what I wanted. The sequencer editor in blender :



well apparently… this methods is here for seeking you’re right…the thing is it only works with non streamed audio files.



Look at TestMusicPlayer, it does exactly what you want to do.

you may have to change the way the audio file is loaded though line 176 to

[java]

AudioKey key = new AudioKey(selected.getName(), false, false);

[/java]

Also depending on the file you load, you’ll need to increase the jvm heap space to avoid OOM errors

I’m gonna look into this, to make it work even with streamed files.

1 Like

Thanks. I was creating a testcase right now. The TestMusicPlayer.java will save my time.

Thanks man. This is really what I needed!!! When I tried for the first time, it wasn’t working (No audio renderer available), streamed or not, and increased the jvm heap space, then I decided to update my working copy and it worked like a charm, both streamed and not.