multithreading on "normal" CPUs

hello,

i have a 3d game running with jogl. apparently jogl has it’s own thread, which tries to run as fast as possible.
and i have another thread that prepares ressources like textures for the main jogl thread. if the ressources are ready, the jogl thread can pick them up.
edit: what this ressource thread does, is mainly merging several texture-layers (bufferedimages) into one.

now all this works fine on CPUs that have some kind of multithreaded optimization like the Intel HyperThreading or Intel Dual Core CPUs.
but on normal, “single-threaded” CPUs the jogl-thread becomes extremely stuttery and slow whenever the ressource thread has something to do.

i believe the problem is, that both threads need almost 100% of the cpu and on these single-threaded CPUs that is not possible.

i am working on this problem now for almost a month and i am pretty sure i can rule out garbage collection and blocking (synchronized ressources) to be the cause for this.

now i guess my game is not the only one that does some extra work in another thread, so my question to you guys is, how do you handle this problem in your games, while keeping the main rendering thread at a constant frame rate?

thanks a lot!

Lower the resource-thread’s priority a bit and you should be fine.

Right now they have equal ‘rights’ to get cpu-cycles, but you want the rendering-thread to be dominant.

thanks riven,
i already tried that, but it does not really help. what happens is, that the renderloop is less often interrupted by the the ressource thread, but when it is interrupted, then the hiccups occur and they occur worse. also, ressources are prepared slower and might not be ready when they are needed.

the only thing that helps is, to do Thread.yield() in the ressource thread, then the hiccups dont block one frame for a long time but are evened out over about 5 to 10 frames. but this still is unacceptable for me.

it seems, the core of the problem is that this merging of bufferedimages is done by graphics2d.drawimage(), which seem to take up really a lot of CPU. so if i could go into this function and do Thread.yield() there a couple of times, might this solve the problem?

thanks!

Tiling/scaling images is not that hard. You can easily do it yourself (try to stay away from get/setRGB, work with the rasters directly - like IntDataBuffer).

Once you are in control, you can insert the yield() wherever you want.

thank you riven,
yes it is most definitely the setRGB function, since this is the one that takes up most of the CPU time according to the profiler.

i will look into that.

Use time-based movement for the graphics. Load resources between paints, don’t do it in the middle of the render - that’s what makes things look choppy, since the image is being delayed. By taking time out in between paints, that time will be taken into account by the timer being applied to the next update which should mean less choppyness.

You still can’t have the resources time take too long since the user will notice that frames go missing. If this is an issue & you can be bothered trying to fix it, then if you run the resources in another thread, (even though the rendering thread never actually executes at the same time) you can use thread.interrupt() to stop resources on their blocking file I/O, letting the rendering thread get on with its job.

thank you commanderkeith,

how can i determine the time, that is “in between paints”? (i am using jogl, btw)

the ressource blocking isnt because of the file IO, but because of the merging of bufferedimages, using drawImage()

My pleasure. System.nanoTime() (don’t use System.currentTimeMillis(), it gives resolution of about 35 ms on windows).

here is the time for my shameless plug. ;D
https://preciseinternaldate.dev.java.net/ is a project that aims to provide a quick replacement for System.currentTimeMillis(). It is millisecond precise even on windows. (no DLL involved, but 1.5 minimum)

But Java 1.5 has System.nanoTime() already, and it is (at least) precise to the millisecond on macs and near-nanosecond precision on windows? So long as you can remember that there are a million nanoseconds (10^9) in a second, its not much harder than System.currentTimeMillis(). Is your project a wrapper around System.nanoTime() or is there some other benefit?

Because nanosecond timer does not give you date (which can be important if that info is also used to tick other actions in game loop).
I agree of course that to just get elapsed time between two frames, nanotimer is fine.
That was mainly just to mention that there is a windows solution to currentTimeMillis(), sorry if it became a perturbance.

Oh, well… Errr, anyway, i said it was a shameless plug. :wink: ;D

That’s pretty useful then. I bet there’s a bug against the JDK about that, maybe you could get your code into it through Sun’s project peabody?!

Actually, that’s not a bug (if I know what you’re talking about).

The people at Sun decided that the nanosecond timer wouldn’t be from a set time - it would just be for time elapsed. If it were from a set time, it would eventually go beyond Long.MAX_VALUE and cause an Exception in every Java program. So not being able to get the date from the nanoseconds is a feature, not a bug.

If you’re talking about the millisecond timer not having millisecond accuracy in Windows, that’s not a bug in Java so much as it’s a problem with Windows. I think Windows XP has better accuracy, but I’m not sure. I just use the nanosecond timer anyways.

On Linux its pretty accurat … I use it often for small-scale profiling … if I am too lazy to fire up the slow netbeans profilier :wink:

I did propose a RFE based on a draft of the code of that project. It was reviewed (pretty rapidly, imho), but got rejected. (too rapidly, imho)
Of course, they were right to do so and the comments that were added to explain their decision were just as right.
I don’t know anyway if the way i did it is the right way for the platform, but i think that even as i did it it would help people that use the millisecond timer basically.
[edit] the project takes all the remarks of rejection in account and tries to solve them. Nevertheless, nothing’s perfect and even if the project is clean and problems are taken in account, it might not be fine for integration.