diff --git a/src/java/com/threerings/media/FrameManager.java b/src/java/com/threerings/media/FrameManager.java index 94a30116..9cf8cff4 100644 --- a/src/java/com/threerings/media/FrameManager.java +++ b/src/java/com/threerings/media/FrameManager.java @@ -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", + }; } diff --git a/src/java/com/threerings/media/timer/SystemMediaTimer.java b/src/java/com/threerings/media/timer/MillisTimer.java similarity index 76% rename from src/java/com/threerings/media/timer/SystemMediaTimer.java rename to src/java/com/threerings/media/timer/MillisTimer.java index 2a908d41..6e5bca16 100644 --- a/src/java/com/threerings/media/timer/SystemMediaTimer.java +++ b/src/java/com/threerings/media/timer/MillisTimer.java @@ -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. * - *
Note: {@link System#currentTimeMillis} is notoriously
- * inaccurate on different platforms. See
+ * Note: {@link System#currentTimeMillis} is notoriously inaccurate on different
+ * platforms. See
* bug report 4486109 for more information.
*
- * Also note: 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).
+ * Also note: 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 ()
diff --git a/src/java/com/threerings/media/timer/NanoTimer.java b/src/java/com/threerings/media/timer/NanoTimer.java
new file mode 100644
index 00000000..dd35091a
--- /dev/null
+++ b/src/java/com/threerings/media/timer/NanoTimer.java
@@ -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();
+}
diff --git a/src/java/com/threerings/media/util/PerformanceMonitor.java b/src/java/com/threerings/media/util/PerformanceMonitor.java
index a8c67346..fee962fb 100644
--- a/src/java/com/threerings/media/util/PerformanceMonitor.java
+++ b/src/java/com/threerings/media/util/PerformanceMonitor.java
@@ -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.
*
- * 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.
+ * 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.
*
- * 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
+ * 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}.
*
- * Note that this is not 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 Note that this is not 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 checkpoint() 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.
+ * checkpoint() 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();
}
/**