Running a Java drawing benchmark on a new PC (Core i7-4820K 3.7 GHz, Asus P9X79 LE, GeForce GTX 650, Windows 8.1 and Ubuntu 14.04) appeared to run using vsync at around 60 FPS via Windows with Java RTE 1.7.0_65 . Then, on one later occasion, ran at an expected 400+ FPS, based on speeds on other PCs. Now it is back to 60 FPS. CPU utilisation is almost 0% with GPU at <10% on the lightest test. A new graphics driver made no difference. The same class file obtains 400 FPS via Ubuntu with linux java 1.7.0_55 and makes no difference compiled with JDK 6 or 7.
Below is the code without the functions that load, calculate and display images. This obtains nearly 600 FPS on an older slightly slower Win 7 PC but, again, 60 FPS on the new PC. A variation of the code to run on-line via an HTML applet runs at 400+ FPS. Does anyone have an explanation?
// Save as JavaDrawIt.java
// Compile command - javac JavaDrawIt.java
// Run command - java JavaDrawIt
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
public class JavaDrawIt extends JPanel implements ActionListener
{
Timer timer;
static int WIDTH = 1280 ;
static int HEIGHT = 720 ;
int gch = 1;
int gcm = 1;
int grn = 0;
String msg;
double fps;
double startTime;
double runTime = 0;
int frames = 0;
Random randNum = new Random();
private JavaDrawIt()
{
randNum.setSeed(999);
timer = new Timer(0, this);
startTime = (double)System.currentTimeMillis();
}
public void actionPerformed(ActionEvent e)
{
if (runTime <= 5.0)
{
repaint();
}
}
public void paintComponent(Graphics g)
{
int i;
float fh;
float fw;
super.paintComponent(g);
grn = grn + gch;
if (grn > 255)
{
gch = -gcm;
grn = 255;
}
if (grn < 1)
{
gch = gcm;
grn = 0;
}
g.setColor(new Color(0, grn, 255));
g.fillRect(0, 0, WIDTH, HEIGHT);
frames = frames + 1;
Graphics2D g2 = (Graphics2D)g;
Font font = new Font("MONOSPACE", Font.PLAIN, 24);
g2.setFont(font);
g.setColor (Color.WHITE);
runTime = ((double)System.currentTimeMillis() - startTime) / 1000;
fps = (double)frames / runTime;
msg = String.format(" %6.2f FPS, %6d Frames, %6.2f Seconds", fps, frames, runTime);
g2.drawString(msg, 10, 30);
}
public static void main(String[] args)
{
JFrame f = new JFrame(" JavaDrawIt");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JavaDrawIt m = new JavaDrawIt();
f.add(m);
f.setSize(WIDTH, HEIGHT);
f.setVisible(true);
m.timer.start();
}
}
I have tried a number of “Thread Safe” examples, attempting to obtain faster FPS speeds on the new PC, without any success. The last one was just refreshing a blank screen with no graphics. I noted that measured FPS was often up to 65 FPS, suggesting that it might not be a forced VSYNC. That lead to suspecting Swing Timer and I found that it could be calibrated as demonstrated in the following that also covers sleep, wait, currentTimeMillis AND nanoTime.
http://www.java2s.com/Code/Java/Swing-JFC/TimeResolution.htm
The following produces Swing Timer measurements:
// TimeResolution.java
// Copyright (c) 2007, Sun Microsystems, Inc
// All rights reserved.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
public class TimeResolution implements ActionListener
{
private static int INCREMENT = 5;
private static int MAX = 50;
// Variables used in measurement of Swing timer
int timerIteration = 0;
int iterations = 0;
Timer timer;
long startTime, endTime;
int sleepTime;
public void actionPerformed(ActionEvent ae)
{
if (++timerIteration > iterations)
{
timer.stop();
timerIteration = 0;
endTime = System.nanoTime();
long totalTime = (endTime - startTime) / 1000000;
float calculatedDelayTime = totalTime / (float)iterations;
System.out.printf(" %2d %5d %5d %5.2f\n",
sleepTime, iterations, totalTime, calculatedDelayTime);
}
}
public void measureTimer()
{
System.out.printf(" measured\n");
System.out.printf("timer delay iterations total time per-delay\n");
for (sleepTime = 0; sleepTime <= 5; ++sleepTime)
{
iterations = (sleepTime == 0) ? 1000 : (1000 / sleepTime);
timerIteration = 1;
timer = new Timer(sleepTime, this);
startTime = System.nanoTime();
timer.start();
while (timerIteration > 0)
{
try
{
Thread.sleep(1000);
}
catch (Exception e)
{
}
}
}
}
// Execute the various timer resolution tests.
public static void main(String args[])
{
TimeResolution timeResolution = new TimeResolution();
timeResolution.measureTimer();
}
}
Following shows results from the PC that produces fast FPS and the second from the new PC. With sleep time of zero the other PC produces 0.11 milliseconds and the new one 15.66 milliseconds, equivalent to nearly 64 FPS, with the former limit at 9091 FPS.
Does anyone know if it is possible to force a minimum Swing Timer resolution?
Other PC
timer delay iterations total time per-delay
0 1000 113 0.11
1 1000 15600 15.60
2 500 7800 15.60
3 333 5195 15.60
4 250 3900 15.60
5 200 3120 15.60
New PC
0 1000 15660 15.66
1 1000 15625 15.63
2 500 7812 15.62
3 333 5203 15.62
4 250 3906 15.62
5 200 3125 15.63