Multithreading speed

I need to multithread because loading my procedural world is a bit expensive. I tried the ScheduledThreadPoolExecutor.submit(callable) (in the simpleUpdate method) from the tutorials, the classic initializing of a thread, and some ExecutorService.submit(runnable) which I got from looking around of the code of TerrainGrid. Yet, the game still lagged a bit while loading new parts of the world, even though the computer wasn’t on “full CPU”. Out of the three I think the 1st one worked the smoothest (as expected, since it’s the way suggested).

I reread the multithreading tutorial, changed the ScheduledThreadPoolExecutor’s instance method’s argument from 4 to 8 (my computer’s quad core, the tutorial said it should be from 1 to 2 times the number of cores). It reduced lagging by quite a lot (there’s an occasional fraction-of-a-second-freeze, which I believe is from garbage collection but have no idea on how to deal with).

Is there something I might be doing that’s slowing things down even though I’m multithreading, something I should do, or a better way to multithread?

Make sure you limit the amount of things you add to a scene on any given frame. The same goes for removal.



Also, what version of JME are you using?

@pspeed Thanks, I’ll go try that.

By the way does it hurt if I used Thread.sleep(~10) after adding/removing? Because the game used to throw some error (EXCEPTION_ACCESS_VIOLATION, similar situation) until I did that after every add. I’m assuming it was some RAM thing, and allowing it to sleep let it have more chance for clearing up some of that memory.

Here’s how part of my code works:

1.executor.submit(callable)

2.callable calls a world updater method, returns Void

3.updater method does stuff, Thread.sleep(~10) occasionally; something like:

for (int i = 0; i < updates.size(); i++) {

updateChunk(updates.get(i));

Thread.sleep(10);

}

I use RC2.

I’m not assuming to know the detail in what you’ve implemented (since you sound very knowledgeable about jme internals), but a few comments, in a general performance-diagnosis sense that might help.



First, if you’re not seeing “full” CPU (beyond around 80%) during the lags, there is likely to be an IO/interrupt/kernelspace+userspace issue of some type happening.



Second, unless the calculations/IO/preloading that you’re generating for your procedural world needs to be executed within the context of a single frame render time-slice, don’t. Find a way to pre-load into memory on another thread/core (or while a video is playing…) and feed that into jme (enqueue/callable) as its requested.



Third, build yourself a System.nanotime() subsystem (nanotime stamps plus an ident string in source thread, posted through a queue to a logging/accumulation thread… does wonders), so you have a better way to exactly illuminate what is taking longer than you assumed.



The best optimizer is between your ears, as they say… and that’s the funnest place.



Good luck :smiley:

@seann999 said:
@pspeed Thanks, I'll go try that.
By the way does it hurt if I used Thread.sleep(~10) after adding/removing? Because the game used to throw some error (EXCEPTION_ACCESS_VIOLATION, similar situation) until I did that after every add. I'm assuming it was some RAM thing, and allowing it to sleep let it have more chance for clearing up some of that memory.
Here's how part of my code works:
1.executor.submit(callable)
2.callable calls a world updater method, returns Void
3.updater method does stuff, Thread.sleep(~10) occasionally; something like:
for (int i = 0; i < updates.size(); i++) {
updateChunk(updates.get(i));
Thread.sleep(10);
}
I use RC2.


The sleep is where your pause comes from. If you are doing that on the render thread then of course it will pause the update loop, ie: all rendering, making your game feel like it glitches. And if you aren't doing it on the render thread then you will get problems because you are updating the scene graph on a separate thread.

The access violation is something else.

Anyway, your architecture would be better served by having an update queue (ConcurrentLinkedQueue is best). Submit your callables like normal but when they are done then add the result to the queue. Every update frame on the render thread, pull one item off (if the queue is not empty) and update it.

Do not sleep().

@pspeed Is simpleUpdate on the render thread?

@pspeed said:
The sleep is where your pause comes from. If you are doing that on the render thread then of course it will pause the update loop, ie: all rendering, making your game feel like it glitches. And if you aren't doing it on the render thread then you will get problems because you are updating the scene graph on a separate thread.

The access violation is something else.

Anyway, your architecture would be better served by having an update queue (ConcurrentLinkedQueue is best). Submit your callables like normal but when they are done then add the result to the queue. Every update frame on the render thread, pull one item off (if the queue is not empty) and update it.

Do not sleep().


Yes.

@pspeed Sorry, more questions:

  1. I thought sleeping there didn’t affect the main thread (I think the rendering thread?), since I thought the submitted stuff ran on a different thread?
  2. Does it matter if I submit an instantiated callable or a reused global variable?

Maybe I misunderstood what you “updates” loop was doing. It looked like that was the one collecting the things that had been updating them and then applying it to the scene graph… if that isn’t done on the rendering thread then that’s a HUGE problem.



So now I believe I don’t have enough information to actually help.

@pspeed Sorry if I’m not being clear, but here’s the pseudocode:

[java]

public void simpleUpdate(float tpf) {

//add player-edited chunks (more specifically, chunks clicked on) to that update list

executor.submit(updateChunksCallable); //I think “chunk” is what you call “leaf” in Mythruna

//player movement, etc.

}



Callable<Void> updateChunksCallable = new Callable<Void>() {

public Void call() {

updateChunks();

return null;

}

};



private void updateChunks() { //creates new chunks if the player moved, removes far-away chunks, replaces edited chunks (usually by the player)

//in here is that loop I mentioned

}

[/java]

And how do the changes make it back to the scene graph? That’s the part you’ll want to limit per frame.

@pspeed Oh, the method that gets called in the loop (there’s several loops actually, one for completely replacing, one for adding, one for removing, etc. The example’s the one for replacing) uses the game.enqueue(callable) for making changes to the scene graph.

@seann999 said:
@pspeed Oh, the method that gets called in the loop (there's several loops actually, one for completely replacing, one for adding, one for removing, etc. The example's the one for replacing) uses the game.enqueue(callable) for making changes to the scene graph.


@pspeed said:
Anyway, your architecture would be better served by having an update queue (ConcurrentLinkedQueue is best). Submit your callables like normal but when they are done then add the result to the queue. Every update frame on the render thread, pull one item off (if the queue is not empty) and update it.


Something to try sometime.

Edit: and by "update it" I mean make the scene graph changes. This is instead of queuing callables on the application.
@pspeed said:
@seann999 said:
@pspeed Oh, the method that gets called in the loop (there's several loops actually, one for completely replacing, one for adding, one for removing, etc. The example's the one for replacing) uses the game.enqueue(callable) for making changes to the scene graph.


@pspeed said:
Anyway, your architecture would be better served by having an update queue (ConcurrentLinkedQueue is best). Submit your callables like normal but when they are done then add the result to the queue. Every update frame on the render thread, pull one item off (if the queue is not empty) and update it.


Something to try sometime.

Edit: and by "update it" I mean make the scene graph changes. This is instead of queuing callables on the application.

^--- multithreading @pspeed ;)
@normen said:
^--- multithreading @pspeed ;)


It's just that in this case, enqueuing callables on the application gives you no control over how many changes you make per frame. That's easier to handle by pulling items off of a queue... which could still be callables I suppose.
@pspeed said:
It's just that in this case, enqueuing callables on the application gives you no control over how many changes you make per frame. That's easier to handle by pulling items off of a queue... which could still be callables I suppose.

Yeah sure, I just meant you were "mutithreading" as you appeared three times in your post: In a quote, in the text and in an edit :D
@normen said:
Yeah sure, I just meant you were "mutithreading" as you appeared three times in your post: In a quote, in the text and in an edit :D


Next I'll figure out how to answer multiple threads at the same time. :)

@pspeed I might be misunderstanding your suggestion, but will immediately returning after an every add/remove do what you’re saying? Because doing this ensures that there will only be one add/remove per submit.

@seann999 said:
@pspeed I might be misunderstanding your suggestion, but will immediately returning after an every add/remove do what you're saying? Because doing this ensures that there will only be one add/remove per submit.


When you submit them, you can't control when they are executed. You are on a different thread and you still might queue up 50 of them before the next frame starts. You just can't know.

@pspeed Goddamnit! I think I’ve tried what you’ve said, I’m not fully sure yet, but can you tell me how you did it in Mythruna?