FPS lock not precise - java

I'm implementing an FPS cap for my game, but it's not very precise.
public static volatile int FPS_CAP = 60;
#Override
public void run() {
long lastTime = System.nanoTime();
double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
long timer = System.currentTimeMillis(), lastRender;
while (running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while (delta >= 1) {
tick();
delta--;
}
lastRender = System.currentTimeMillis();
draw.render();
draw.fps++;
if (FPS_CAP != -1) {
try {
int nsToSleep = (int) ((1000 / FPS_CAP) - (System.currentTimeMillis() - lastRender));
if (nsToSleep > 1 / FPS_CAP) {
Thread.sleep(nsToSleep);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (System.currentTimeMillis() - timer > 1000) {
timer += 1000;
draw.lastFPS = draw.fps;
draw.fps = 0;
// updates = 0;
}
}
}
The result is:
As you can see it's really not accurate, sometimes it's a lot lower than 60 and sometimes even higher!
I want it to be as precise as possible.
Thanks in advance.

Java is not precise enough to achieve such precision mechanisms. All rendering libraries actually rely on a C or C++ layer to manage real-time precision.
In your case, the best workaround would be to avoid the use of Thread.sleep().
You can rely on Timer events instead to run the updates during the TimerTask. Your game will have a heartbeat approximately 60 times per second.
Another solution, if 60fps is good for you, is to wait for a VSync before rendering your screen. Most LCD screens are 60 or 120fps. The VSync should be managed by your graphical library (swing, JavaFX or other).
A last solution, you could look into the code of a specialized engine (like JMonkey) as a reference.

First of all I see you mixed System.currentTimeMilis() and System.nanoTime() not really a good idea, use only either one of them. Better only use System.nanoTime() since you are working on a high precision.
What's causing your issue is Thread.sleep() is not precise enough. So you need to avoid sleeping. Change your sleeping code to this;
lastRender = System.nanoTime(); //change it to nano instead milli
draw.render();
draw.fps++;
if (FPS_CAP > 0) {
while ( now - lastRender < (1000000000 / FPS_CAP))
{
Thread.yield();
//This stops the app from consuming all your CPU. It makes this slightly less accurate, but is worth it.
//You can remove this line and it will still work (better), your CPU just climbs on certain OSes.
//FYI on some OS's this can cause pretty bad stuttering.
try {Thread.sleep(1);} catch(Exception e) {}
now = System.nanoTime();
}
}
About how to enable VSYNC, your application need to be full screen and you should call Toolkit.sync() after every render.

JavaFX is based upon a pulse mechanism.
A pulse is an event that indicates to the JavaFX scene graph that it
is time to synchronize the state of the elements on the scene graph
with Prism. A pulse is throttled at 60 frames per second (fps) maximum
and is fired whenever animations are running on the scene graph. Even
when animation is not running, a pulse is scheduled when something in
the scene graph is changed. For example, if a position of a button is
changed, a pulse is scheduled.
When a pulse is fired, the state of the elements on the scene graph is
synchronized down to the rendering layer. A pulse enables application
developers a way to handle events asynchronously. This important
feature allows the system to batch and execute events on the pulse.
. . .
The Glass Windowing Toolkit is responsible for executing the pulse
events. It uses the high-resolution native timers to make the
execution.
To understand the implementation of the pulse mechanism, it is best to study the JavaFX source code. Some key classes are:
Timer.java
WinTimer.java
win/Timer.h
win/Timer.cpp
The above links are for the generic Timer class and the window specific timer implementations. The JavaFX source code includes implementations for other platforms, such as OS X, GTK, iOS, Android, etc.
Some implementations (such as OS X it would seem) allow for vsync synchronization of the Timer implementation, others (such as Windows it would seem) do not allow for vsync synchronization. Though, these systems can get complicated, so I guess it is possible that, in some cases, vsync synchronization might be achieved via the hardware graphics pipeline rather than via the timer.
The windows native code is based upon a timeSetEvent call.
By default, the JavaFX framerate is capped at 60fps, though it is adjustable via undocumented properties.
If you are not using JavaFX (and it doesn't seem you are), you could still examine the JavaFX source code and learn about its implementation there in case you wanted to port any of the concepts or code for use in your application. You might also be able to shoehorn the JavaFX timer mechanism into a non-JavaFX application by making your application subclass the JavaFX Application class or creating a JFXPanel to initiate the JavaFX toolkit, then implementing your timer callback based upon AnimationTimer.

Related

LineChart performance decrease over time

So we're working on an signal processing application, there's a specific type of hardware in the PC and a C driver communicating with it.
The application frontend/gui is written in JavaFX. We're having some issues with the JavaFX LineChart, we're measuring electrical signal frequency and trying to plot it on the aforementioned LineChart.
The measurements are running in a loop until 1000 samples are gathered, we've been testing with 100Hz signal, which means that it takes 10s to get these 1000 samples.
There's a separate 'LineChart' thread running and checking (every 10ms) whether there are new samples available, if so these are added to the LineChart, if the measurement thread is finished the LineChart thread resets the LineChart (clears the series data) and the process starts over.
Every thing is running fine for first ~20 min, after which it seems that the LineChart 'slows down', it looks as if the drawing is not as fast/dynamic as in the beginning.
We've checked pretty much everything we could in the application and found nothing, so we've created a separate project which only has the LineChart and a thread that adds samples to the chart every 10ms (up to 1000 samples). We've observed the same behavior, here's how it's done:
Thread t = new Thread(new Runnable() {
#Override
public void run() {
int iteration = 0;
long start = 0;
long stop = 0;
while (run) {
CountDownLatch latch = new CountDownLatch(1);
start = System.currentTimeMillis();
for (int i = 0; i < 1001; i++) {
double ran = random(50, 105);
final int c = i;
Platform.runLater(() -> {
series.getData().add(new XYChart.Data<>(c, ran));
if (c == 1000) {
System.out.print("Points: " + series.getData().size());
series.getData().clear();
latch.countDown();
}
});
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
iteration++;
stop = System.currentTimeMillis();
try {
latch.await();
} catch (InterruptedException e) {}
System.out.println(", Iteration : " + iteration + ", elapsed: " + (stop - start) + " [ms]");
}
}
});
What are we missing here? Why is the performance dropping after ~30-45 min in above example? Any ideas?
The above piece of code was run for 8h, each time all points were added to the Chart, the 'drawing time' was comparable (between 10100ms and 10350ms).
You don't have anything wrong with the code that I can see, but, you keep adding to the series. I don't think that this is an issue with the code, but it's the machine trying to keep up and manage ALL the points you have, you said 1000 in 10s, that means that after 20 mins, you have 120,000 points in storage, being managed, and plotted. Assuming that you record to the tenths place, thats a TON of storage, and more likely than not, you're seeing the processing slow down with all that info. Simply put, the machine can't handle it.
This is an older question, but in case anyone stumbles across it looking for performance problems, there is a huge hit here in the way data is added to the series.
Points should be added to a series all at once when possible, rather than individually.
In the case of the above example, if the code collected all encountered data points into a list, and then added to the entire list to the series using an addAll call, the performance would increase. The frequency of the addAll call can be set based on trial and error for aesthetic performance, but the hertz a user can see is much less than the hertz the Platform.RunLater is trying to update.
I found the reason, it was lack of hardware acceleration on Linux Platforms where AMD GFX cards where installed. Oracle did not provide hardware support so JavaFX was falling back to some crappy one resulting in performance decay. The piece of code from original post works no problem on Win machines or Linux machines with Nvidia cards BUT not on Linux with AMD cards. On Linux with amd cards you have to manually enforce software acceleration (as opposed to the default one).

Make a simple timer in Java

I can't seem to figure out how to make a simple timer in java. All I need it to do is just display time, really. So just a start method, and it keeps counting up like 0:00, 0:01, 0:02, etc. I've seen some other similar forum posts on this, but all the code is kind of complicated for my level of understanding; I'm kind of new to java. But it shouldnt be that hard to make a timer that just performs such a basic function? If anyone could help it would be greatly appreciated :)
This is not difficult. However, I would caution you that I have seen some very confused answers on stack overflow, in some cases shockingly poor coding habits, so be very careful. First let me answer the question.
If seem that the biggest mistake that programmers make in implementing a timer, is thinking that they need something to keep track of the current time. That is, they write some sort of loop that increments a variable every second or some such silly thing. You do not need to write code to keep track of the time. The function System.currentTimeMillis() will do that for you, and it does it quite accurately.
Timer code will involve two aspects which many programmers mix up:
calculation of the time
refresh of the display
All you need to do to calculate the time to display, is to record the time that the timer started:
long startTime = System.currentTimeMillis();
Later, when you want to display the amount of time, you just subtract this from the current time.
long elapsedTime = System.currentTimeMillis() - startTime;
long elapsedSeconds = elapsedTime / 1000;
long secondsDisplay = elapsedSeconds % 60;
long elapsedMinutes = elapsedSeconds / 60;
//put here code to format and display the values
The biggest mistake that programmers make is to think they need a variable to hold the current time and then to write code to increment that variable every second, e.g. something called "elapsedSeconds" which they maintain. The problem is that you can schedule code to be called every second, but there is no guarantee of exactly when that code will be called. If the system is busy, that code might be called quite a bit later than the second. If the system is extremely busy (for example page fetching from a faulty disk) it could actually be several seconds late. Code that uses the Thread.sleep(1000) function to loop every second will find that the error builds up over time. If sleep returns 300ms late one time, that error is compounded into your calculation of what time it is. This is all completely unnecessary because the OS has a function to tell you the current time.
The above calculation will be accurate whether you run this code every second, 100 times a second, or once every 3.572 seconds. The point is that currentTimeMillis() is the accurate representation of the time regardless of when this code is called -- and that is an important consideration because thread and timer events are not guaranteed to be accurate at a specific time.
The second aspect of a timer is refresh of the display. This will depend upon the technology you are using to display with. In a GUI environment you need to schedule paint events. You would like these paint events to come right after the time that the display is expected to change. However, it is tricky. You can request a paint event, but there may be hundreds of other paint events queued up to be handled before yours.
One lazy way to do this is to schedule 10 paint events per second. Because the calculation of the time does not depend on the code being called at a particular point in time, and because it does not matter if you re-paint the screen with the same time, this approach more or less guarantees that the displayed time will show the right time within about 1/10 of a second. This seems a bit of a waste, because 9 times out of 10 you are painting what is already on the screen.
If you are writing a program with animation of some sort (like a game) which is refreshing the screen 30 times a second, then you need do nothing. Just incorporate the timer display call into your regular screen refresh.
If paint events are expensive, or if you are writing a program that does terminal-style output, you can optimize the scheduling of events by calculating the amount of time remaining until the display will change:
long elapsedTime = System.currentTimeMillis() - startTime;
long timeTillNextDisplayChange = 1000 - (elapsedTime % 1000);
The variable timeTillNextDisplayChange holds the number of milliseconds you need to wait until the seconds part of the timer will change. You can then schedule a paint event to occur at that time, possibly calling Thread.sleep(timeTillNextDisplayChange) and after the sleep do the output. If your code is running in a browser, you can use this technique to update the page DOM at the right time.
Note, that there is nothing in this calculation of the display refresh that effects the accuracy of the timer itself. The thread might return from sleep 10ms late, or even 500ms late, and the accuracy of the timer will not be effected. On every pass we calculate the time to wait from the currentTimeMillis, so being called late on one occasion will not cause later displays to be late.
That is the key to an accurate timer. Do not expect the OS to call your routine or send the paint event exactly when you ask it to. Usually, of course, with modern machines, the OS is remarkably responsive and accurate. This happens in test situations where you are not running much else, and the timer seems to work. But, in production, under rare stress situation, you do not want your timer "drifting" because the system is busy.
You can either use Timer class from java.util or another way, which is more complicated, is with Threads. Timer also has thread action, but it's pretty easy to understand to use it.
For creating a simple timer as you explained as per your need , it is very easy to write a code for that. I have written the below code for your reference. If you wish you can enhance it.
import java.util.concurrent.TimeUnit;
public class PerfectTimer {
public static void main(String[] args) throws InterruptedException
{
boolean x=true;
long displayMinutes=0;
long starttime=System.currentTimeMillis();
System.out.println("Timer:");
while(x)
{
TimeUnit.SECONDS.sleep(1);
long timepassed=System.currentTimeMillis()-starttime;
long secondspassed=timepassed/1000;
if(secondspassed==60)
{
secondspassed=0;
starttime=System.currentTimeMillis();
}
if((secondspassed%60)==0)
displayMinutes++;
System.out.println(displayMinutes+"::"+secondspassed);
}
}
}
if you want to update something in the main thread (like UI components)
better to use Handler
Handler h = new Handler();
h.postDelayed(new Runnable() {
#Override
public void run() {
//do something
}
}, 20);
20 - the delay In MS to do something.
and run it in a loop.
I have created a Timer that has everything you might need in it.
I even documented it!
And I also compiled it for faster usage.
Here's an example:
//...
//For demo only!
public static void main(String[]a){
Timer timer=new Timer();
timer.setWatcher(new Timer.TimerWatcher(){
public void hasStopped(boolean stopped){
System.out.print(stopped+" | ");
}
public void timeElapsed(long nano, long millis, long seconds){
System.out.print(nano+", ");
System.out.print(millis+", ");
System.out.print(seconds+" | ");
}
public void timeLeft(long timeLeft){
System.out.print(timeLeft+"\r");
}
});
//Block the thread for 5 seconds!
timer.stopAfter(5, Timer.seconds); //You can replace this with Integer.MAX_VALUE.
//So that our watcher won't go to waste.
System.out.println();
}
//...
This is not for promotion, made this to help people not waste their time in coding classes themselves!

Java timing accuracy on Windows XP vs. Windows 7

I have a bizarre problem - I'm hoping someone can explain to me what is happening and a possible workaround. I am implementing a Z80 core in Java, and attempting to slow it down, by using a java.util.Timer object in a separate thread.
The basic setup is that I have one thread running an execute loop, 50 times per second. Within this execute loop, however many cycles are executed, and then wait() is invoked. The external Timer thread will invoke notifyAll() on the Z80 object every 20ms, simulating a PAL Sega Master System clock frequency of 3.54 MHz (ish).
The method I have described above works perfectly on Windows 7 (tried two machines) but I have also tried two Windows XP machines and on both of them, the Timer object seems to be oversleeping by around 50% or so. This means that one second of emulation time is actually taking around 1.5 seconds or so on a Windows XP machine.
I have tried using Thread.sleep() instead of a Timer object, but this has exactly the same effect. I realise granularity of time in most OSes isn't better than 1ms, but I can put up with 999ms or 1001ms instead of 1000ms. What I can't put up with is 1562ms - I just don't understand why my method works OK on newer version of Windows, but not the older one - I've investigated interrupt periods and so on, but don't seem to have developed a workaround.
Could anyone please tell me the cause of this problem and a suggested workaround? Many thanks.
Update: Here is the full code for a smaller app I built to show the same issue:
import java.util.Timer;
import java.util.TimerTask;
public class WorkThread extends Thread
{
private Timer timerThread;
private WakeUpTask timerTask;
public WorkThread()
{
timerThread = new Timer();
timerTask = new WakeUpTask(this);
}
public void run()
{
timerThread.schedule(timerTask, 0, 20);
while (true)
{
long startTime = System.nanoTime();
for (int i = 0; i < 50; i++)
{
int a = 1 + 1;
goToSleep();
}
long timeTaken = (System.nanoTime() - startTime) / 1000000;
System.out.println("Time taken this loop: " + timeTaken + " milliseconds");
}
}
synchronized public void goToSleep()
{
try
{
wait();
}
catch (InterruptedException e)
{
System.exit(0);
}
}
synchronized public void wakeUp()
{
notifyAll();
}
private class WakeUpTask extends TimerTask
{
private WorkThread w;
public WakeUpTask(WorkThread t)
{
w = t;
}
public void run()
{
w.wakeUp();
}
}
}
All the main class does is create and start one of these worker threads. On Windows 7, this code produces a time of around 999ms - 1000ms, which is totally fine. Running the same jar on Windows XP however produces a time of around 1562ms - 1566ms, and this is on two separate XP machines that I have tested this. They are all running Java 6 update 27.
I find this problem is happening because the Timer is sleeping for 20ms (quite a small value) - if I bung all the execute loops for a single second into wait wait() - notifyAll() cycle, this produces the correct result - I'm sure people who see what I'm trying to do (emulate a Sega Master System at 50fps) will see how this is not a solution though - it won't give an interactive response time, skipping 49 of every 50. As I say, Win7 copes fine with this. Sorry if my code is too large :-(
Could anyone please tell me the cause of this problem and a suggested workaround?
The problem you are seeing probably has to do with clock resolution. Some Operating Systems (Windows XP and earlier) are notorious for oversleeping and being slow with wait/notify/sleep (interrupts in general). Meanwhile other Operating Systems (every Linux I've seen) are excellent at returning control at quite nearly the moment specified.
The workaround? For short durations, use a live wait (busy loop). For long durations, sleep for less time than you really want and then live wait the remainder.
I'd forgo the TimerTask and just use a busy loop:
long sleepUntil = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(20);
while (System.nanoTime() < sleepUntil) {
Thread.sleep(2); // catch of InterruptedException left out for brevity
}
The two millisecond delay gives the host OS plenty of time to work on other stuff (and you're likely to be on a multicore anyway). The remaining program code is a lot simpler.
If the hard-coded two milliseconds are too much of a blunt instrument, you can calculate the required sleep time and use the Thread.sleep(long, int) overload.
You can set the timer resolution on Windows XP.
http://msdn.microsoft.com/en-us/library/windows/desktop/dd757624%28v=vs.85%29.aspx
Since this is a system-wide setting, you can use a tool to set the resolution so you can verify whether this is your problem.
Try this out and see if it helps: http://www.lucashale.com/timer-resolution/
You might see better timings on newer versions of Windows because, by default, newer version might have tighter timings. Also, if you are running an application such as Windows Media Player, it improves the timer resolution. So if you happen to be listening to some music while running your emulator, you might get great timings.

Play a sound every N milliseconds

I'm developing a metronome application. The user can select at runtime the bpm, and my app will play the "tick" sound accordingly. The "tick" is a single metronome "shot" (mp3). I tried implementing it using Handler and MediaPlayer, but the metronome is not precise at all.
So I thought about changing the whole approach: when the user choose a new bpm value, I synthesize a new sound by repeating the tick sound X times every N milliseconds, then looping over this runtime created sound.
Is this a valid alternative? How can it be implemented in Android?
The alternative of looping through a synthesized sound seems to be the best choice for now. There was a great session about audio on Google I/O 2013 called High Performance Audio that I would certainly advice watching for having a deeper understanding on how the system works and what problems the developers will face when dealing with the audio latency. At about the 17:00 of the video, there is graph that shows jitter versus callbacks. In the perfect world that does not exist (oh really?), the jitter would be zero for all the scheduled audio callbacks made. But that is not the case, for there are jitters as high as 35 milliseconds or even greater, for the data in the graph was made using an unspecified ICS device and there are certainly worse scenarios than that.
So, as a metronome is a precision tool and these jitters are not good at all, the scheduled playback approach should be left aside. I even made an reasonably realiable metronome work with a synthesized sound using AudioTrack.
Hope it helps ^^
You could try to use a TimerTask scheduled for fixed-rate execution on a Timer.
Timer and TimerTask are both part of the Android SDK (and Java SE). The executions do not delay because of execution time of the previous event.
Timer timer = new Timer("MetronomeTimer", true);
TimerTask tone = new TimerTask(){
#Override
public void run(){
//Play sound
}
};
timer.scheduleAtFixedRate(tone, 500, 500); //120 BPM. Executes every 500 ms.
You can then cancel the TimerTask when you need to change the BPM.
tone.cancel();
tone = new TimerTask(){...}
timer.scheduleAtFixedRate(tone, 1000, 1000); //60 BPM. Executes every 1000 ms.
Another possibility that may meet your requirements (from your comments) is spinning a thread and checking System.nanoTime() and sleeping in increments but spinning when you get close to wake up.
long delayNanos = 500000000;
long wakeup = System.nanoTime() + delayNanos; //Half second from right now
long now;
while(!done){
now = System.nanoTime();
//If we are less than 50 milliseconds from wake up. Spin away.
if(now <= wakeup - 50000000){
//Sleep in very small increments, so we don't spin unrestricted.
Thread.sleep(10);
}
if(now >= wakeup){
//Play sound
wakeup += delayNanos;
}
}
When this play sound is called
mSoundManager.playSound(1);
Android waits until that call is finished, then you call
mHandler.postAtTime(this, SystemClock.uptimeMillis() + 200);
however, if you reverse those calls, you may find that the timing is more accurate.
mHandler.postAtTime(this, SystemClock.uptimeMillis() + 200);
mSoundManager.playSound(1);
You can't count on your sound taking exactly the same amount of time to play, so telling the handler to post first is a bit better. Still not ideal, however.

Measuring time spent in application / thread

I am writing a simulation in Java whereby objects act under Newtonian physics. An object may have a force applied to it and the resulting velocity causes it to move across the screen. The nature of the simulation means that objects move in discrete steps depending on the time ellapsed between the current and previous iteration of the animation loop; e.g
public void animationLoop() {
long prev = System.currentTimeMillis();
long now;
while(true) {
long now = System.currentTimeMillis();
long deltaMillis = now - prev;
prev = now;
if (deltaMillis > 0) { // Some time has passed
for (Mass m : masses) {
m.updatePosition(deltaMillis);
}
// Do all repaints.
}
}
}
A problem arises if the animation thread is delayed in some way causing a large amount of time to ellapse (the classic case being under Windows whereby clicking and holding on minimise / maximise prevents a repaint), which causes objects to move at an alarming rate. My question: Is there a way to determine the time spent in the animation thread rather than the wallclock time, or can anyone suggest a workaround to avoid this problem?
My only thought so far is to contstrain deltaMillis by some upper bound.
Have you considered using something like a timer instead of spinning in a loop?
TimerTask tt = new TimerTask(){
long prev = System.currentTimeMillis();
public void run(){
long now = System.currentTimeMillis();
for (Mass m : masses) {
m.updatePosition(now-prev);
}
prev = now;
}
}
new Timer(true).schedule(tt, 1000, 1000) ;
This way you are guaranteed to at least have some delay between the update of your objects so you shouldn't have a bunch of repaints consecutively as with the while(true) loop, and if the thread is delayed you will not got an immediate re-execution of the task, from the docs: "In fixed-delay execution, each execution is scheduled relative to the actual execution time of the previous execution."
I found javax.swing.Timer.html particularly helpful for this. Here's an example that models elastic collisions among spherical particles and the walls of a container.
Addendum: This related approach may help de-couple the model from the view. A separate thread models the system's evolution, while the view renders a "snapshot" of the model at a fixed rate.
In either case, I cap the rate to accommodate the slowest target platform.
You might like to read this article entitled "Java: Getting Thread Time with ThreadMXBean".
Basically, there is a class ThreadMXBean that enables you to get time spent in particular Thread. I haven't tried that, but the methods (and examples from article I mentioned) look promising, so I think you will be able to accomplish what you want with this.
I would use an animation library for doing the animation instead of reinventing the wheel. Here are two good choices:
The Timing Framework
Trident

Categories

Resources