Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (513)
Games in Android Showcase (121)
games submitted by our members
Games in WIP (577)
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  
  GC Lag Question  (Read 11237 times)
0 Members and 1 Guest are viewing this topic.
Offline CommanderKeith
« Posted 2006-04-27 14:09:31 »

Hi,

In my experience the garbage collector is the most painful problem when making good games since it kills percieved performance when a full GC kicks in and adds a delay between the updating of the game world and its display on the screen.  So what is the best way to handle game objects like bullets to minimise full GC's but keep design object-oriented?

Bullets can hang around in the game world for any length of time, often so long that they are promoted out of GC-eden space and into the long-lived space.  So what should be done with them to reduce full GC's?  I see a couple of alternatives, and I rank them in order of preference:

1. Object pooling - recycle old bullets by having factory methods to 'create' new ones.
2. Adjusting the eden space proportion (I don't know how, I just read that it can be done)
3. depart from OO design and have a static Bullet class that has arrays of primitives that represent all bullets' primitives

So how have you handled these problems or is GC lag just accepted?

Keith

PS:  I am using time-based updating and I know that GC lag is fine if it happens after showing the game world but before updating takes place, however it cannot be compensated for in the frame about to be displayed when it delays that frame's rendering >> leads to a percieved lag.

Offline Riven
« League of Dukes »

JGO Overlord


Medals: 818
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #1 - Posted 2006-04-27 14:25:12 »

You must be shooting zillions of bullets then. Or really 'heavy' bullets for that matter. Both are unlikely, and besides that, bullets are pretty short-lived (unless you keep them laying in the world). Do you really think many MBs of bullet-data are residing on the heap? (literally 100.000s of bullets)

I can't help but think something else in your code is creating a lot of garbage. If you stop shooting bullets and the lag vanishes, you should inspect the code that is creating those bullets, not the bullets themselves, maybe it can be optimized.

If all else fails, sacrify design for performance and either pool (least bad design) or create a big array of bullets (enabled/disabled) which would be the worst design, but probably fastest.

Keep in mind that enlarging the eden-heap will also increase non-full GC times.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline princec

JGO Kernel


Medals: 409
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #2 - Posted 2006-04-27 14:31:30 »

See Titan Attacks and Ultratron. Do you see any GC lag?

Cas Smiley

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline CommanderKeith
« Reply #3 - Posted 2006-04-27 14:57:45 »

I can't help but think something else in your code is creating a lot of garbage.

You're probably right, but sometimes I create 300+ bullets per frame (at 60fps) and they have lots of fields (21, mostly floats and other objects).  hmmmm.... but I suppose that not a zillion  Smiley....

When you guys have GC problems how do you find out the cause?  I've done a heap profile in netbeans but it told me that Java2D was creating most of the garbage, but that garbage can't have been promoted out of the eden.

How can you tell what is causing the GC lags?  I have a 1% GC-tick count as it is (unnacceptable) and it can get up to 4%.

I definitley want to learn more about java heap memory usage and the GC but it took me ages just to find out what -verbosegc output actually tells you on windows.

Offline swpalmer

JGO Coder


Exp: 12 years


Where's the Kaboom?


« Reply #4 - Posted 2006-04-28 03:16:49 »

Have you read this http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html ?

In particular, try the concurrent low-pause collector.. with incremental mode and automatic 'pacing'

http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html#5.4.9.1

Offline CommanderKeith
« Reply #5 - Posted 2006-04-28 08:48:45 »

Thanks for that, its mitigated the problem.  I tried the parallel GC before but not with those fancy add-ons. 

It was funny though, the prescribed options have a typo:

-XX:+UseConcMarkSweepGC
-XX:+CMSIncrementalMode
-XX:+CMSIncrementalPacing
-XX:CMSIncrementalDutyCycleMin=0
-XX:+CMSIncrementalDutyCycle=10                                   this one doesn't work with the '+'.
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:-TraceClassUnloading

Keith

Offline emzic

Senior Duke





« Reply #6 - Posted 2006-05-02 14:55:10 »

See Titan Attacks and Ultratron. Do you see any GC lag?

no lags there, but these guys seem to use lwjgl and not jogl.

btw: great games!

www.embege.com - personal website
webstart blendinspect - OpenGL BlendingModes visualization.
Offline princec

JGO Kernel


Medals: 409
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #7 - Posted 2006-05-02 17:04:45 »

I shouldn't think LWJGL or JOGL are any different in terms of GC activity...

For comparison have a look at Alien Flux: I used extensive particle pooling trickery and pools for enemy bullets and lasers, figuring I'd be generating hundreds of these kinds of things all the time. And in truth it is fractionally smoother than Ultratron/Titan but you have to be very, very sharp to spot it, and the code complexity is huge compared to just creating new Particle()s and forgetting about them when they're done which is what I switched to in the minigames.

Anyway: the gist of it is, GC lag is very unlikely to actually be GC lag, it's probably something else, and even if it's not, it can be tuned.

Cas Smiley

Offline Jeff

JGO Coder




Got any cats?


« Reply #8 - Posted 2006-05-02 22:06:05 »

One common cause of apparent GC errors is filling the heap with an object leak that causes it to be *constantly* GCing whats left.

Have you run a profiler and  looked at your actual heap?

Got a question about Java and game programming?  Just new to the Java Game Development Community?  Try my FAQ.  Its likely you'll learn something!

http://wiki.java.net/bin/view/Games/JeffFAQ
Offline CommanderKeith
« Reply #9 - Posted 2006-05-03 05:49:40 »

> One common cause of apparent GC errors is filling the heap with an object leak that causes it to be *constantly* GCing whats left.

No it's not that, the heap stays small (< 30M).

Maybe the GC tick-count is just a combination of many long-lived bullets and Java2D rendering garbage. 

Just out of interest, why can't Sun add some methods to manipulate when the GC does its work?  After all, the GC is just a thread.

System.gc() exists but that suggests to the VM to do a full gc, which it seems to actually do every time it's called whether it's neded or not (and it takes ages).  A method like System.edenGC() to prompt the VM to do a young generation GC (if necessary) would be great.

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

Junior Duke




Nothing unreal exists


« Reply #10 - Posted 2006-05-03 07:57:28 »

I'm with CAS on that one.
"Life fast, die young" should be the motto of your objects. The JVM is much more capable in pooling objects than you will ever be so don't waste time even thinking about it.

Home page: http://frederic.barachant.com
------------------------------------------------------
GoSub: java2D gamechmark http://frederic.barachant.com/GoSub/GoSub.jnlp
Offline swpalmer

JGO Coder


Exp: 12 years


Where's the Kaboom?


« Reply #11 - Posted 2006-05-03 12:34:58 »

Just out of interest, why can't Sun add some methods to manipulate when the GC does its work?  After all, the GC is just a thread.

System.gc() exists but that suggests to the VM to do a full gc, which it seems to actually do every time it's called whether it's neded or not (and it takes ages).  A method like System.edenGC() to prompt the VM to do a young generation GC (if necessary) would be great.

Have you profiled the GC?  The Eden GC doesn't take enough time to matter.
There is really no point in continuing the conversation if you haven't got the actual stats to show what the GC is really doing and when.  Without that info you are just shooting in the dark.
Have you used the -XX:+PrintGCDetails (or whatever it is) switch?

Start here:
http://java.sun.com/docs/hotspot/index.html

Offline Jeff

JGO Coder




Got any cats?


« Reply #12 - Posted 2006-05-03 23:07:07 »

So the answer to "why aren't there more GC controls in the API" is that a decision was made early on to leave the GC implementors maximum room for different implementations of GCs.

The eden, for instance, is a very specific part of a very specific implementation.

Had we tied the GC to an APi that exposed how it works then you'ld be stuck today with the first one we had (the mark/sweep collector.)

Frankly, even exposing System.gc(), with what VERY limited gauranatees it makes,  has basically proved to be a mistake as  the results of calling it vary greatly between GC implementations and programs that depend on it to do anything in particular lose portability.

Got a question about Java and game programming?  Just new to the Java Game Development Community?  Try my FAQ.  Its likely you'll learn something!

http://wiki.java.net/bin/view/Games/JeffFAQ
Offline princec

JGO Kernel


Medals: 409
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #13 - Posted 2006-05-03 23:24:47 »

It would, nonetheless, be probably a boon to programmatically tune the GC from within an application. At the very least it would be exceedingly useful to be able to set -Xmx and -Xms dynamically at runtime.

Cas Smiley

Offline zingbat

Senior Duke




Java games rock!


« Reply #14 - Posted 2006-05-05 02:02:24 »

Just out of interest, why can't Sun add some methods to manipulate when the GC does its work?  After all, the GC is just a thread.

System.gc() exists but that suggests to the VM to do a full gc, which it seems to actually do every time it's called whether it's neded or not (and it takes ages).  A method like System.edenGC() to prompt the VM to do a young generation GC (if necessary) would be great.

Have you profiled the GC?  The Eden GC doesn't take enough time to matter.
There is really no point in continuing the conversation if you haven't got the actual stats to show what the GC is really doing and when.  Without that info you are just shooting in the dark.
Have you used the -XX:+PrintGCDetails (or whatever it is) switch?

Start here:
http://java.sun.com/docs/hotspot/index.html

Maybe this will help with CK argument. I have modified ny little sprite rotation benchmark. Now it takes into account the extra time wasted by sleep and logging and discounts that time in the next cycle. I have also removed all System.out.printlnS and im using an array to log data instead. The output is like this:

<update time>  <drawing time>  <fill time to next frame>  <latency time>  <recovery time>

Im using a frame of 0.002 milliseconds and if recovery time is bigger than this the frame will be skipped.

Im also using these arguments:

-XX:+UseConcMarkSweepGC  -XX:+CMSIncrementalMode  -XX:+CMSIncrementalPacing  -XX:CMSIncrementalDutyCycleMin=0
-XX:CMSIncrementalDutyCycle=10 -verbose:gc -Dsun.java2d.opengl=true

But didn't notice much difference.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
[GC 1944K(16320K), 0.0032607 secs]
[GC 2023K(16320K), 0.0107422 secs]
0.000001601    0.000399223    0.002916319    0.001322865    0.001322865
0.000003711    0.001932507    0.000000000    0.000000000    0.001277139
...
0.000001113    0.000311164    0.001685209    0.000001868    0.000001868
0.000001075    0.000341113    0.001654918    0.000001973    0.000001973
[ParNew 4082K->1119K(16320K), 0.0142923 secs]
0.000000828    0.000317662    0.001678342    0.000001593    0.000001593
0.000000811    0.000305137    0.001691493    0.000001820    0.000001820
...
0.000001278    0.000315372    0.001680717    0.000001825    0.000001825
0.000000931    0.000308691    0.001687813    0.000001891    0.000001891
[GC 2941K(16320K), 0.0037765 secs]
0.000001058    0.000301988    0.001694364    0.000001819    0.000001819
0.000000905    0.000301778    0.001694927    0.000001945    0.000001945
...
0.000000913    0.000306197    0.001690615    0.000001895    0.000001895
0.000000983    0.000532326    0.001465397    0.000003360    0.000003360
[ParNew 5087K->1119K(16320K), 0.0014446 secs]
0.000001531    0.000507845    0.001483932    0.000002016    0.000002016
0.000001368    0.000347703    0.001647204    0.000001417    0.000001417
...
0.000001137    0.001043897    0.000952418    0.000001829    0.000001829
0.000000838    0.005141818    0.000000000    0.000000000    0.003145566
*skip*
0.000001326    0.000000675    0.000000000    0.000000000    0.001149968
0.000000638    0.001004171    0.000000000    0.000000000    0.000155542
0.000000845    0.003107058    0.000000000    0.000000000    0.001265168
0.000001378    0.001169552    0.000000000    0.000000000    0.000437526
0.000001116    0.001032476    0.000529242    0.000002045    0.000002045
0.000001196    0.007081311    0.000000000    0.000000000    0.005086058
*skip*
0.000001396    0.000000653    0.000000000    0.000000000    0.003090326
*skip*
0.000000625    0.000000648    0.000000000    0.000000000    0.001092314
0.000000638    0.002204311    0.000000000    0.000000000    0.001297968
0.000001341    0.011736162    0.000000000    0.000000000    0.011036995
*skip*
0.000002246    0.000001111    0.000000000    0.000000000    0.009042558
*skip*
0.000000633    0.000000620    0.000000000    0.000000000    0.007044587
*skip*
0.000000628    0.000000615    0.000000000    0.000000000    0.005046540
*skip*
0.000000631    0.000000613    0.000000000    0.000000000    0.003048524
*skip*
0.000000626    0.000000612    0.000000000    0.000000000    0.001050502
0.000000631    0.001758613    0.000000000    0.000000000    0.000810491
...
0.000001151    0.000354055    0.001644016    0.000002201    0.000002201
0.000001553    0.000408814    0.001587720    0.000001886    0.000001886
[ParNew 5087K->1120K(16320K), 0.0011402 secs]
0.000000956    0.000299241    0.001698633    0.000001689    0.000001689
0.000000710    0.000268572    0.001729585    0.000001676    0.000001676
...
0.000000710    0.000254531    0.001771521    0.000029520    0.000029520
0.000001108    0.000316977    0.001652275    0.000001916    0.000001916
[ParNew 5088K->1121K(16320K), 0.0015111 secs]
0.000000835    0.000261114    0.001737151    0.000001967    0.000001967
0.000000698    0.000291981    0.001705902    0.000001509    0.000001509
...


It looks like GC usualy takes a very short time in the order of 1 millisecond to do his job and i suspect that with lwjgl and jogl this would be much better.

There is however the ocasional situation where, without any reasonable explanation gc takes an absurd amount of time. Look at the second gc output above. Or when java2d is performance so well rendering frames in less than a millisecond and sudenly it starts chooking. But that only happened once in that group of skips in the example above.

Anyway i think java2d performs quite well but lwjgl/jogl probably performs a lot better and gc won't be a problem in there. I think the ocasional hickups we will notice in very rare ocasions are more because of the way java2d works internaly than because of gc.


Offline Linuxhippy

Senior Duke


Medals: 1


Java games rock!


« Reply #15 - Posted 2006-05-05 05:54:34 »

And whats your/the conclusion?
Sorry if I am a bit harsh, but I wonder about the sence of this discussion Wink

lg Clemens
Offline pepe

Junior Duke




Nothing unreal exists


« Reply #16 - Posted 2006-05-05 07:28:34 »

And whats your/the conclusion?
Sorry if I am a bit harsh, but I wonder about the sence of this discussion Wink

lg Clemens
That's exactly what i thought... not being able to render 1000fps flawlessly is out of reality.
Being able to have a 60fps game that does not stutter is a goal that can be achieved easily now, and imho that's enough for most of us.
Moreover, with the generalization to come of multi-core processors, asynchronous GC will be more and more imperceptible.
Even i, who does applications that have very precise and short timings to comply to when displaying images is not bothered (that much) by GC.

Of course, having smaller/sliced full GCs would complete the set, as nothing would stop renders anymore, but i think we can already be pretty happy with what we have since 1.4.

Home page: http://frederic.barachant.com
------------------------------------------------------
GoSub: java2D gamechmark http://frederic.barachant.com/GoSub/GoSub.jnlp
Offline CommanderKeith
« Reply #17 - Posted 2006-05-05 09:16:34 »

Thanks for everybody's interest & help.

>Have you profiled the GC?  The Eden GC doesn't take enough time to matter.

Yes, Eden GC's are quick but even on my 2GHz machine -verbosegc shows they take 0.0005 seconds (1/2 a millisecond).  There is no question that this is noticeable when it delays a frame getting to the screen (zingbat's 1 millisecond lag would be very noticeable).  It would not be an issue if the eden GC could be told when to work so that its lag could be adjusted for.  In my opinion this is a rock-bottom basic thing that java should have. 

And Jeff, more efficient GC's are not what is needed -> predictable GC's are the answer and I'm sure some VM vendor will realise this soon.  Also, multi-core processors won't necessarily solve the problem since the GC thread could still be scheduled on the core running the rendering.

Offline Riven
« League of Dukes »

JGO Overlord


Medals: 818
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #18 - Posted 2006-05-05 09:40:37 »

Noticing 0.5ms, and a 1.0ms delay would be very noticable?

Do you realize that even 10ms result in 100fps. Even if that would cause a frame-miss, you'd still be rendering at 50fps.

My only worries are about 50+ ms GCs, only those will decrease perceived performance in a game.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline CommanderKeith
« Reply #19 - Posted 2006-05-05 13:50:17 »

I admit that 1/2 a millisecond is hard to spot.  This tests what lags are noticeable.  It replicates GC lags every 3/4 second, delaying the current frame from being displayed and beeps when it does this:


import java.awt.*;
import javax.swing.*;
import java.awt.image.*;
import java.awt.geom.*;

public class LagTest extends JPanel{


   float gcLagInMillis = 5;


   long lastRenderNanos = 0;
   float counterMillis = 0;
   float speed = 0.08f;      // pixels per millisecond
   float xPos = 0;

   public LagTest(){
      lastRenderNanos = System.nanoTime();
   }
   public void render(Graphics2D g2D){
      g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
      long currentNanos = System.nanoTime();
      int nanosElapsed = (int)(currentNanos - lastRenderNanos);
      float millisElapsed = (float)(nanosElapsed/1000000f);
      counterMillis += millisElapsed;
      xPos += speed*millisElapsed;
      if (xPos > getWidth()){
         System.exit(0);
      }
      g2D.setColor(Color.white);
      g2D.fillRect(0, 0, getWidth(), getHeight());
      g2D.setColor(Color.black);
      g2D.setStroke(new BasicStroke(3));
      g2D.drawLine(Math.round(xPos), Math.round(getHeight()/2),
               Math.round(xPos)+10, Math.round(getHeight()/2));
      lastRenderNanos = currentNanos;

      //replicate GC lag every 3/4 second
      if (gcLagInMillis != 0){
         if (counterMillis > 750){
            Toolkit.getDefaultToolkit().beep();
            long nanos = System.nanoTime();
            while(true){
               float millisWaited = (float)((System.nanoTime() - nanos)/1000000f);
               if (millisWaited > gcLagInMillis){
                  counterMillis = 0;
                  break;
               }
            }
         }
      }
   }


   public static void main(String[] arghhImAPirate){
      JFrame frame = new JFrame("LagTest");

      frame.setIgnoreRepaint(true);

        frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

      final LagTest lagTest = new LagTest();
        frame.setContentPane(lagTest);

      frame.setVisible(true);

      frame.createBufferStrategy(2);
      final BufferStrategy strategy = frame.getBufferStrategy();


      Thread thread = new Thread(new Runnable(){
         public void run(){
            while (true){
               Graphics2D g2D = (Graphics2D)strategy.getDrawGraphics();
               lagTest.render(g2D);
               strategy.show();
               g2D.dispose();
               try{
                  Thread.sleep(5);
               }catch(InterruptedException e){
               }
            }
         }
      });
      thread.start();
   }

}


EDIT:
change the Thread.sleep(5); call to something bigger like 40 milliseconds and see what a big difference this makes to how noticeable the lag is.  This might show that gc lag is worse when the frame rate is low.  That must be because the delayed frame hangs around for longer and the eye picks up on it.  Unfortunately the lower the frame rate, the more Java2D rendering that is probably being done, and the more garbage that is being created!

Offline abies

Senior Duke





« Reply #20 - Posted 2006-05-05 13:56:06 »

Noticing 0.5ms, and a 1.0ms delay would be very noticable?

Do you realize that even 10ms result in 100fps. Even if that would cause a frame-miss, you'd still be rendering at 50fps.

My only worries are about 50+ ms GCs, only those will decrease perceived performance in a game.

Well, 1ms is certainly not important, but 50ms is probably way too obvious. Problem is not running at constant 50fps - this is probably good enough. Problem is with running at 100fps and suddenly missing 2-3 frames in row and then again running with full speed for some seconds. You can easily spot such stutter, because of the sudden change in behaviour. I would even risk saying than having 20fps constant is a lot better than having 100fps with 20-50ms breaks once per second. Of course, gc is not only thing which can cause some delays - in many games, loading the textures to GPU for a new objects can also cause stuttering, even for a longer period of time.

That said, we are running in 10 second pauses on 8 cpu machine with concurrent gc.... and we are allocating modest 2-3MB of memory per second, most of it never leaving the eden space (less than 1MB promoted to old generation every 10 seconds) with total heap size of 1-1.5GB. Fortunately it is not an interactive game...

Artur Biesiadowski
Offline pepe

Junior Duke




Nothing unreal exists


« Reply #21 - Posted 2006-05-05 15:00:32 »

.../...
That said, we are running in 10 second pauses on 8 cpu machine with concurrent gc.... and we are allocating modest 2-3MB of memory per second, most of it never leaving the eden space (less than 1MB promoted to old generation every 10 seconds) with total heap size of 1-1.5GB. Fortunately it is not an interactive game...
Shocked
Do you mean that you are having 10 second long pauses due to collection of eden?
[edit] did you tune the eden, or things like that? what is the occurency of the pauses?

Home page: http://frederic.barachant.com
------------------------------------------------------
GoSub: java2D gamechmark http://frederic.barachant.com/GoSub/GoSub.jnlp
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 818
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #22 - Posted 2006-05-05 15:34:33 »

Although a 8-cpu system should have more than 1.0-1.5 GB, did you take swapping into account? a GC over a swapped heap part is dead-slow.

I can't think of anothre reason that would cause these slowdowns.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline abies

Senior Duke





« Reply #23 - Posted 2006-05-05 17:43:43 »

10 second pauses during rescan phase of old generation (one of the few blocking phases of CMS). New generation pauses are generally around 100ms.
We have 16GB RAM, with many processes running, but we always have around 3GB free physical RAM on top of all them.

Few explanations why it can take so long:
We are running on 8x1200MHz Sparc. Every of these CPUs is probably a lot slower than current x86 based CPUs, especially if you take memory access into account.
We have to disable parallelism in rescan phase, as using parallel GC together with CMS is resulting in jvm crash in few hours for us (both on windows and on solaris). We are using 5.0_06, I have reported this problem to Sun, unfortunately they are not able to solve it without small, easily reproductible case.

Unfortunately, there is almost no relation between number of dirty cards during rescan and duration of pause. We sometimes get under-1s CMS pause with 30k dirty pages, and 10s pauses with 9k dirty pages.

I hope that this problem is caused by http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6367204, which is supposed to be fix in 5.0_07. Anyway, currently we are not even close to being realtime on 8 CPU machine with a lot of free memory and 20% total load on average.

Artur Biesiadowski
Offline Jeff

JGO Coder




Got any cats?


« Reply #24 - Posted 2006-05-06 01:02:13 »

. Problem is with running at 100fps and suddenly missing 2-3 frames in row and then again running with full speed for some seconds. You can easily spot such stutter, because of the sudden change in behaviour.

Im not sure I follow this, if your moving the object in a time-based rather then frame based motion unless the variation is *very* large I wouldnt imagine it would be noticeable.  After all, flicer rate for the human eye is only about 50hz as I recall.

Quote
That said, we are running in 10 second pauses on 8 cpu machine with concurrent gc....

Wow.  I find that amazing.  How big is your long-lived heap?  If you make you long lived heap huge it means fewer but bigger pauses collecting it.

 

Got a question about Java and game programming?  Just new to the Java Game Development Community?  Try my FAQ.  Its likely you'll learn something!

http://wiki.java.net/bin/view/Games/JeffFAQ
Offline abies

Senior Duke





« Reply #25 - Posted 2006-05-06 10:34:22 »

Im not sure I follow this, if your moving the object in a time-based rather then frame based motion unless the variation is *very* large I wouldnt imagine it would be noticeable.  After all, flicer rate for the human eye is only about 50hz as I recall.

Yes, but 3 missed frames means same image displayed for 40ms (25Hz). if you have full screen moving (like turning around in FPS game) this will be extremly noticeable.
I think that LagTest posted below is quite nice test.

Quote
Quote
That said, we are running in 10 second pauses on 8 cpu machine with concurrent gc....
Wow.  I find that amazing.  How big is your long-lived heap?  If you make you long lived heap huge it means fewer but bigger pauses collecting it.
 

Around 1GB of used old heap (from 2.5GB of Xmx). We are running CMS in incremental mode, so it is running by itself every 5-10 minutes - without that, if it was running every 1 hour or so when memory was closing to a limit, we were running into minute long pauses.

Artur Biesiadowski
Offline zingbat

Senior Duke




Java games rock!


« Reply #26 - Posted 2006-05-06 12:57:12 »

I made more tests with several sprites instead of just one rotating at the center. Here's the results:

1  
2  
3  
4  
5  
6  
7  
8  
reqfps    numit     numsp     avgdraw      max       avggc    numgc
200       200       1         0.0003       0.026     0.01     1
200       200       10        0.0007       0.034     0.06     1
200       200       50        0.0015       0.036     0.014    1
100       200       100       0.003        0.041     0.014    1
50        200       200       0.005        0.031     0.012    1
50        200       400       0.02         0.07      0.017    3
20        200       1000      0.03         0.108     0.013    6


The legend:

reqfps=required fps
numit=number of iterations
numsp=number of sprites
avgdraw=average drawing time
max=maximum drawing time
avggc=average gc time
numgc=numbered of  Par gcs during demo


Being able to draw 400 sprites at 50 fps and 1000 at 20 fps almost concistently is great. I also have a good machine.

I say almost concistently because of the ocasional java hickup. Like CK said concistency is very important. It doesn't mater if this only hapens every 5 minutes. If its visible and i think a pause of 0.026 is visible, people will say the game is unstable and badly coded.

If my data is correct and i didn't made any mistake the problem isn't from gc which is very stable but from the java2d api itself and the way it caches it's resources.
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 818
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #27 - Posted 2006-05-06 16:21:19 »

Is the rotation time-based or frame-based?

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline zingbat

Senior Duke




Java games rock!


« Reply #28 - Posted 2006-05-06 19:35:03 »

Is the rotation time-based or frame-based?

There  is a fixed angle increment per update. I have not changed this angle increment when i changed the target fps for the heavier tests so it gets a bit slower with lower fps values. But it could be easly made time based by using angular velocity instead of a fixed angle value.
Offline zingbat

Senior Duke




Java games rock!


« Reply #29 - Posted 2006-05-06 19:41:24 »

Heres the code:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
package game2d.tests;

import game2d.imp.java2d.Java2DGameCanvas;
import game2d.imp.java2d.Java2DSpriteFactory;
import game2d.imp.java2d.Java2DSprite;
import game2d.util.FastLogger;
import game2d.util.Timer;

import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;


public class Java2DSpriteDrawTest2 {
   
   public static void main(String[] args) {
      new Java2DSpriteDrawTest2();
   }
   
   private Java2DSprite sprite;
   private JFrame frame;
   private Java2DGameCanvas canvas;
   private Java2DSpriteFactory factory;
   private int w;
   private int h;
   private int sw;
   private int sh;
   private Graphics2D gc;
   private FastLogger fastlog = new FastLogger();
   private Timer timer = Timer.getSingleton();
   private int[] spw;
   private int[] sph;
   private int numsp;
   private int numit;
   private double framedur;
   
   public Java2DSpriteDrawTest2() {
      canvas = new Java2DGameCanvas(800,600);
      w = canvas.getWidth();
      h = canvas.getHeight();
      frame = Java2DGameCanvas.createFrame("",canvas,null);
      factory = Java2DSpriteFactory.getSingleton();
      frame.pack();
      frame.setVisible(true);
      sprite = Java2DSpriteFactory.getSingleton().getSprite("sprites/pleg.png");
      sw = sprite.getWidth();
      sh = sprite.getHeight();
      start();
   }
   
   private void waitSeconds(double period) {
      double t0 = timer.getTime();
      double tm = t0;
      for (; tm - t0 < period; tm = timer.getTime()) ;
   }
   
   public void start() {
      numit = 200;
      numsp = 1000;
      framedur = 0.05;
      // init sprites
      spw = new int[numsp];
      sph = new int[numsp];
      for (int i=0; i < numsp; i++) {
         spw[i] = (int) (Math.random() * w);
         if (spw[i] < 128) spw[i] = 128;
         if (spw[i] > w - 128) spw[i] = w - 128;
         sph[i] = (int) (Math.random() * h);
         if (sph[i] < 128) sph[i] = 128;
         if (sph[i] > w - 128) sph[i] = w - 128;
      }
      // statistics
      double requestedFrame = framedur;
      double beforeUpdate;
      double updatePeriod = 0.0;
      double beforePresentation = 0.0;
      double presentationPeriod = 0.0;
      double beforeFilling = 0.0;
      double fillPeriod = 0.0;
      double latency = 0.0;
      double timeLeft = 0.0;
      double recoveryPeriod = 0.0;
      boolean skip = false;
      double beforeLogging;
      double loggingPeriod = 0.0;
      for (int i=0; i < numit; i++) {
         timeLeft = requestedFrame - recoveryPeriod;
         beforeUpdate = timer.getTime();
         update(); // allways update
         updatePeriod = timer.getTime() - beforeUpdate;
         timeLeft -= updatePeriod;
         // only draw if there is possibly time for it
         beforePresentation = timer.getTime();
         if (timeLeft >= 0) {
            skip = false;
            draw();
         } else {
            // tell fastlog a frame was skiped
            skip = true;
         }
         presentationPeriod = timer.getTime() - beforePresentation;
         timeLeft -= presentationPeriod;
         // fill any remaining time if there is some
         // computer recovery period
         latency = 0.0;
         fillPeriod = 0.0;
         if (timeLeft >= 0) {
            beforeFilling = timer.getTime();
            waitSeconds(timeLeft);
            fillPeriod = timer.getTime() - beforeFilling;
            latency = fillPeriod - timeLeft;
            recoveryPeriod = latency;
         } else {
            // frame toke too much time to draw
            recoveryPeriod = -timeLeft;
         }
         beforeLogging = timer.getTime();
         fastlog.push(skip, updatePeriod, presentationPeriod,
               fillPeriod, latency, recoveryPeriod);
         loggingPeriod = timer.getTime() - beforeLogging;
         recoveryPeriod += loggingPeriod;
      }
      fastlog.print(System.out);
   }
   
   private double rot = 0.0;
   
   public void update() {
      rot += Math.PI/48.0;
   }
   
   private AffineTransform identity = new AffineTransform();
   public void draw() {
      gc = canvas.getDrawGraphics();
      gc.setColor(Color.black);
      gc.fillRect(0,0,w,h);
      for (int i=0; i < numsp; i++) {
         gc.setTransform(identity);
         gc.translate(spw[i]-sw,sph[i]-sh);
         gc.rotate(rot,sw/2.0,sh/2.0);
         gc.drawImage(sprite.getImage(), 0, 0, null);
      }
      gc.dispose();
      canvas.flip();
   }
   
}

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.

theagentd (21 views)
2014-10-25 15:46:29

Longarmx (53 views)
2014-10-17 03:59:02

Norakomi (47 views)
2014-10-16 15:22:06

Norakomi (35 views)
2014-10-16 15:20:20

lcass (39 views)
2014-10-15 16:18:58

TehJavaDev (70 views)
2014-10-14 00:39:48

TehJavaDev (69 views)
2014-10-14 00:35:47

TehJavaDev (61 views)
2014-10-14 00:32:37

BurntPizza (74 views)
2014-10-11 23:24:42

BurntPizza (47 views)
2014-10-11 23:10:45
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
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!