为什么Java在新PC上绘制速度慢? - VSYNC?

时间:2014-08-02 09:50:35

标签: java drawing benchmarking vsync

在新的PC上运行Java绘图基准测试(Core i7-4820K 3.7 GHz,Asus P9X79 LE,GeForce GTX 650,Windows 8.1和Ubuntu 14.04)似乎使用vsync在大约60 FPS下通过Windows与Java RTE 1.7运行。 0_65。然后,在稍后的情况下,基于其他PC上的速度,以预期的400+ FPS运行。现在又回到了60 FPS。 GPU利用率几乎为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,我发现它可以校准,如下所示,还包括sleep,wait,currentTimeMillis和nanoTime。

http://www.java2s.com/Code/Java/Swing-JFC/TimeResolution.htm

以下产生摆动定时器测量:

//  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毫秒,新的一台产生15.66毫秒,相当于接近64 FPS,前者限制为9091 FPS。

有谁知道是否可以强制使用最小摆动计时器分辨率?

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

1 个答案:

答案 0 :(得分:0)

我相信这是一个完整的答案(前面已经低估了)。我希望有人在这里知道,但事实并非如此。所以我不得不做自己的研究。

在使用Javax swing timer = new Timer(0,this)时,在指示actionPerformed后,主要活动执行应该以零睡眠时间重新开始。我找到了一个简单的程序,它演示了时序,没有图形活动,并修改它来测量单个动作(帧)和每秒累积帧数所用的时间。结果如下。

几帧之后,有问题的PC切换到15.3+ ms的常规休眠时间,可能正如另一条消息中所报告的那样,由Windows时间片粒度1000 ms / 64或15.625 ms控制,另一台PC表示高开头的开销,但在50帧内录得543 FPS。

           New PC Win 8.1     Other PC Win 7

   Frames   FPS   This frame   FPS   This frame
                  microsecs          microsecs

         1  500       2603     166       6170
         2   44      42630     333        100
         3   57       7051     500        107
         4   58      15402     571         74
         5   60      15550     555        231
         6   60      15633     117      41586
         7   60      15483     134        817
         8   61      15396     106      22895
         9   61      15388     107       8374
        10   61      15370     117        867
        11   62      15321     129         41
        12   62      15418     141        217
        13   62      15390     152         88
        14   62      15353     162         73
     To
        45   63      15353     494         45
        46   63      15360     505         48
        47   63      14998     516         45
        48   63      15306     521        113
        49   63      15331     532         64
        50   63      15365     543         44

Java程序如下。

// From http://www.java2s.com/Code/JavaAPI/javax.swing/Timerstop.htm

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.Timer;

class MainClass extends JFrame 
{
  Timer timer;
  long startTime, startTimeF, runTime, fps, usecs;
  int counter;

  MainClass(String title) 
  {
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    ActionListener a = new ActionListener() 
    {
      public void actionPerformed(ActionEvent e) 
      {
        runTime = (System.nanoTime() - startTime) / 1000000;
        usecs = (System.nanoTime() - startTimeF) / 1000;
        fps = counter * 1000 / runTime;
        System.out.println(" Frames = " + counter + "  " + fps + " FPS This frame " + usecs + " microseconds");
        startTimeF = System.nanoTime();

        if (++counter > 50) 
        {
          timer.stop();
          System.exit(0);
        }
      }
    };

    timer = new Timer(0, a);
    startTime = System.nanoTime();
    startTimeF = System.nanoTime();
    counter = 1;
    timer.start();
    setSize(800, 600);
//    pack();
    setVisible(true);
  }

  public static void main(String[] args) 
  {
    new MainClass("Timer Demo1");
  }
}