在一台新 PC(Core i7-4820K 3.7 GHz、Asus P9X79 LE、GeForce GTX 650、Windows 8.1 和 Ubuntu 14.04)上运行 Java 绘图基准测试似乎可以通过带有 Java RTE 1.7.0_65 的 Windows 以大约 60 FPS 的速度运行。然后,有一次,根据其他 PC 上的速度,以预期的 400+ FPS 运行。现在它又回到了 60 FPS。在最轻量级的测试中,CPU 利用率几乎为 0%,而 GPU 小于 10%。新的图形驱动程序没有任何区别。相同的类文件通过 Ubuntu 和 linux java 1.7.0_55 获得 400 FPS,并且使用 JDK 6 或 7 编译没有区别。
下面是没有加载、计算和显示图像的函数的代码。这在较旧的稍慢的 Win 7 PC 上获得了近 600 FPS,但在新 PC 上再次获得了 60 FPS。通过 HTML 小程序在线运行的代码变体以 400+ FPS 运行。有人有解释吗?
// 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();
}
}
我尝试了许多“线程安全”示例,试图在新 PC 上获得更快的 FPS 速度,但均未成功。最后一个只是刷新没有图形的空白屏幕。我注意到测得的 FPS 通常高达 65 FPS,这表明它可能不是强制 VSYNC。这导致怀疑 Swing Timer,我发现它可以按照以下所示进行校准,其中还包括睡眠、等待、currentTimeMillis 和 nanoTime。
http://www.java2s.com/Code/Java/Swing-JFC/TimeResolution.htm
以下产生 Swing Timer 测量:
// 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();
}
}
以下显示了产生快速 FPS 的 PC 的结果和新 PC 的第二个结果。睡眠时间为零时,另一台 PC 产生 0.11 毫秒,新的 PC 产生 15.66 毫秒,相当于接近 64 FPS,之前的限制为 9091 FPS。
有谁知道是否可以强制最低 Swing Timer 分辨率?
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