The call to executeNext() is important because that is where a synchronize block happens to pass reference geometry to the renderer, after all collision detection, animation, etc has happend. excecuteNext is a command pattern executer that determines which objects are invalid based on how often they wanted to be woke up. Each active entity can operate at upto 62 game frames per second (they get called back if it is time for them to work on their movement or their geometry...or whatever they do).

This is my main rendering method (not the loop..see below for that). The syncrhonzation block ensures that the engine can not pass a new reference to geometry (inside engine.world) while actual drawing is taking place.

Two things to note here are that the buffer swap is not within a synchronization block. This is safe because only the renderer writes to the context. By having it unsynchronized, the engine can start working on the next frame as soon as the renderer has finished the last gl call.

The other is the yield within this loop. If the renderer thread has already reached the refresh rate, it will not draw the next frame without yielding some cpu time to the engine or awt threads. There is no point as it only wastes cpu time wich would be better spent on preparing the data for the next frame.

That's the high lights. The engine thread runs at a constant 62 FPS and the renderer thread goes from worst case of 54 fps (with 28K geometry being rendered) upto 1800 fps when looking at nothing (I said 400 before... I found some bad code that was causing a chained recalc of bounding boxes down the SG path..big difference with it removed)

That code isn't really complicated. As you can see I can test to see if the engine thread is actually benefiting anything at all by simply calling executeNext() inside the main display() method. When I do, I get this:

(unknown engine FPS)Worse case scenario is now 42 FPS for renderer. So as it stands, the engine thread is gaining me 12 FPS under the most highest geometry conditions. 12 FPS is a pretty substantial gain to me because I am already well below the target FPS of 85 for the renderer thread.

As I add more geometry, this will get even worse. I willl balance it out by using a stripifier on the data and vertex lists were possible (some for static geometry now). So, if I double my geometry rendering speed with a stripifier, I will hit around 100 fps. Without the engine thread I would only be hitting around 84 (best case), and I wouldn't be able to add any more geometry. The AI is also going to get alot more complicated, but will have an almost unoticable effect on rendering FPS becuase it happens in the engine thread. With the performance gains from the threading I will be able to add approx, 15% more geometry to the worst case scenario and still achieve my desired FPS.

edit: I almost forgot the other point of relevance to this thread....the engine FPS is constant and seperate from the rendering, so all players of the game (despite hardware, or network if I add it) will have the same experience.

Again, your programs are just going to be outclassed Cas, when the average desktop computer is a multicore system.

Nah, what's going to happen is that AMD, Intel, etc are going to have to fund much much better threading API's that make it feasible to do rich custom scheduling hints or else see adoption of their processors by developers falter. There's far too many people around who are going to carry on just coding to a single thread (much as I wish it were otherwise) for a long time to come.

Isn't the state of play already that a lot of work goes into hardware and OS mechanisms to make single threaded programs run a little faster on MT processors? ISTR considerable effort from compiler writers (Intel, IBM) because the obvious problem that most coders won't change habits easily.

Isn't the state of play already that a lot of work goes into hardware and OS mechanisms to make single threaded programs run a little faster on MT processors?

You're not making much sense to me. The only "magic" in any current compilers is some auto-vectorization that Intel has been working on for quite some time. That has nothing to do with MT.

Quote

the obvious problem that most coders won't change habits easily.

For "most coders", MT isn't much of an issue, because they don't need MT or they're already using a framework that takes care of the big MT issues for them - like J2EE. The same thing is probably happening for gaming companies, where the big game engines take care of most of the MT design for you. The rest of us can get along just fine writing MT code ourselves.

Years ago, I wrote that crappy terrain demo to show off Java to various people, and it had a multithreading switch in it that took advantage of a second CPU. It took a reasonable amount of code to make it work correctly (properly correctly, not just "it happened to work on my machine"), and for a gain of just 10% in performance on a dual CPU machine.

However being a realist I find that the extra development time over the top of the single threaded baseline (and it's huge if you do it right) does not justify pandering to giving a 10% performance boost to the 1% of the market who currently have dual CPUs and will have for the next 5 years.

<edit>ISTR Carmack gave Q3 a multithreaded switch too, and he reported similar results.

Part of the problem there, though, is that he was multithreading multiple intel chips.

Intel chips are so bad at multi-processor work it's scandalous. Double the number of processors and you get +40% performance. Huh? Yeah...god-awful cheap-ass mobo design (no crossbar switch, each CPU has exclusive access to RAM, so they have to fight each other for access).

Would be worth trying again on an AMD multiprocessor mobo and seeing what difference it makes.

Then again... to what extent was that demo graphics card lmited or CPU lmited?

Years ago, I wrote that crappy terrain demo to show off Java to various people, and it had a multithreading switch in it that took advantage of a second CPU. It took a reasonable amount of code to make it work correctly (properly correctly, not just "it happened to work on my machine"), and for a gain of just 10% in performance on a dual CPU machine.

In C, threads are a pain in the arse (or were when I last used them with it...long ago), in C++ they are not to bad at all.... in Java they are so simple it would be hard for me to justify not using them. Especially if they can get me 10% better performance (or even 2%) while greatly simplifying timing issues wich will reduce the code complexity later. Since Java is starting of with a speed disadvantage when compared to C and C++, it's even harder to ignore.

Carmack was using C and multi-processor support was only for server IIRC.

If you can reliably confirm a minimum number of clock schedules that your threaded code will get per second to execute your AI, on Linux, Win32, MacOS X, on both 1.4 and 1.5, then you've sold the idea to me.

If you can reliably confirm a minimum number of clock schedules that your threaded code will get per second to execute your AI, on Linux, Win32, MacOS X, on both 1.4 and 1.5, then you've sold the idea to me.

But you can't, so you won't

Cas

You don't need guaranteed clock cycles, you only need a constant speed regardless of geometry, the code above will give you that.

Part of the problem there, though, is that he was multithreading multiple intel chips.

IMHO the really big problem is just desktop OSs.

Typical game usage of threads would be to schedule a percentage of CPU time to different, seperate task. But your regular OS just isn't designed for this kind of scheduling (in fact windows (and probably linux) don't really gurantee *anything* when it comes to threading and time allocated) and are far too unpredictable. Its perfectly possible for one thread to get 5 solid seconds of CPU and then switch to another for 5 seconds. As far as the OS is concerned thats a perfectly acceptable 50/50 split. As far as your game is concerned you've just rendered the same frame 300 times. Yay.

Threading for games only works if you've either:- Got really low priority background work that you really don't care how soon it gets done (level streaming)or- Got some kind of interupt handler so the OS actually wakes up your thread.

Anything else is just going to suck big time.

The 'solution' is either to get a real-time OS that can actually do reliable, predictable scheduling (like a non-pre-emptive one) or to manually time slice things in your app (like practically every game ever does).

I guess I just don't understand why people are having so many problems with threading in Java.

Are you guys setting priorities or something? Are you using Thread.sleep (<--- ABSOLUTE EVIL..can't stress this enough) instead of Thread.yield? Are you using synchronized calls instead of synchronized blocks? Are you using a lock object at all?

If you use yield and default priorities, and put timmers in both your threads, you will see they are actually getting almost identical amounts of CPU always.

To control which gets more, use yield like I have in the code above. The engine thread gets only what it needs, no more, no less. The renderer/awt/ thread and awt threads gets everything else. The engine stays at a constant (I stress CONSTANT) 62 FPS regardless of if the rendere is doing 1400 FPS of nothing or 70 FPS of 28K tris. When the renderer is doing 70FPS that means the engine is heavily working as well calculating geometry for it...yet it remains constant because it can do all it needs to do in less then 15 ms.

If you find one thread is getting CPU for 5 seconds then the other is getting it, then something is wrong with how you have implemented your threading, like an unreleased lock, or a dead loop with no yielding at all.

If you find one thread is getting CPU for 5 seconds then the other is getting it, then something is wrong with how you have implemented your threading, like an unreleased lock, or a dead loop with no yielding at all.

I didn't say I was actually getting this - but the point is that threading is totally unreliable in terms of scheduling (on PC). Its impossible to have a 100% smooth, 100% predictable game using threads for anything non-trivial.

Typical game usage of threads would be to schedule a percentage of CPU time to different, seperate task. But your regular OS just isn't designed for this kind of scheduling (in fact windows (and probably linux) don't really gurantee *anything* when it comes to threading and time allocated) and are far too unpredictable....The 'solution' is either to get a real-time OS that can actually do reliable, predictable scheduling (like a non-pre-emptive one) or to manually time slice things in your app (like practically every game ever does).

You don't need an RT OS, not by a long way.

There are well-known and actually mature (in their own way) OS's and threading libraries that support this kind of stuff, but the problem is they aren't mainstream. A lot of research OS's (some of which can be used as a workstation OS!) have this kind of thing. My favourite is/was Nemesis, aka Pegasus v3 (IIRC). It allowed you to do precisely what you say: ask for a percentage of CPU time. It also allowed you to state a minimum and a preferred, and it would give you something between the two, depending upon system load.

When I learnt that a JVM had been got to run on it, I momentarily considered using it as a real workstation OS. Unfortunately, the team at cambridge dumped development of it. I have no idea why - probably because they got bored, or some professor left to go somewhere else. Very sad. By removing the overhead of unnecessary thread switching / thrashing it was able to significantly increase performance. The classic example was that two spamming network servers under linux competed for I/O and CPU so erratically that Nemesis coudl achieve a 10% higher throughput simply by much much more precisely scheduling them - the graph of bandwidth usage for linux see-sawed between the two processes, each getting more then less time, whreeas for Nemesis it ran almost dead level for each.

NB: I belive the 10% gap has closed a lot since then, probably down to 1% or less, because of particular improvements I recall that have gone into the linux kernel.

Incidently, I don't think anyone here is saying that they have problems working with threads. We can all do it to one degree or another.. its just that it doesn't fit gaming (at least the sort of primitive crap game that I write) very well.

Intel is moving support for threading into theirs processors. You should prepare for that it would be preffered way of coding. I hope Java would be extended at least with as nice support as ada. I didn't checked the lastest additions to Java, so part of it could be here, just support from OS and CPUs is missing.Alas I believe there would be simillar delay as with SSE instrucitons.SSE2 from 1.4.2 server aww.AI could be improved with threads that are sheduled outside control of main program. Nice random data could be very nice for properly designed AI. Of course we are talking about smart AI and NP hard problems, like the assault problem.As for my current design, I'm completely uninterested if threads would be sheduled unpredictably, for some threads. The important thing is they should be sheduled at least once per half hour. This means at least partially run once per half hour. I designed it originaly targeted on the Earth simulator, so it's heavily multihreaded design.And of course higher priority thread are what theirs name suggests higher priority threads, get in do work get out don't fight between them too much. Yes it's true that windoze threading is very strange, and you must test, and possibly poslish the game for majority of OSs, or and write sheduler more robust.As for thread.sleep(xxx) It could be very nice to CPU. It cool down a little, and cooler could be more silent. There is also the isue with the laptop users, laptops have more balanced CPUs toward power savings, if you let them save some power. Of course MB integrated GFX cards are crap,I used thread.sleep(xxx) and then recalculated deltas. It used 1/5 of CPU power and looked very nice. Of course it was rather simple so not too much of a real application.

java-gaming.org is not responsible for the content posted by its members, including references to external websites,
and other references that may or may not have a relation with our primarily
gaming and game production oriented community.
inquiries and complaints can be sent via email to the info‑account of the
company managing the website of java‑gaming.org