Timer resolution?
We don't have J2SE 1.5 on Mac OS X yet, so I wrote my own nanoTime() method (below) using Sun's performance measurement class.
One thing I've noticed is that I obtain 2x better clock resolution when I compute elapsed CPU time directly from clock ticks because the conversion from ticks to nanoseconds requires one multiply and one divide (before the compiler optimizes my code).
Could someone please test the program below under Java 1.5 and tell me how the resolution of my nanoTime() method compares with the new System.nanoTime() method? Set the BEST variable to false and change the 2 timer.nanoTime() calls in getResolution() to System.nanoTime().
Currently, with BEST = true, I am getting a time resolution of 440 nanoseconds on Mac OS X (old 400 MHz G3 iMac).
Thank you!
Craig
[code]
// Test Sun's performance measurement clock
import sun.misc.Perf;
import java.text.DecimalFormat;
public class TestTimer
{
HiResTimer timer;
public TestTimer()
{
long before, after, cputime; // CPU timing variables
DecimalFormat sci = new DecimalFormat("##0.###E0");
timer = new HiResTimer();
System.out.println("Counter frequency : " + sci.format(timer.getFrequency()) + " Hz (ticks/sec)");
System.out.println("Time per clock tick : " + timer.getTickTime() + " nanoseconds");
System.out.println("Counter resolution : " + timer.getCounterResolution() + " clock ticks");
System.out.println("Avg. counter resolution: " + timer.getAvgCounterResolution() + " clock ticks");
System.out.println("Time resolution : " + timer.getResolution() + " nanoseconds");
System.out.println("Sleeping for 3 seconds . . .");
before = System.currentTimeMillis(); // timer.milliTime();
snooze();
after = System.currentTimeMillis(); // timer.milliTime();
cputime = after - before;
System.out.println("Sleep time of 3 seconds measured as: " + cputime + " milliseconds");
System.out.println("Sleeping again for 3 seconds . . .");
before = timer.nanoTime(); // System.nanoTime();
snooze();
after = timer.nanoTime(); // System.nanoTime();
cputime = after - before;
System.out.println("Sleep time of 3 seconds measured as: " + cputime + " nanoseconds");
System.out.println("Sleeping yet again for 3 seconds . . .");
before = timer.getTicks();
snooze();
after = timer.getTicks();
cputime = timer.nsFromTicks(after - before);
System.out.println("Sleep time of 3 seconds measured as: " + cputime + " nanoseconds from ticks");
}
// Sleep 3 seconds
private final void snooze()
{
try
{
Thread.sleep(3000);
}
catch ( Exception x )
{
x.printStackTrace();
}
}
public static void main(String[] args)
{
new TestTimer();
}
// Inner class for high-rez timing measurements
public class HiResTimer
{
private Perf hiResTimer;
private long freq;
private int LOOPS;
private boolean BEST;
public HiResTimer()
{
hiResTimer = Perf.getPerf();
freq = hiResTimer.highResFrequency();
LOOPS = 1000000;
BEST = true; // Toggle for clock ticks ns
}
// return current time in milliseconds
public long milliTime()
{
return (hiResTimer.highResCounter() * 1000L / freq);
// return (hiResTimer.highResCounter() / ((freq + 500L) / 1000L));
}
// return current time in nanoseconds
public long nanoTime()
{
return (hiResTimer.highResCounter() * 1000000000L / freq);
}
// return the current clock ticks
public long getTicks()
{
return hiResTimer.highResCounter();
}
// return the number of clock ticks per second
public long getFrequency()
{
return freq;
}
// return the number of nanoseconds per clock tick
public long getTickTime()
{
return (1000000000L/freq);
}
// convert clock ticks to nanoseconds
public long nsFromTicks(long ticks)
{
return (ticks * 1000000000L / freq);
}
// Error expected in measured elapsed time (in nanoseconds)
public long getResolution()
{
long before = 0L;
long after = 0L;
long smallest = Long.MAX_VALUE;
if (BEST)
{
// Compute using clock ticks
for (int i=0; i ns
}
else
{
// Compute using nanoseconds
for (int i=0; i<LOOPS; ++i)
{
before = nanoTime(); // System.nanoTime();
after = nanoTime(); // System.nanoTime();
smallest = Math.min(smallest, after - before);
}
return (smallest);
}
}
public long getCounterResolution()
{
long before = 0L;
long after = 0L;
long smallest = Long.MAX_VALUE;
for (int i=0; i<LOOPS; ++i)
{
before = hiResTimer.highResCounter();
after = hiResTimer.highResCounter();
smallest = Math.min(smallest, after - before);
}
return smallest;
}
// Avg error expected in measured elapsed time (in clock ticks)
public long getAvgCounterResolution()
{
long before = 0L;
long after = 0L;
long dt = 0L;
// Warm up JIT/HotSpot compiler
// for (int i=0; i<LOOPS; ++i)
// before = hiResTimer.highResCounter();
for (int i=0; i<LOOPS; ++i)
{
// before = after = hiResTimer.highResCounter();
// while (before == after)
// after = hiResTimer.highResCounter();
before = hiResTimer.highResCounter();
after = hiResTimer.highResCounter();
dt += (after - before);
}
return Math.round((double)dt/LOOPS);
}
} // End HiResTimer inner class
} // End TestTimer class
[/code]
Posted by: mattocks on February 06, 2004 at 07:25 PM