290 lines
13 KiB
HTML
290 lines
13 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head>
|
|
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
|
|
|
|
<title>EARandom</title>
|
|
<link type="text/css" rel="stylesheet" href="UTFDoc.css">
|
|
<meta name="author" content="Paul Pedriana">
|
|
</head>
|
|
<body bgcolor="#FFFFFF">
|
|
<h1>EAStopwatch</h1>
|
|
|
|
<h2>Introduction</h2>
|
|
<p>EAStopwatch provides timing facilities for use in game development. It provides
|
|
two C++ classes:</p>
|
|
<blockquote>
|
|
<table width="100%" border="1">
|
|
<tr>
|
|
<td>Stopwatch</td>
|
|
<td>A general-purpose timer</td>
|
|
</tr>
|
|
<tr>
|
|
<td>LimitStopwatch</td>
|
|
<td>A special-purpose countdown-style timer</td>
|
|
</tr>
|
|
</table>
|
|
</blockquote>
|
|
<p>Stopwatch acts much like and classic hand-held stopwatch or like the stopwatch
|
|
found on sports watches. It has additional flexibility, such as the ability
|
|
to set an elapsed time to any value.</p>
|
|
<p>LimitStopwatch is a stopwatch which simply tells you if a given amount of time
|
|
has passed. You can accomplish this same functionality by polling a Stopwatch,
|
|
but LimitStopwatch is more efficient.</p>
|
|
<h2>Important things to remember</h2>
|
|
<ul>
|
|
<li> You won't get very accurate timings if you use a millisecond stopwatch
|
|
repeatedly to time tiny sections of code that take only nanoseconds.</li>
|
|
<li>You can start and stop a stopwatch repeatedly and it will do the right thing,
|
|
which is sum up the times during which it was running.</li>
|
|
<li>Timing CPU cycles (clock ticks) accurately can be hard if you are trying
|
|
to time very small pieces of code. Pipeline stalls and memory stalls can result
|
|
in highly variable results.</li>
|
|
<li>A running stopwatch consumes no resources (CPU cycles nor memory) during
|
|
its existence nor while it is running.</li>
|
|
<li>You don't have to stop a stopwatch that is running; it doesn't take up CPU
|
|
time to be running. It is not an error to not stop a stopwatch.</li>
|
|
<li>There is a distinction between stopwatch cycles and CPU-based cycles. While
|
|
it may be the case that the stopwatch uses a CPU cycle counter as its basis,
|
|
this also may not be the case. In fact, using a CPU cycles counter as the
|
|
basis for a stopwatch is often a dangerous thing to do because processors
|
|
these days will sometimes switch frequencies on the fly. </li>
|
|
<li>You don't have to worry about multi-processor issues unless you are running
|
|
on a desktop platform such as Windows. In the case of such platforms, you
|
|
only need to worry about such issues if you happen to define EA_STOPWATCH_FORCE_CPU_CYCLE_USAGE = 1.</li>
|
|
<li>You can call safely GetElapsedTime while the stopwatch is running; it will
|
|
simply return the currently elapsed time.</li>
|
|
<li>The construction and destruction instances of Stopwatch is fast; don't worry
|
|
about it. Similarly, a Stopwatch instance is small in size.</li>
|
|
</ul>
|
|
<h2>Example usage </h2>
|
|
<p>EAStopwatch is very easy to use, though curiously its simplicity actually confuses
|
|
some users familiar with more cumbersome alternatives.</p>
|
|
<p>Basic usage:</p>
|
|
<pre class="code-example">Stopwatch stopwatch(Stopwatch::kUnitsMilliseconds);
|
|
|
|
stopwatch.Start();
|
|
DoSomethingThatYouWantToMeasure();
|
|
printf("Time to do something: %u.\n", stopwatch.GetElapsedTime());</pre>
|
|
Example of stopwatch reuse (via Restart):
|
|
<pre class="code-example">Stopwatch stopwatch(Stopwatch::kUnitsCycles, true); // Note that 'true' tells the timer to auto-start here.
|
|
|
|
DoSomethingSmall();
|
|
printf("Time to do something small: %u.\n", stopwatch.GetElapsedTime());
|
|
|
|
stopwatch.Restart();
|
|
DoSomethingElseSmall();
|
|
printf("Time to do something else small: %d.\n", stopwatch.GetElapsedTime());</pre>
|
|
Example of SetElapsedTime usage.
|
|
<pre class="code-example">Stopwatch stopwatch(Stopwatch::kUnitsMilliseconds);
|
|
|
|
stopwatch.SetElapsedTime(100); // Give the stopwatch a "100 ms head start."
|
|
stopwatch.Start();
|
|
printf("This should print out 100 (or maybe 101): %u.\n", stopwatch.GetElapsedTime());</pre>
|
|
<p>Example of LimitStopwatch usage:</p>
|
|
<pre class="code-example">LimitStopwatch limitStopwatch(Stopwatch::kUnitsMilliseconds, 1000, true);
|
|
|
|
while(!limitStopwatch.IsTimeUp())
|
|
printf("waiting\n"); </pre>
|
|
<h2>Don't do this!</h2>
|
|
<p> It seems that quite often people unfamiliar with a C++ stopwatch tend to revert
|
|
away from using the stopwatch as it was designed and try to do timings manually,
|
|
like shown below. The code below is more complicated than it needs to be and
|
|
is less precise than it can be, as the high internal resolution of the stopwatch
|
|
is lost when using it like this. </p>
|
|
<pre class="code-example"><font color="#CC0000">Stopwatch stopwatch(Stopwatch::kUnitsMilliseconds);
|
|
|
|
stopwatch.Start();
|
|
uint64_t timeStart = stopwatch.GetElapsedTime();
|
|
DoSomething();
|
|
uint64_t timeElapsed = stopwatch.GetElapsedTime() - time;</font>
|
|
</pre>
|
|
<h2>Interface </h2>
|
|
<p>Stopwatch</p>
|
|
<pre class="code-example">class Stopwatch
|
|
{
|
|
public:
|
|
<span class="code-example-comment"> /// Units
|
|
/// Defines common timing units plus a user-definable set of units.
|
|
</span> enum Units
|
|
{
|
|
kUnitsCycles = 0, <font color="#999999">/// Stopwatch clock ticks. </font>
|
|
kUnitsCPUCycles = 1, <font color="#999999">/// CPU clock ticks (or similar equivalent for the platform).</font>
|
|
kUnitsNanoseconds = 2, <font color="#999999">/// Count in nanoseconds.</font>
|
|
kUnitsMicroseconds = 3, <font color="#999999">/// Count in microseconds.</font>
|
|
kUnitsMilliseconds = 4, <font color="#999999">/// Count in milliseconds.</font>
|
|
kUnitsSeconds = 5, <font color="#999999">/// Count in seconds.</font>
|
|
kUnitsMinutes = 6, <font color="#999999">/// Count in minutes.</font>
|
|
kUnitsUserDefined = 1000 <font color="#999999">/// User defined units (animation frames, video vertical retrace, etc.).</font>
|
|
};
|
|
|
|
public:
|
|
<span class="code-example-comment"> /// Stopwatch
|
|
/// Constructor for Stopwatch, allows user to specify units.
|
|
/// If units are kUnitsUserDefined, you'll need to either subclass
|
|
/// Stopwatch and implement GetUserDefinedStopwatchCycle or call
|
|
/// SetUserDefinedUnitsToStopwatchCyclesRatio in order to allow it
|
|
/// to know how to convert units.
|
|
</span> explicit Stopwatch(int nUnits = kUnitsCycles, bool bStartImmediately = false);
|
|
|
|
<span class="code-example-comment"> /// Stopwatch
|
|
/// Copy constructor.
|
|
</span> Stopwatch(const Stopwatch& stopwatch);
|
|
|
|
<span class="code-example-comment"> /// ~Stopwatch
|
|
/// Destructor.
|
|
</span> ~Stopwatch();
|
|
|
|
<span class="code-example-comment"> /// operator=
|
|
/// Assignment operator.
|
|
</span> Stopwatch& operator=(const Stopwatch& stopwatch);
|
|
|
|
<span class="code-example-comment"> /// GetUnits
|
|
/// Gets the current units. Returns one of enum Units or kUnitsUserDefined+.
|
|
</span> int GetUnits() const;
|
|
|
|
<span class="code-example-comment"> /// SetUnits
|
|
/// Sets the current units. One of enum Units or kUnitsUserDefined+.
|
|
</span> void SetUnits(int nUnits);
|
|
|
|
<span class="code-example-comment"> /// Start
|
|
/// Starts the stopwatch. Continues where it was last stopped.
|
|
/// Does nothing if the stopwatch is already started.
|
|
</span> void Start();
|
|
|
|
<span class="code-example-comment"> /// Stop
|
|
/// Stops the stopwatch it it was running and retaines the elasped time.
|
|
</span> void Stop();
|
|
|
|
<span class="code-example-comment"> /// Reset
|
|
/// Stops the stopwatch if it was running and clears the elapsed time.
|
|
</span> void Reset();
|
|
|
|
<span class="code-example-comment"> /// Restart
|
|
/// Clears the elapsed time and starts the stopwatch if it was not
|
|
/// already running. Has the same effect as Reset(), Start().
|
|
</span> void Restart();
|
|
|
|
<span class="code-example-comment"> /// IsRunning
|
|
/// Returns true if the stopwatch is running.
|
|
</span> bool IsRunning() const;
|
|
|
|
<span class="code-example-comment"> /// GetElapsedTime
|
|
/// Gets the elapsed time, which properly takes into account any
|
|
/// intervening stops and starts. Works properly whether the stopwatch
|
|
/// is running or not.
|
|
</span> uint64_t GetElapsedTime() const;
|
|
|
|
<span class="code-example-comment"> /// SetElapsedTime
|
|
/// Allows you to set the elapsed time. Erases whatever is current.
|
|
/// Works properly whether the stopwatch is running or not.
|
|
</span> void SetElapsedTime(uint64_t nElapsedTime);
|
|
|
|
<span class="code-example-comment"> /// GetElapsedTimeFloat
|
|
/// Float version, which is useful for counting fractions of
|
|
/// seconds or possibly milliseconds.
|
|
</span> float GetElapsedTimeFloat() const;
|
|
|
|
<span class="code-example-comment"> /// SetElapsedTimeFloat
|
|
/// Allows you to set the elapsed time. Erases whatever is current.
|
|
/// Works properly whether the stopwatch is running or not.
|
|
</span> void SetElapsedTimeFloat(float fElapsedTime);
|
|
|
|
<span class="code-example-comment"> /// SetCyclesPerUnit
|
|
/// Allows the user to manually override the frequency of the
|
|
/// timer.
|
|
</span> void SetCyclesPerUnit(float fCyclesPerUnit);
|
|
|
|
<span class="code-example-comment"> /// GetCyclesPerUnit
|
|
/// Returns the value number of cycles per unit. If the user
|
|
/// set a manual value via SetCyclesPerUnit, this function returns
|
|
/// that value.
|
|
</span> float GetCyclesPerUnit() const;
|
|
|
|
<span class="code-example-comment"> /// GetStopwatchCycle
|
|
/// Gets the current stopwatch cycle on the current machine.
|
|
/// Note that a stopwatch cyle may or may not be the same thing
|
|
/// as a CPU cycle. We provide the distinction between stopwatch
|
|
/// cycles and CPU cycles in order to accomodate platforms (e.g.
|
|
/// desktop platforms) in which CPU cycle counting is unreliable.
|
|
</span> static uint64_t GetStopwatchCycle();
|
|
|
|
<span class="code-example-comment"> /// GetStopwatchFrequency
|
|
/// Note that the stopwatch freqency may or may not be the same thing
|
|
/// as the CPU freqency. We provide the distinction between stopwatch
|
|
/// cycles and CPU cycles in order to accomodate platforms (e.g.
|
|
/// desktop platforms) in which CPU cycle counting is unreliable.
|
|
</span> static uint64_t GetStopwatchFrequency();
|
|
|
|
<span class="code-example-comment"> /// GetUnitsPerStopwatchCycle
|
|
/// Returns the number of stopwatch cycles per the given unit.
|
|
/// If the unit is seconds, the return value would be the frequency of
|
|
/// the stopwatch timer and thus be the same value as returned by
|
|
/// GetStopwatchFrequency().
|
|
</span> static float GetUnitsPerStopwatchCycle(Units units);
|
|
|
|
<span class="code-example-comment"> /// GetCPUCycle
|
|
/// Gets the current CPU-based timer cycle on the current processor
|
|
/// (if in a multiprocessor system). Note that this doesn't necessarily
|
|
/// get the actual machine CPU clock cycle; rather it returns the
|
|
/// CPU-based timer cycle. One some platforms the CPU-based timer is
|
|
/// a 1:1 relation to the CPU clock, while on others it is some multiple
|
|
/// of it.
|
|
</span> static uint64_t GetCPUCycle();
|
|
|
|
<span class="code-example-comment"> /// GetCPUFrequency
|
|
/// Gets the frequency of the CPU-based timer. Note that this doesn't
|
|
/// necessarily get the actual machine CPU clock frequency; rather it returns
|
|
/// the CPU-based timer frequency. One some platforms the CPU-based timer is
|
|
/// a 1:1 relation to the CPU clock, while on others it is some multiple of it.
|
|
</span> static uint64_t GetCPUFrequency();
|
|
|
|
<span class="code-example-comment"> /// GetUnitsPerCPUCycle
|
|
/// Returns the number of CPU cycles per the given unit.
|
|
/// If the unit is seconds, the return value would be the frequency
|
|
/// of the CPU-based timer.
|
|
</span> static float GetUnitsPerCPUCycle(Units units);
|
|
};
|
|
</pre>
|
|
<p>LimitStopwatch</p>
|
|
<pre class="code-example">class LimitStopwatch : public Stopwatch
|
|
{
|
|
public:
|
|
<span class="code-example-comment"> /// LimitStopwatch
|
|
/// Constructor
|
|
</span> LimitStopwatch(int nUnits = kUnitsCycles, uint32_t nLimit = 0, bool bStartImmediately = false);
|
|
|
|
<span class="code-example-comment"> /// SetTimeLimit
|
|
/// Sets the time limit and lets you start the stopwatch at the same time.
|
|
</span> void SetTimeLimit(uint32_t nLimit, bool bStartImmediately = false);
|
|
|
|
<span class="code-example-comment"> /// IsTimeUp
|
|
/// Returns true if the limit has been reached. Highly efficient.
|
|
</span> bool IsTimeUp();
|
|
|
|
<span class="code-example-comment"> /// GetTimeRemaining
|
|
/// More expensive than IsTimeUp, as it returns a value.
|
|
</span> int64_t GetTimeRemaining();
|
|
|
|
<span class="code-example-comment"> /// GetTimeRemainingFloat
|
|
/// More expensive than IsTimeUp, as it returns a value.
|
|
</span> float GetTimeRemainingFloat();
|
|
};</pre>
|
|
<hr>
|
|
<p> </p>
|
|
<p> </p>
|
|
<p> </p>
|
|
<p> </p>
|
|
<p> </p>
|
|
<p> </p>
|
|
<p> </p>
|
|
<p> </p>
|
|
<p> </p>
|
|
<p> </p>
|
|
<p> </p>
|
|
<p> </p>
|
|
<p> </p>
|
|
<p> </p>
|
|
</body></html>
|
|
|
|
|
|
|