Wow, the media framework gets into a bad way if it's forced to use the

inaccurate System.currentTimeMillis() timer. Fortuately Sun introduced
System.nanoTime() in 1.5 which provides civilized timing information, so we can
use that instead of sun.misc.Perf which is unavailable in an applet sandbox. We
will need to go in and try to cope as best we can with currentTimeMillis() if
we want to support unsigned play in JDK 1.4 or earlier. We'll do that later.


git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@231 ed5b42cb-e716-0410-a449-f6a68f950b19
This commit is contained in:
Michael Bayne
2007-05-09 19:22:10 +00:00
parent ef35b37648
commit 0024a02067
4 changed files with 96 additions and 44 deletions
+22 -12
View File
@@ -51,7 +51,7 @@ import com.samskivert.util.RunAnywhere;
import com.samskivert.util.StringUtil;
import com.threerings.media.timer.MediaTimer;
import com.threerings.media.timer.SystemMediaTimer;
import com.threerings.media.timer.MillisTimer;
import com.threerings.media.util.TrailingAverage;
import com.threerings.util.unsafe.Unsafe;
@@ -127,28 +127,35 @@ public abstract class FrameManager
}
/**
* Creates a frame manager that will use a {@link SystemMediaTimer} to obtain timing
* information, which is available on every platform, but returns inaccurate time stamps on
* many platforms.
* Creates a frame manager that will try to use a high resolution timer for timing but will
* fall back to {@link MillisTimer}, which is available on every platform, but returns
* inaccurate time stamps on many platforms.
*
* @see #newInstance(ManagedRoot, MediaTimer)
*/
public static FrameManager newInstance (ManagedRoot root)
{
// first try creating a PerfTimer which is the best if we're using JDK1.4.2
MediaTimer timer = null;
try {
timer = (MediaTimer)Class.forName(PERF_TIMER).newInstance();
} catch (Throwable t) {
Log.info("Can't use PerfTimer (" + t + ") reverting to " +
for (String timerClass : PERF_TIMERS) {
try {
timer = (MediaTimer)Class.forName(timerClass).newInstance();
break;
} catch (Throwable t) {
t.printStackTrace(System.err);
// try the next one
}
}
if (timer == null) {
Log.info("Can't use high performance timer, reverting to " +
"System.currentTimeMillis() based timer.");
timer = new SystemMediaTimer();
timer = new MillisTimer();
}
return newInstance(root, timer);
}
/**
* Constructs a frame manager that will do its rendering to the supplied root.
* Constructs a frame manager that will do its rendering to the supplied root and use the
* supplied media timer for timing information.
*/
public static FrameManager newInstance (ManagedRoot root, MediaTimer timer)
{
@@ -751,5 +758,8 @@ public abstract class FrameManager
"narya.media.fps_display", MediaPrefs.config, false);
/** The name of the high-performance timer class we attempt to load. */
protected static final String PERF_TIMER = "com.threerings.media.timer.PerfTimer";
protected static final String[] PERF_TIMERS = {
"com.threerings.media.timer.NanoTimer",
"com.threerings.media.timer.PerfTimer",
};
}
@@ -22,20 +22,18 @@
package com.threerings.media.timer;
/**
* Implements the {@link MediaTimer} interface using {@link
* System#currentTimeMillis} to obtain timing information.
* Implements the {@link MediaTimer} interface using {@link System#currentTimeMillis} to obtain
* timing information.
*
* <p> <em>Note:</em> {@link System#currentTimeMillis} is notoriously
* inaccurate on different platforms. See <a
* href="http://developer.java.sun.com/developer/bugParade/bugs/4486109.html">
* <p> <em>Note:</em> {@link System#currentTimeMillis} is notoriously inaccurate on different
* platforms. See <a href="http://developer.java.sun.com/developer/bugParade/bugs/4486109.html">
* bug report 4486109</a> for more information.
*
* <p> <em>Also note:</em> clock drift on Windows XP is especially
* pronounced and is exacerbated by the fact that WinXP periodically
* resyncs the system clock with the hardware clock, causing discontinuous
* jumps in the progression of time (usually backwards in time).
* <p> <em>Also note:</em> clock drift on Windows XP is especially pronounced and is exacerbated by
* the fact that WinXP periodically resyncs the system clock with the hardware clock, causing
* discontinuous jumps in the progression of time (usually backwards in time).
*/
public class SystemMediaTimer implements MediaTimer
public class MillisTimer implements MediaTimer
{
// documentation inherited from interface
public void reset ()
@@ -0,0 +1,50 @@
//
// $Id$
//
// Nenya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/nenya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.media.timer;
/**
* Uses the {@link System#nanoTime} method introduced in 1.5 to try to obtain higher resolution
* timestamps than those available via {@link System#currentTimeMillis}.
*/
public class NanoTimer implements MediaTimer
{
// documentation inherited from interface
public void reset ()
{
_resetStamp = System.nanoTime();
}
// documentation inherited from interface
public long getElapsedMillis ()
{
return (System.nanoTime() - _resetStamp) / 1000000L;
}
// documentation inherited from interface
public long getElapsedMicros ()
{
return (System.nanoTime() - _resetStamp) / 1000L;
}
/** The time at which this timer was last reset. */
protected long _resetStamp = System.nanoTime();
}
@@ -25,42 +25,36 @@ import java.util.HashMap;
import com.threerings.media.Log;
import com.threerings.media.timer.MediaTimer;
import com.threerings.media.timer.SystemMediaTimer;
import com.threerings.media.timer.NanoTimer;
/**
* Provides a simple mechanism for monitoring the number of times an
* action takes place within a certain time period.
* Provides a simple mechanism for monitoring the number of times an action takes place within a
* certain time period.
*
* <p> The action being tracked should be registered with a suitable name
* via {@link #register}, and {@link #tick} should be called each time the
* action is performed.
* <p> The action being tracked should be registered with a suitable name via {@link #register},
* and {@link #tick} should be called each time the action is performed.
*
* <p> Whenever {@link #tick} is called and the checkpoint time interval
* has elapsed since the last checkpoint (if any), the observer will be
* notified to that effect by a call to {@link
* <p> Whenever {@link #tick} is called and the checkpoint time interval has elapsed since the last
* checkpoint (if any), the observer will be notified to that effect by a call to {@link
* PerformanceObserver#checkpoint}.
*
* <p> Note that this is <em>not</em> intended to be used as an
* industrial-strength profiling or performance monitoring tool. The
* checkpoint time interval granularity is in milliseconds, not
* microseconds, and the observer's <code>checkpoint()</code> method will
* never be called until/unless a subsequent call to {@link #tick} is made
* after the requested number of milliseconds have passed since the last
* checkpoint.
* <p> Note that this is <em>not</em> intended to be used as an industrial-strength profiling or
* performance monitoring tool. The checkpoint time interval granularity is in milliseconds, not
* microseconds, and the observer's <code>checkpoint()</code> method will never be called
* until/unless a subsequent call to {@link #tick} is made after the requested number of
* milliseconds have passed since the last checkpoint.
*/
public class PerformanceMonitor
{
/**
* Register a new action with an observer, the action name, and
* the milliseconds to wait between checkpointing the action's
* performance.
* Register a new action with an observer, the action name, and the milliseconds to wait
* between checkpointing the action's performance.
*
* @param obs the action observer.
* @param name the action name.
* @param delta the milliseconds between checkpoints.
*/
public static void register (PerformanceObserver obs, String name,
long delta)
public static void register (PerformanceObserver obs, String name, long delta)
{
// get the observer's action hashtable
HashMap actions = (HashMap)_observers.get(obs);
@@ -152,7 +146,7 @@ public class PerformanceMonitor
protected static HashMap _observers = new HashMap();
/** Used to obtain high resolution time stamps. */
protected static MediaTimer _timer = new SystemMediaTimer();
protected static MediaTimer _timer = new NanoTimer();
}
/**