Java-Gaming.org    
Featured games (91)
games approved by the League of Dukes
Games in Showcase (580)
games submitted by our members
Games in WIP (500)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: 1 [2]
  ignore  |  Print  
  Render/Update Threads  (Read 6119 times)
0 Members and 1 Guest are viewing this topic.
Offline Vorax

Senior Member


Projects: 1


System shutting down in 5..4..3...


« Reply #30 - Posted 2005-01-10 20:52:24 »

If you are wondering how you can easily schedule time for AI, collision detection, animation etc.  with threads, here is a copy-paste from my games engine thread code.  

This is the main thread loop for the engine (not the renderer)

----------------
   while (!stopped && !this.isInterrupted()) {
     newTime = System.currentTimeMillis();

     // Integrate mouse and keybaord effects on player position
     engine.player_camera.update();

     // Update active entity AI
     updateEntityAI();

     // Execute geometry updates for next frame
     // (executeNext obtains geomety lock if renderer has finished buffer swap)
     executeNext();

     // Did we have left over time to give back to the renderer?
     // TODO: for J15, use nano
     long delta = newTime - System.currentTimeMillis();

     if (delta < desired_time) {
       // Give unused time back to renderer or awt threads
       while (System.currentTimeMillis() < newTime + (desired_time - delta)) {
         Thread.yield();
       }
     } else {
       // Renderer thread or other CPU process is starving us
       // (Share the CPU as best we can)
       Thread.yield();
     }

     // Figure out how long this all took
     // TODO: use nana for J15
     long elapsed = System.currentTimeMillis() - newTime;
     currentFPS = (int) (1000 / elapsed);

     // Target elapsed time should be 15 ms (aprx 62 FPS)
     // Adjust lagMultipler accordingly for the next
     // engine frame
     engine.setLagMultiplier(currentFPS / optimal_rate);
   }
------------

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.

-----------------------
 public void display(GLDrawable drawable) {
   if (!engine.engine_running)
     return;

   // Let the engine know we are about to draw a new frame.
   engine.newFrame();

   gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

   // Per frame things that are non-visual and non-thread dependent can be done within this call
   nonVisualPrep();

   // Prevent geometry from being updated while we are doing
   // the actual rendering
   synchronized (engine.frame_sync) {
     // Take ownership
     engine.setActiveThread(VoraxEngine.RENDERER);

     // Clear the draw later que every frame
     clearDrawLaterQue();

     // Need orientation help?
     if (VoraxEngine.DEBUG)
       drawGrid(gl);

     // apply the camera
     engine.player_camera.apply(gl);

     // Render the world
     engine.world.render(gl, matStack);

     // Draw items in the draw later que
     for (int i = 0; i < drawLaterQue.size(); i++) {
       ((GeoObject) drawLaterQue.elementAt(i)).drawObject(gl);
     }

     // Show fps?
     if (engine.show_fps)
       drawFPSText(gl);

     // Show engine fps?
     if (engine.show_fps)
       drawEngineFPSText(gl);

     // Geometry stats?
     if (engine.tris_stats)
       drawTrisCountText(gl);
   }
 }
-----------------------


This is the main loop that calls display() above:

   while (engine_running) {

     // Render...
     renderer.display(drawable);

     // swap the buffers
     drawable.swapBuffers();
     
     // Don't overdraw and waste CPU, give it to the
     // engine or awt threads
     if (gl_fps > config.refresh_rate  || engineThread.currentFPS < engineThread.optimal_refresh)
        Thread.yield();      
   }


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.

....are the advantages becoming clearer yet?

Offline blahblahblahh

JGO Coder


Medals: 1


http://t-machine.org


« Reply #31 - Posted 2005-01-10 20:55:28 »

Quote

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.

malloc will be first against the wall when the revolution comes...
Offline blahblahblahh

JGO Coder


Medals: 1


http://t-machine.org


« Reply #32 - Posted 2005-01-10 20:58:17 »

Quote
If you are wondering how you can easily schedule time for AI, collision detection, animation etc.  with threads, here is a copy-paste from my games engine thread code.  


Looks to me like co-routines. I suggest you grab a co-routine library and see if it would improve your code at all.

malloc will be first against the wall when the revolution comes...
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Vorax

Senior Member


Projects: 1


System shutting down in 5..4..3...


« Reply #33 - Posted 2005-01-10 21:07:59 »

Quote


Looks to me like co-routines. I suggest you grab a co-routine library and see if it would improve your code at all.


Ya, it's the same idea.  This is very lean and does only what I need, but if more threads get involved I might grab the library and adapt the code.

Offline rreyelts

Junior Member




There is nothing Nu under the sun


« Reply #34 - Posted 2005-01-10 21:39:11 »

Quote
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.

God bless,
-Toby Reyelts

About me: http://jroller.com/page/rreyelts
Jace - Easier JNI: http://jace.reyelts.com/jace
Retroweaver - Compile on JDK1.5, and deploy on 1.4: http://retroweaver.sf.net.
Offline Vorax

Senior Member


Projects: 1


System shutting down in 5..4..3...


« Reply #35 - Posted 2005-01-11 02:06:49 »

Well, I just did some more refinements and performance tuning on the engine and things look a little better for non-threaded mode.

I also modified the engine so it can run in threaded or non-threaded with a static final boolean setting (before I had to copy and paste some code into the rendering loop).

New engine with worst case scenerio:

Non-threaded Mode:
Renderer FPS: 65 (improved by 23 FPS)
Engine FPS (N/A)

Threaded Mode:
Renderer FPS: 70 (improved by 16 FPS)
Engine FPS: 62

That brings the non-threaded version to within 5 FPS of the threaded version (it was 12 slower).  Which is not bad.

That said...I still want the constant game engine rate of the threaded version, and of course, those 5 other FPS which will be more like 10 FPS once stripped.  

Having a constant engine rate makes everything much easier and predictable IMHO.

Either way, I am very happy with the performance gains.

Offline princec

JGO Kernel


Medals: 282
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #36 - Posted 2005-01-11 09:02:19 »

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.

Cas Smiley

Offline blahblahblahh

JGO Coder


Medals: 1


http://t-machine.org


« Reply #37 - Posted 2005-01-11 09:32:36 »

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?

malloc will be first against the wall when the revolution comes...
Offline Vorax

Senior Member


Projects: 1


System shutting down in 5..4..3...


« Reply #38 - Posted 2005-01-11 10:44:49 »

Quote
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.

Offline princec

JGO Kernel


Medals: 282
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #39 - Posted 2005-01-11 10:53:56 »

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 Smiley

Cas Smiley

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Vorax

Senior Member


Projects: 1


System shutting down in 5..4..3...


« Reply #40 - Posted 2005-01-11 11:23:17 »

Quote
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 Smiley

Cas Smiley


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

Offline Orangy Tang

JGO Kernel


Medals: 51
Projects: 11


Monkey for a head


« Reply #41 - Posted 2005-01-11 11:33:36 »

Quote
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).

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline Vorax

Senior Member


Projects: 1


System shutting down in 5..4..3...


« Reply #42 - Posted 2005-01-11 11:48:38 »

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.

Offline Orangy Tang

JGO Kernel


Medals: 51
Projects: 11


Monkey for a head


« Reply #43 - Posted 2005-01-11 11:59:16 »

Quote

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.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline blahblahblahh

JGO Coder


Medals: 1


http://t-machine.org


« Reply #44 - Posted 2005-01-11 12:38:37 »

Quote

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.
...
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.

malloc will be first against the wall when the revolution comes...
Offline Orangy Tang

JGO Kernel


Medals: 51
Projects: 11


Monkey for a head


« Reply #45 - Posted 2005-01-11 12:53:44 »

Quote


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.

Well maybe you don't need a full RT OS, but what I'm saying is that native threading for windows etc. just doesn't cut it.

Whether you get around this by using a RT OS or an external threading lib is basically doing the same thing.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline kevglass

JGO Kernel


Medals: 85
Projects: 25


Coder, Trainee Pixel Artist, Game Reviewer


« Reply #46 - Posted 2005-01-11 13:17:12 »

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.

Kev

Offline Raghar

Junior Member




Ue ni taete 'ru hitomi ni kono mi wa dou utsuru


« Reply #47 - Posted 2005-01-13 20:57:56 »

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.
Pages: 1 [2]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

xsi3rr4x (50 views)
2014-04-15 18:08:23

BurntPizza (46 views)
2014-04-15 03:46:01

UprightPath (62 views)
2014-04-14 17:39:50

UprightPath (44 views)
2014-04-14 17:35:47

Porlus (60 views)
2014-04-14 15:48:38

tom_mai78101 (84 views)
2014-04-10 04:04:31

BurntPizza (142 views)
2014-04-08 23:06:04

tom_mai78101 (242 views)
2014-04-05 13:34:39

trollwarrior1 (201 views)
2014-04-04 12:06:45

CJLetsGame (208 views)
2014-04-01 02:16:10
List of Learning Resources
by SHC
2014-04-18 03:17:39

List of Learning Resources
by Longarmx
2014-04-08 03:14:44

Good Examples
by matheus23
2014-04-05 13:51:37

Good Examples
by Grunnt
2014-04-03 15:48:46

Good Examples
by Grunnt
2014-04-03 15:48:37

Good Examples
by matheus23
2014-04-01 18:40:51

Good Examples
by matheus23
2014-04-01 18:40:34

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:22:30
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
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!