<?xml version="1.0"?>
<rss version="2.0">
	<channel>
		<title>I need a high resolution timer with QPC</title>
		<link>http://www.allegro.cc/forums/view/589730</link>
		<description>Allegro.cc Forum Thread</description>
		<webMaster>matthew@allegro.cc (Matthew Leverton)</webMaster>
		<lastBuildDate>Fri, 26 Jan 2007 05:23:30 +0000</lastBuildDate>
	</channel>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>I looked at this <a href="http://www.allegro.cc/forums/thread/585140">thread</a>, and I found a lot of timer routines using QPC but there is no explanation about how to use these routines in the main loop.<br />My game must run at 60FPS, with options for reducing CPU ussage.<br />Can someone post a little example program using high resolution timer routines, and how to use them in the main loop?<br />Thanks in advance.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Paul whoknows)</author>
		<pubDate>Fri, 26 Jan 2007 01:38:15 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>You should not use high resolution timers in main loops.  They should be used for high precision timing - in games, mainly profiling.  For game logic, use lower precision time functions, like timeGetTime() (returns milliseconds) on win32.  </p><p>The reason is because most high resolution timing functions have... issues...<br />edit: updated RDTSC problems description<br />RDTSC: reports incorrect results on many computers (mostly dual-core systems),  crashes on 486s and earlier, and the units change at run time due to power-management issues<br />(note: dual-core issue can be fixed for dual-core AMDs with a utility downloadable from their website)<br />QPC: slow; yields incorrect results on many computers; win32 only<br />gettimeofday: changes when system time changed; not sure what underlieing method it uses; many yield errors on some computers</p><p>And anyway, sub-millisecond precision for regular user interactions is pointless.  </p><div class="source-code"><div class="toolbar"></div><div class="inner"><table width="100%"><tbody><tr><td class="number">1</td><td>  <span class="k1">int</span> next_tick_ms <span class="k3">=</span> get_time_ms<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">2</td><td>  <span class="k1">int</span> ticks_since_last_frame <span class="k3">=</span> <span class="n">0</span><span class="k2">;</span></td></tr><tr><td class="number">3</td><td>  <span class="k1">int</span> last_frame_ms <span class="k3">=</span> <span class="n">0</span><span class="k2">;</span></td></tr><tr><td class="number">4</td><td>  <span class="k1">while</span> <span class="k2">(</span><span class="k3">!</span>quitting<span class="k2">)</span> <span class="k2">{</span></td></tr><tr><td class="number">5</td><td>    <span class="k1">bool</span> do_frame <span class="k3">=</span> <span class="k1">false</span><span class="k2">;</span></td></tr><tr><td class="number">6</td><td>    <span class="k1">int</span> current_ms <span class="k3">=</span> get_time_ms<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">7</td><td>    <span class="k1">if</span> <span class="k2">(</span>current_ms <span class="k3">&gt;</span><span class="k3">=</span> next_tick_ms<span class="k2">)</span> <span class="k2">{</span></td></tr><tr><td class="number">8</td><td>      calculate_physics<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">9</td><td>      next_tick_ms <span class="k3">+</span><span class="k3">=</span> ms_per_tick<span class="k2">;</span></td></tr><tr><td class="number">10</td><td>      <span class="c">//we're too far behind</span></td></tr><tr><td class="number">11</td><td>      <span class="k1">if</span> <span class="k2">(</span>next_tick_ms <span class="k3">&lt;</span> current_ms <span class="k3">-</span> <span class="n">20</span><span class="k2">)</span> next_tick_ms <span class="k3">=</span> current_ms <span class="k3">-</span> <span class="n">20</span><span class="k2">;</span></td></tr><tr><td class="number">12</td><td>      ticks_since_last_frame<span class="k3">+</span><span class="k3">+</span><span class="k2">;</span></td></tr><tr><td class="number">13</td><td>      <span class="k1">if</span> <span class="k2">(</span>ticks_since_last_frame <span class="k3">&gt;</span> <span class="n">5</span><span class="k2">)</span> do_frame <span class="k3">=</span> <span class="k1">true</span><span class="k2">;</span></td></tr><tr><td class="number">14</td><td>    <span class="k2">}</span></td></tr><tr><td class="number">15</td><td>    <span class="k1">else</span> <span class="k2">{</span></td></tr><tr><td class="number">16</td><td>      <span class="k1">if</span> <span class="k2">(</span>ticks_since_last_frame <span class="k3">|</span><span class="k3">|</span> current_ms <span class="k3">&gt;</span> last_frame_ms <span class="k3">+</span> <span class="n">100</span><span class="k2">)</span></td></tr><tr><td class="number">17</td><td>        do_frame <span class="k3">=</span> <span class="k1">true</span><span class="k2">;</span></td></tr><tr><td class="number">18</td><td>    <span class="k2">}</span></td></tr><tr><td class="number">19</td><td>    <span class="k1">if</span> <span class="k2">(</span>do_frame<span class="k2">)</span> <span class="k2">{</span></td></tr><tr><td class="number">20</td><td>      render_frame<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">21</td><td>      ticks_sicne_last_frame <span class="k3">=</span> <span class="n">0</span><span class="k2">;</span></td></tr><tr><td class="number">22</td><td>      last_frame_ms <span class="k3">=</span> current_ms<span class="k2">;</span></td></tr><tr><td class="number">23</td><td>    <span class="k2">}</span></td></tr><tr><td class="number">24</td><td>  <span class="k2">}</span></td></tr></tbody></table></div></div><p>
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (orz)</author>
		<pubDate>Fri, 26 Jan 2007 02:10:08 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
QPC: slow; yields incorrect results on many computers&#8230;<br />gettimeofday: &#8230;many yield errors on some computers
</p></div></div><p>I&#39;m going to need you to prove this.</p><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
And anyway, sub-millisecond precision for regular user interactions is pointless.
</p></div></div><p>But it leads to more accurate simulation of physics and other game functions.</p><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
RDTSC: crashes on 486s and earlier&#8230;<br />gettimeofday: changes when system time changed
</p></div></div><p>These are completely non-issues <img src="http://www.allegro.cc/forums/smileys/rolleyes.gif" alt="::)" />
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (CGamesPlay)</author>
		<pubDate>Fri, 26 Jan 2007 02:19:29 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>
Orz: Wrong I&#39;m afraid.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Richard Phipps)</author>
		<pubDate>Fri, 26 Jan 2007 02:21:29 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
I&#39;m going to need you to prove this.
</p></div></div><p>
Gimme a few minutes to come up with references.  Only some of the problems are documented on the web though.  I have personally seen both QPC and RDTSC fail.  I&#39;ve never seen gettimeofday() fail, but that&#39;s because I primarily use windows.  </p><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
But it leads to more accurate simulation of physics and other game functions.
</p></div></div><p>

Timers don&#39;t make physics calculations more precise; they just make physics more closely synchronized with real time.  However, there&#39;s not point in synchronizing them more accurately with real time than the output devices (or the human perceiving them, assuming you&#39;re outputting to a human) can track.  For instance, CRTs tend to only do a retrace every 8-20 milliseconds, rendering sub-millisecond synchronization for animations displayed on CRTs pointless.  LCDs have different issues, which I&#39;m less familiar with the precise numbers for, but they have multiple sources of timing issues; data rates for the digital cables and update rates for the LCs themselves.  Either issue alone is enough to render sub-millisecond timing irrelevant for synchronizing LCD output.  The human eye also introduces timing limitations, but these are harder to quantify due to variations depending upon which portion of the eye you are using (peripheral vision etc), individual variation between eyes and brains, and the nature of the visual stimuli.  <br />Sound is a different issue of course, but one I know less about.  However, it&#39;s usually buffered for several milliseconds in advance even in games, and much of the timing there is handled by the sound hardware and drivers.  </p><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
Orz: Wrong I&#39;m afraid.
</p></div></div><p>
About what?  Be more specific.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (orz)</author>
		<pubDate>Fri, 26 Jan 2007 02:40:30 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>Basically, I have tested high resolution timers using QPC on windows on many different PC&#39;s for my games, as has Mike Welch who I have worked with on Neon Wars. The results are consistently better than lower precision timing results in terms of smoothness and accuracy.</p><p>So, I am speaking from a practical and pretty experienced point of view here.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Richard Phipps)</author>
		<pubDate>Fri, 26 Jan 2007 02:45:25 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
Timers don&#39;t make physics calculations more precise; they just make physics more closely synchronized with real time.
</p></div></div><p>If you&#39;re using a delta-time method, you are basically using a Riemann sum to compute the position based off the velocity and acceleration. By using smaller deltas (smaller rectangles), your result is more accurate. Imagine: how accurate (*not* how smooth would it appear on screen) would the movements be if you used a 1-second timer?
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (CGamesPlay)</author>
		<pubDate>Fri, 26 Jan 2007 02:52:34 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>You are totally high jacking the thread.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (GullRaDriel)</author>
		<pubDate>Fri, 26 Jan 2007 03:04:37 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
You are totally high jacking the thread.
</p></div></div><p>Oh, you&#39;re right. I sorta forgot about the question when orz posted his example of how to do it. Did you just add the example of how to use KittyCat&#39;s code, or was that there? Either way: Paul: read <a href="http://www.allegro.cc/forums/thread/585140">this</a>, especially where he says &quot;How to use KC&#39;s routines:&quot;
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (CGamesPlay)</author>
		<pubDate>Fri, 26 Jan 2007 03:12:00 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>The &quot;proof&quot; I promised:</p><p>(also, of course, the other reason I forgot to list originally: RDTSC is based upon processor frequency, which changes at run time due to power management features)</p><p>personal experience: my dual-core AMD had neither QPC nor RDTSC work correctly originally.  Using KB896256 and another microsoft patch I can&#39;t find at the moment fixed QPC but did not fix RDTSC (contrary to the claims of the docs for the hotfixes IIRC).  Using AMDs utility may have fixed RDTSC, but I haven&#39;t tested it enough to tell yet (only installed yesterday).  </p><p>2nd-hand experience: Shizmoo Games (<a href="http://www.shizmoo.com/">http://www.shizmoo.com/</a>) told me in aproximately 2001 (my memory is a little fuzzy on the exact date) that they had switched from using QPC to using lower resolution timing functions because a significant numbers of their users had some flaw in their motherboards chipset that caused QPC to return bizarre results but left other timing methods functional.  </p><p>documentation for dual-core &amp;| multi-CPU issues on the web from major companies:</p><p><a href="http://support.microsoft.com/kb/896256">http://support.microsoft.com/kb/896256</a><br />Supposedly fixes issues with QPC and/or RDTSC; however, it did not fix RDTSC on my dual-core AMD.  </p><p><a href="http://support.microsoft.com/kb/909944">http://support.microsoft.com/kb/909944</a></p><p><a href="http://www.amd.com/us-en/Processors/TechnicalResources/0,,30_182_871_9706,00.html">http://www.amd.com/us-en/Processors/TechnicalResources/0,,30_182_871_9706,00.html</a><br />Supposedly fixes issues with RDTSC; working so far for me, but only had it installed for a few hours now.  Reports of crashes if both this and the above microsoft hotfix are installed. </p><p>documentation on the web from less well-known sources:</p><p><a href="http://www.virtualdub.org/blog/pivot/entry.php?id=106">http://www.virtualdub.org/blog/pivot/entry.php?id=106</a><br />note the headline: Beware of QueryPerformanceCounter()</p><p><a href="http://www.gamedev.net/reference/programming/features/timing/">http://www.gamedev.net/reference/programming/features/timing/</a><br />in particular, note:
</p><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
QPC has several issues:</p><p>   1. Hardware bug: race condition when updating parts of the register? I have seen speculation to this effect more than once. ([qpc_race])<br />   2. It jumps forward several hundred ms sometimes under heavy PCI bus load. ([qpc_jump])<br />   3. The PIT is slow to read - it requires sending a latch command, and 2 8-bit reads, for a total of ~3 µs.<br />   4. When using the TSC, it is documented to return different values depending on which processor is running the code, on some (buggy) systems.
</p></div></div><p>

<a href="http://forums.seriouszone.com/showthread.php?t=44791&amp;page=5">http://forums.seriouszone.com/showthread.php?t=44791&amp;page=5</a><br />edit: note: that&#39;s a Croteam (developers of Serious Sam) developer posting there, talking about RDTSC (he likes QPC though)</p><p>Will update this to handle other posts while I was googling for that stuff</p><p>edit:
</p><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
If you&#39;re using a delta-time method, you are basically using a Riemann sum to compute the position based off the velocity and acceleration. By using smaller deltas (smaller rectangles), your result is more accurate. Imagine: how accurate (*not* how smooth would it appear on screen) would the movements be if you used a 1-second timer?
</p></div></div><p>
You&#39;re equating physics synchronization with physics accuracy.  If you want more accurate physics on the same time measurement method while using a delta-based time, it&#39;s as simple as using two deltas of half the size.  Time gets clumped, but physics accuracy is not lost.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (orz)</author>
		<pubDate>Fri, 26 Jan 2007 03:16:18 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>
I&#39;ll be honest. I don&#39;t care about all those references.. In my experience when testing on many different setups, it&#39;s the best choice. <img src="http://www.allegro.cc/forums/smileys/smiley.gif" alt=":)" />
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Richard Phipps)</author>
		<pubDate>Fri, 26 Jan 2007 03:26:26 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
I don&#39;t care about all those references..
</p></div></div><p>I do. I don&#39;t know I quite trust the stuff about QPF, but the RDTSC references make sense. Actually, I&#39;m going to do some experimentation when I get home: the original UT used RDTSC in its code, and it runs too fast on many systems I&#39;ve played it on. I will disable CPU clock scaling and see what I get.</p><p>[append]<br />That&#39;s the first comment in the virtual dub blog post <img src="http://www.allegro.cc/forums/smileys/rolleyes.gif" alt="::)" /></p><p>Okay, so the best high-frequency counter is timeGetTime and gettimeofday, it seems. Yes, orz?
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (CGamesPlay)</author>
		<pubDate>Fri, 26 Jan 2007 03:40:07 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>CGamesPlay: if you QueryPerformanceFrequency each time you get the timer it is good with frequency scaled processors
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (GullRaDriel)</author>
		<pubDate>Fri, 26 Jan 2007 03:45:58 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>Gull: I&#39;m sure that solves the CPU scaling problem, but not the others...</p><p>Personally, I like the timeGetTime/gettimeofday method. It&#39;s easier, after all <img src="http://www.allegro.cc/forums/smileys/smiley.gif" alt=":)" />
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (CGamesPlay)</author>
		<pubDate>Fri, 26 Jan 2007 03:50:06 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>
What is the precision of gettimeofday? If it is too low it won&#39;t look very good even if it is more reliable.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Richard Phipps)</author>
		<pubDate>Fri, 26 Jan 2007 03:53:33 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>It&#39;s microseconds. <img src="http://www.allegro.cc/forums/smileys/tongue.gif" alt=":P" />
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (CGamesPlay)</author>
		<pubDate>Fri, 26 Jan 2007 03:55:44 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>
Ok.... <img src="http://www.allegro.cc/forums/smileys/rolleyes.gif" alt="::)" />
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Richard Phipps)</author>
		<pubDate>Fri, 26 Jan 2007 03:59:39 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>I use timeGetTime() for game logic, and RDTSC for performance monitoring.  </p><p>timeGetTime():<br />On all systems I&#39;ve tested, has a resolution of at least 10 milliseconds; on many (all 2k&amp;XP? not sure) it has a resolution of 1 millisecond.  It&#39;s accuracy seems generally quite good for its resolution.  10 milliseconds is less than I&#39;d like when use delta-timing, but good enough; 1 millisecond is plenty for delta-timing games.  This function was reasonably fast on the systems where I tested it.  </p><p>RDTSC:<br />Fast.  Typically 10-100 cycles, depending upon CPU type.  The problems this has render it useless on some platforms, but performance monitoring is non-critical on users systems, so you only have to worry about your own testbeds.  </p><p>other timing methods:</p><p>allegro timer interrupts - I don&#39;t like the interface, but they seem to yield enough accuracy for timing game logic.  I never set them to run over 200 hertz.  </p><p>gettimeofday() - unixers seem to like it but docs claim that it&#39;s not monotically increasing, so I would avoid it for game logic.  I&#39;d like to do more testing on this - I don&#39;t know what the real-world speed, resolution, or accuracy is like.  </p><p>SDL_GetTicks() - haven&#39;t checked the implementation, but I would guess it to be a wrapper for timeGetTime() on windows.  If you use SDL this looks like a decent choice.  </p><p>libc time(NULL) - very low resolution, but this is what I use when I can&#39;t find anything non-libc</p><p>libc clock() - documentation on this varies wildly and is contradictory.  </p><p>QPC() - too buggy for game logic, too slow for profiling.  However, unlike RDTSC its units are easily convertable to seconds, so I still occaisonally use it.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (orz)</author>
		<pubDate>Fri, 26 Jan 2007 04:03:16 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[Hijackers have something for you Paul, and all come from one of the latest a.cc news.<br />
<br />
Here are Orz's routines for timing:<br />
<br />
get_time.h<br />
[code]<br />
#ifndef _GET_TIME_H<br />
#define _GET_TIME_H<br />
<br />
#ifndef _TYPES_H<br />
#include &quot;types.h&quot;<br />
#endif<br />
<br />
#ifdef __cplusplus<br />
extern &quot;C&quot; {<br />
#endif<br />
<br />
void init_time();      //to initialize time stuff<br />
void deinit_time();    //to de-initialize time stuff<br />
<br />
/*<br />
three forms of get_time<br />
NAME / ALTERNATE NAME				RETURNS	UNITS			PRECISION	SPEED<br />
get_time() / get_time_ms()			int		milliseconds	moderate	fast<br />
get_time_s() / get_time_seconds()	double	seconds			high		slow on WIN32<br />
get_time_ticks()					Sint64	unspecified		high		fast on intel<br />
<br />
the current time is measured relative to the call <br />
	to init_time() for get_time_ms() and get_time_s(), but NOT for get_time_ticks()<br />
*/<br />
<br />
volatile int    get_time();   //to get the current time in milliseconds<br />
#define get_time_ms get_time<br />
<br />
volatile double get_time_s(); //to get the current time in seconds at high precision<br />
#define get_time_seconds get_time_s<br />
<br />
volatile Sint64 get_time_ticks(); //to get the current time in unspecified units<br />
volatile double get_time_tick_period();<br />
/*note: The period of the ticks returned by get_time_ticks() may change over time<br />
		and the value reported is only an aproximation.  <br />
*/<br />
<br />
//set this to determine how you want to react to errors<br />
extern void (*get_time_error_function) (char *);<br />
<br />
int idle ( int time ); //to yeild a number of milliseconds to the OS<br />
extern int _no_idle;   //to disable the above function<br />
<br />
#ifdef __cplusplus<br />
}<br />
#endif<br />
<br />
<br />
#endif<br />
[/code]<br />
<br />
get_time.c<br />
[code]<br />
//#define NO_WINMM_TGT<br />
#define NO_WINMM_QPC<br />
#define NO_RDTSC<br />
#define NO_LIBC<br />
//#define NO_ALLEGRO_TIME<br />
//#define NO_SDL_TIME<br />
//#define NO_GETTIMEOFDAY<br />
<br />
//#define PLATFORM_IS_ALLEGRO<br />
//#define PLATFORM_IS_SDL<br />
<br />
/*<br />
These #defines are used to control what underlying system-dependant <br />
time functions are used to calculate the current time.  <br />
<br />
WINMM_TGT:<br />
	requires: Windows, linking with winmm.lib<br />
	resolution: varies, between 1 and 10 milliseconds<br />
	efficiency: fast<br />
	other notes: recommended method of timing on Windows at this time<br />
<br />
WINMM_QPC:<br />
	requires: Windows, linking with winmm.lib<br />
	resolution: varies, typically between 1 nanosecond and 1 microseconds<br />
	efficiency: slow, typically 0.1-1.0 microseconds per call<br />
	other notes: buggy on many computers<br />
<br />
RDTSC:<br />
	requires: x86 (including x86-64) CPU, Pentium or more recent<br />
	resolution: varies, typically between 0.1 and 30 nanoseconds<br />
	efficiency: fast, typically between 5 and 100 nanoseconds<br />
	other notes: buggy on some multi-CPU systems (different times on diff. CPUs)<br />
<br />
gettimeofday:<br />
	requires: UNIX (including linux, and many other unix-like systems)<br />
	resolution: varies, at best 1 microsecond, at worst ?100 microseconds? (guess)<br />
	efficiency: no idea (untested)<br />
	other notes: may run backwards due if the system time is adjusted<br />
<br />
LIBC:<br />
	requires: an implementation of the C standard library<br />
	resolution: shitty: 1 second<br />
	efficiency: varies<br />
	other notes: the method of last resort<br />
<br />
Allegro:<br />
	requires: Allegro<br />
	resolution: typically between 1 and 10 milliseconds<br />
	efficiency: extremely fast on a per-call basis, but high overhead to install at all<br />
	other notes: none<br />
<br />
SDL:<br />
	requires: SDL<br />
	resolution: typically between 1 and 10 milliseconds<br />
	efficiency: ?fast? (untested)<br />
	other notes: none<br />
<br />
other methods to consider for future use:<br />
	GetTickCount:<br />
		requires: Windows ???<br />
		resolution: typically between 55 and ?1? milliseconds<br />
		efficiency: ???<br />
		other notes: ???<br />
	libC clock:<br />
		requires: standard C library<br />
		resolution: frequently 55 milliseconds<br />
		efficiency: ???<br />
		other notes: documentation varies widely, inconsistent<br />
	clock_gettime:<br />
<br />
*/<br />
<br />
<br />
#ifndef NO_LIBC<br />
#	include &lt;time.h&gt;<br />
#	include &lt;math.h&gt;<br />
#endif<br />
#include &quot;types.h&quot;<br />
#include &quot;get_time.h&quot;<br />
//#include &quot;errors.h&quot;<br />
<br />
//static void get_time_error_function_impl ( const char *desc ) {}<br />
//void (*get_time_error_function) (char *) = get_time_error_function_impl;<br />
void (*get_time_error_function) (char *) = 0;<br />
static void get_time_error(char * msg) {<br />
	get_time_error_function(msg);<br />
}<br />
<br />
<br />
#ifdef NO_ALLEGRO_TIME<br />
#	undef PLATFORM_IS_ALLEGRO<br />
#endif<br />
#ifdef NO_SDL_TIME<br />
#	undef PLATFORM_IS_SDL<br />
#endif<br />
<br />
//converting all x86-declaring preprocessor symbols to __x86__<br />
#ifndef __x86__<br />
#	if defined __i386__ || defined __i386 || defined i386 || defined __I386__ || defined _M_IX86 || defined _X86 || defined __386__ || defined __x86__<br />
#		define __x86__<br />
#	endif<br />
#	if defined __x86_64__ || defined _M_X64<br />
#		define __x86__<br />
#	endif<br />
#endif<br />
#ifndef __x86_64__<br />
#	if defined __x86_64__ || defined _M_X64<br />
#		define __x86__<br />
#		define __x86_64__<br />
#	endif<br />
#endif<br />
<br />
//same for unix<br />
#ifndef __unix__<br />
#	if defined __unix || defined _unix || defined _UNIX || defined __UNIX__ || defined __UNIX || defined __unix_<br />
#		define __unix__<br />
#	endif<br />
#endif<br />
//same for win32<br />
#ifndef WIN32<br />
#	if defined _WIN32 || defined __WIN32<br />
#		define WIN32<br />
#	endif<br />
#endif<br />
<br />
/*<br />
------------------------------<br />
		Timers &amp; Stuff<br />
------------------------------<br />
<br />
Three sections:<br />
1.  idle() functions for Allegro / SDL / unrecognized platform<br />
2.  Platform-specific time functions:<br />
		LibC time returns integer seconds (fast?)<br />
		Allegro interrupt returns integer milliseconds (fast)<br />
		SDL ticks returns integer milliseconds (fast?)<br />
		Windows Multi-Media timeGetTime returns integer milliseconds (fast)<br />
		Windows Multi-Media Performance Counter returns integer high resolution ticks (slow)<br />
		Intel RDTSC returns integer high resolution ticks (fast)<br />
		unix gettimeofday() returns integer microseconds (???)<br />
3.  Wrappers to pick which time functions to use<br />
		get_time_ms() order of preference:<br />
			Windows Multi-Media timeGettime<br />
			SDL ticks<br />
			Allegro interrupt<br />
			unix gettimeofday()<br />
			Windows Multi-Media Performance Counter<br />
			Libc time<br />
		get_time_s() order of preference:<br />
			Windows Multi-Media Performance Counter<br />
			unix gettimeofday()<br />
			get_time_ms()<br />
		get_time_ticks() order of preference:<br />
			Intel RDTSC<br />
			Windows Multi-Media Performance Counter<br />
			unix gettimeofday()<br />
			get_time_ms()<br />
*/<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
//1.  idle() functions for Allegro / SDL / unknown platform<br />
<br />
<br />
<br />
<br />
int _no_idle = 0;<br />
<br />
#if defined(PLATFORM_IS_ALLEGRO) &amp;&amp; !defined(NO_ALLEGRO_TIME)<br />
#	include &lt;allegro.h&gt;<br />
#	if defined WIN32<br />
#		include &lt;winalleg.h&gt;<br />
#	endif<br />
	int idle ( int time ) {<br />
		if (_no_idle) return 0;<br />
		rest(time);<br />
		return time;<br />
	}<br />
#elif defined(PLATFORM_IS_SDL) &amp;&amp; !defined(NO_SDL_TIME)<br />
#	include &lt;SDL.h&gt;<br />
	int idle ( int time ) {<br />
		if (_no_idle) return 0;<br />
		SDL_Delay ( time );<br />
		return time;<br />
	}<br />
#else<br />
//#	error get_time.c - unknown platform<br />
	int idle ( int time ) {<br />
		if (_no_idle) return 0;<br />
		return 0;<br />
		/*int i = get_time() + time;<br />
		while (i &gt; get_time()) {<br />
			//do nothing real fast<br />
		}<br />
		return time;*/<br />
	}<br />
#endif<br />
<br />
<br />
<br />
<br />
//2.  Platform specific time functions:<br />
<br />
<br />
<br />
#if !defined NO_GETTIMEOFDAY &amp;&amp; defined __unix__<br />
#	define GETTIMEOFDAY_TIME<br />
#	include &lt;sys/time.h&gt;<br />
	static volatile Sint64 gettimeofday_get_time_microseconds() {<br />
		timeval tv;<br />
		gettimeofday( &amp;tv, NULL );<br />
		return (Sint64(tv.tv_sec) * 1000000) + tv.tv_usec;<br />
	}<br />
	static volatile double gettimeofday_get_time_seconds() {<br />
		timeval tv;<br />
		gettimeofday( &amp;tv, NULL );<br />
		return tv.tv_sec + 0.000001d * tv.tv_usec;<br />
	}<br />
#endif<br />
<br />
//RDTSC:<br />
//RDTSC is only valid on pentiums &amp; later, right?<br />
//so how do we detect this at run-time? (without crashing)<br />
#if !defined NO_RDTSC<br />
#	if defined _MSC_VER &amp;&amp; defined __x86__<br />
#		define RDTSC_TIMER<br />
		static volatile Sint64 rdtsc_get_time() {<br />
			unsigned int a, b;<br />
			__asm RDTSC<br />
			__asm mov a, eax<br />
			__asm mov b, edx<br />
			return (a + ((Sint64)b &lt;&lt; 32));<br />
		}<br />
#	elif defined __GNUC__ &amp;&amp; defined __x86__<br />
#		define RDTSC_TIMER<br />
		static __volatile__ Uint64 rdtsc_get_time() {<br />
//			unsigned int a, b;<br />
//			asm (&quot;RDTSC&quot; : &quot;=a&quot; (a), &quot;=d&quot; (b) : );<br />
//			return (a + ((Sint64)b &lt;&lt; 32));<br />
			unsigned long long int r;<br />
			asm (&quot;RDTSC&quot; : &quot;=A&quot; (r) : );<br />
			return r;<br />
		}<br />
#	endif<br />
#endif<br />
<br />
#if defined WIN32 &amp;&amp; !(defined NO_WINMM_TGT &amp;&amp; defined NO_WINMM_QPC)<br />
#	include &lt;windows.h&gt;<br />
#	include &lt;Mmsystem.h&gt;<br />
#	include &lt;winbase.h&gt;<br />
<br />
#	if !defined NO_WINMM_TGT<br />
#		define WINMM_TGT<br />
#		define winmm_tgt_period_i 1<br />
		static int winmm_tgt_get_time() {<br />
			return timeGetTime();<br />
		}<br />
#	endif<br />
<br />
#	if !defined NO_WINMM_QPC<br />
#		define WINMM_QPC<br />
		static double winmm_qpc_period_f = 1;<br />
		static int winmm_qpc_period_i = 0;<br />
		static Uint64 winmm_qpc_base = 0;<br />
		static volatile Uint64 winmm_qpc_get_time() {<br />
			LARGE_INTEGER bob;<br />
			if (QueryPerformanceCounter(&amp;bob)) {<br />
				return bob.QuadPart;<br />
			}<br />
			get_time_error ( &quot;Windows Performance Counter failed\n&quot;);<br />
			return -1;<br />
		}<br />
		static double winmm_qpc_get_freq() {<br />
			LARGE_INTEGER fred;<br />
			if (QueryPerformanceFrequency(&amp;fred)) {<br />
				return (double)fred.QuadPart;<br />
			}<br />
			get_time_error ( &quot;Windows Performance Counter failed\n&quot;);<br />
			return 0;<br />
		}<br />
#	endif<br />
#endif<br />
<br />
#if defined PLATFORM_IS_ALLEGRO<br />
#	include &lt;allegro.h&gt;<br />
#	define allegro_period 5<br />
	static volatile int allegro_time = 0;<br />
	static volatile int allegro_get_time() {<br />
		return allegro_time;<br />
	}<br />
	static void allegro_timer_function(void) {<br />
		allegro_time += allegro_period;<br />
	}<br />
	END_OF_STATIC_FUNCTION(allegro_timer_function);<br />
	static int allegro_time_inited = 0;<br />
	void init_allegro_time() {<br />
		if (allegro_time_inited++) return;<br />
		LOCK_FUNCTION(allegro_timer_function);<br />
		LOCK_VARIABLE(allegro_time);<br />
		if (install_timer() &lt; 0) get_time_error(&quot;Allegro timer initialization failed&quot;);<br />
		install_int(&amp;allegro_timer_function, allegro_period);<br />
	}<br />
	void deinit_allegro_time() {<br />
		if (--allegro_time_inited &gt; 0) return;<br />
		if (allegro_time_inited &lt; 0) get_time_error(&quot;get_time.c - deinit_allegro_time() called incorrectly&quot;);<br />
		remove_int(&amp;allegro_timer_function);<br />
	}<br />
#elif defined PLATFORM_IS_SDL<br />
#	include &lt;SDL.h&gt;<br />
	static int sdl_time_inited = 0;<br />
	static int sdl_get_time() {<br />
		return SDL_GetTicks();<br />
	}<br />
	static void init_sdl_time() {<br />
		if (sdl_time_inited++) return;<br />
		SDL_InitSubSystem(SDL_INIT_TIMER);<br />
	}<br />
	static void deinit_sdl_time() {<br />
		if (--sdl_time_inited &gt; 0) return;<br />
		if (sdl_time_inited &lt; 0) get_time_error(&quot;get_time.c - deinit_sdl_time() called incorrectly&quot;);<br />
		SDL_QuitSubSystem(SDL_INIT_TIMER);<br />
	}<br />
#else<br />
#endif<br />
<br />
#if !defined NO_LIBC<br />
#	define LIBC_TIME<br />
	int libc_get_time() {<br />
		return time(NULL);<br />
	}<br />
#endif<br />
<br />
<br />
<br />
<br />
<br />
//3.  The exported wrappers for time functions<br />
<br />
<br />
<br />
<br />
//volatile int    get_time();<br />
/*	get_time() order of preference:<br />
		Windows Multi-Media timeGettime<br />
		SDL ticks<br />
		Allegro interrupt<br />
		unix gettimeofday()<br />
		Windows Multi-Media Performance Counter<br />
		Libc time<br />
*/<br />
static int get_time_ms_base;<br />
#if 0<br />
#elif defined WINMM_TGT//<br />
	volatile int get_time() {return winmm_tgt_get_time() - get_time_ms_base;}<br />
	static void init_get_time_ms() {};<br />
	static void deinit_get_time_ms() {};<br />
#elif defined PLATFORM_IS_SDL//<br />
	volatile int get_time() {return sdl_get_time() - get_time_ms_base;}<br />
	static void init_get_time_ms() {init_sdl_time();}<br />
	static void deinit_get_time_ms() {deinit_sdl_time();}<br />
#elif defined PLATFORM_IS_ALLEGRO<br />
	volatile int get_time() {return allegro_get_time() - get_time_ms_base;}<br />
	static void init_get_time_ms() {init_allegro_time();};<br />
	static void deinit_get_time_ms() {deinit_allegro_time();};<br />
#elif defined GETTIMEOFDAY_TIME<br />
	volatile int get_time() {return int(gettimeofday_get_time_microseconds() / 1000) - get_time_ms_base;}<br />
	static void init_get_time_ms() {};<br />
	static void deinit_get_time_ms() {};<br />
/*<br />
#	elif defined WINMM_QPC<br />
	static double get_time_ms_period = 0;<br />
	volatile int get_time() {<br />
		return (int)(winmm_qpc_get_time() * get_time_ms_period) - get_time_ms_base;<br />
	}<br />
	static void init_get_time_s() {get_time_ms_period = 1000.0 / winmm_qpc_get_freq();};<br />
	static void deinit_get_time_s() {get_time_ms_period = 0;};<br />
*/<br />
#elif defined LIBC_TIME<br />
	volatile int get_time() {return libc_get_time() - get_time_ms_base;}<br />
	static void init_get_time_ms() {};<br />
	static void deinit_get_time_ms() {};<br />
#else<br />
#	error No millisecond time function specified!<br />
#endif<br />
<br />
<br />
//volatile double get_time_s();<br />
/*	get_time_s() order of preference:<br />
		Windows Multi-Media Performance Counter<br />
		unix gettimeofday()<br />
		get_time_ms()<br />
*/<br />
static double get_time_s_base;<br />
#	if 0<br />
#	elif defined WINMM_QPC<br />
	static double get_time_s_period = 0;<br />
	volatile double get_time_s() {<br />
		return winmm_qpc_get_time() * get_time_s_period - get_time_s_base;<br />
	}<br />
	static void init_get_time_s() {get_time_s_period = 1.0/winmm_qpc_get_freq();};<br />
	static void deinit_get_time_s() {get_time_s_period = 0;};<br />
#elif defined GETTIMEOFDAY_TIME<br />
	volatile double get_time_s() {return gettimeofday_get_time_s() - get_time_s_base;}<br />
	static void init_get_time_s() {};<br />
	static void deinit_get_time_s() {};<br />
#	else<br />
	volatile double get_time_s() {return get_time_ms() * 0.001;}<br />
	static void init_get_time_s() {init_get_time_ms();};<br />
	static void deinit_get_time_s() {deinit_get_time_ms();};<br />
#	endif<br />
<br />
<br />
//volatile Sint64    get_time_ticks();<br />
/*	get_time3() order of preference:<br />
		Intel RDTSC<br />
		unix gettimeofday()<br />
		Windows Multi-Media Performance Counter<br />
		get_time_ms()<br />
*/<br />
static Sint64 get_time_ticks_inited;<br />
#if 0<br />
#elif defined RDTSC_TIMER<br />
	//require debuging mode, since we don't have run-time check<br />
	volatile Sint64 get_time_ticks() {return rdtsc_get_time();}<br />
	static void init_get_time_ticks() {};<br />
	static void deinit_get_time_ticks() {};<br />
#	define NEED_GUESS_TICKS<br />
#elif defined WINMM_QPC<br />
	volatile Sint64 get_time_ticks() {return winmm_qpc_get_time();}<br />
	static void init_get_time_ticks() {};<br />
	static void deinit_get_time_ticks() {};<br />
	volatile double get_time_tick_period() {return 1.0 / winmm_qpc_get_freq();}<br />
#elif defined GETTIMEOFDAY_TIME<br />
	volatile Sint64 get_time_ticks() {return gettimeofday_get_time_microseconds();}<br />
	static void init_get_time_s() {};<br />
	static void deinit_get_time_s() {};<br />
	volatile double get_time_tick_period() {return 0.000001;}<br />
#else<br />
	volatile Sint64 get_time_ticks() {return get_time_ms();}<br />
	static void init_get_time_ticks() {init_get_time_ms();};<br />
	static void deinit_get_time_ticks() {deinit_get_time_ms();};<br />
	volatile double get_time_tick_period() {return 0.001;}<br />
#endif<br />
<br />
#ifdef NEED_GUESS_TICKS<br />
	volatile double get_time_tick_period() {<br />
		return get_time_s() / (get_time_ticks() - get_time_ticks_inited);<br />
	}<br />
#endif<br />
<br />
static unsigned char time_inited = 0;<br />
void init_time() {<br />
	if (time_inited++) get_time_error(&quot;get_time - init_time() called repeatedly w/o deinit_time()&quot;);<br />
	init_get_time_ms();<br />
	init_get_time_s();<br />
	init_get_time_ticks();<br />
	get_time_s_base = get_time_s();<br />
	get_time_ms_base = get_time_ms();<br />
	get_time_ticks_inited = get_time_ticks();<br />
/*	int ms;<br />
	if (timer_attributes &amp; 1) return;<br />
	timer_attributes |= 1;<br />
#	if defined WINMM_TGT<br />
	{<br />
		int tmp = winmm_tgt_get_time();<br />
		int i;<br />
		for (i = 0; i &lt; 1000000; i += 1) <br />
			if (winmm_tgt_get_time() != tmp) break;<br />
		winmm_tgt_base = winmm_tgt_get_time();<br />
	}<br />
#	endif<br />
#	if defined PLATFORM_IS_SDL<br />
		init_sdl_time();<br />
		sdl_base = sdl_get_time();<br />
#	endif<br />
#	if defined PLATFORM_IS_ALLEGRO<br />
		LOCK_FUNCTION(get_time);<br />
		init_allegro_time();<br />
		allegro_base = allegro_get_time();<br />
#	endif<br />
#	if defined LIBC_TIME<br />
		libc_base = libc_get_time();<br />
#	endif<br />
<br />
	ms = get_time();<br />
//finished initializing get_time()<br />
//now we do get_time2() / get_time3()<br />
<br />
#	if defined RDTSC_TIMER<br />
		//require debuging mode, since we don't have a run-time check<br />
		rdtsc_base = rdtsc_get_time();<br />
#	endif<br />
#	if defined WINMM_QPC<br />
		winmm_qpc_base = winmm_qpc_get_time();<br />
		winmm_qpc_period_f = 1000.0 / winmm_qpc_get_freq();<br />
#	endif<br />
<br />
<br />
#	if defined RDTSC_TIMER<br />
	{<br />
		Sint64 tmpl;<br />
		double tmpd;<br />
		while (get_time() - ms &lt; 100) ;<br />
		tmpl = rdtsc_get_time();<br />
		tmpd = tmpl * (1.0 / (get_time() - ms));<br />
#		if !defined NO_LIBC<br />
		{<br />
			double tmpd2, tmpd3;<br />
			//most clock speeds are multiples of nice numbers<br />
			//like 25.0 or 33.333 Mega-Hertz.  <br />
			tmpd2 = floor(0.5 + tmpd / (100000/4.0)) * (100000/4.0);<br />
			tmpd3 = floor(0.5 + tmpd / (100000/3.0)) * (100000/3.0);<br />
			if (fabs(tmpd2-tmpd) &lt; fabs(tmpd3-tmpd)) tmpd = tmpd2;<br />
			else tmpd = tmpd3;<br />
		}<br />
#		endif<br />
		rdtsc_period_f = 1 / tmpd;<br />
	}<br />
#	endif<br />
	*/<br />
}<br />
<br />
void deinit_time() {<br />
	if (--time_inited) get_time_error(&quot;get_time - deinit_time() called without init_time()&quot;);<br />
	deinit_get_time_ticks();<br />
	deinit_get_time_s();<br />
	deinit_get_time_ms();<br />
}<br />
[/code]<br />
<br />
All these examples comes from [url http://sourceforge.net/projects/pmask]pmask library[/url], by Orz.<br />
<br />
I think looking at it will definitely solve your problem Paul.]]>
		</description>
		<author>no-reply@allegro.cc (GullRaDriel)</author>
		<pubDate>Fri, 26 Jan 2007 04:05:29 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
If it is too low it won&#39;t look very good even if it is more reliable.
</p></div></div><p>Oh, well, if the user is playing at the moment DST kicks in and he has his RTC set to localtime (for no reason at all), then the game would lag an hour <img src="http://www.allegro.cc/forums/smileys/tongue.gif" alt=":P" />
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (CGamesPlay)</author>
		<pubDate>Fri, 26 Jan 2007 04:06:31 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>I tried to use these routines, RIchard helped me a lot, and he answered all my question but I could not make it work properly.<br />I am using devcpp since a few days ago and perhaps there is something wrong with my configuration, so can someone else try to compile this routines?</p><p>timer.hpp
</p><div class="source-code"><div class="toolbar"></div><div class="inner"><table width="100%"><tbody><tr><td class="number">1</td><td><span class="p">#ifndef __Timer_hpp__</span></td></tr><tr><td class="number">2</td><td><span class="p">#define __Timer_hpp__</span></td></tr><tr><td class="number">3</td><td>&#160;</td></tr><tr><td class="number">4</td><td><span class="p">#include &lt;allegro.h&gt;</span></td></tr><tr><td class="number">5</td><td><span class="p">#include &lt;winalleg.h&gt;</span></td></tr><tr><td class="number">6</td><td>&#160;</td></tr><tr><td class="number">7</td><td><span class="k1">struct</span> timer</td></tr><tr><td class="number">8</td><td><span class="k2">{</span></td></tr><tr><td class="number">9</td><td>LARGE_INTEGER tstart, tticks, tnow, tlast<span class="k2">;</span></td></tr><tr><td class="number">10</td><td><span class="k1">int</span> high_freq, logic_frames, logic_fps, gfx_frames, gfx_fps<span class="k2">;</span></td></tr><tr><td class="number">11</td><td><span class="k2">}</span><span class="k2">;</span></td></tr><tr><td class="number">12</td><td>&#160;</td></tr><tr><td class="number">13</td><td><span class="k1">extern</span> <span class="k1">struct</span> timer timer<span class="k2">;</span></td></tr><tr><td class="number">14</td><td>&#160;</td></tr><tr><td class="number">15</td><td><span class="k1">void</span> start_timer<span class="k2">(</span><span class="k1">void</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">16</td><td><span class="k1">void</span> reset_timer<span class="k2">(</span><span class="k1">void</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">17</td><td><span class="k1">int</span> check_timer<span class="k2">(</span><span class="k1">int</span> frac_sec<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">18</td><td><span class="k1">void</span> reset_timer_alt<span class="k2">(</span><span class="k1">void</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">19</td><td>&#160;</td></tr><tr><td class="number">20</td><td><span class="p">#endif</span></td></tr></tbody></table></div></div><p>

timer.cpp
</p><div class="source-code"><div class="toolbar"></div><div class="inner"><table width="100%"><tbody><tr><td class="number">1</td><td><span class="p">#include &lt;Windows.h&gt; a veces hay que sacvar esto</span></td></tr><tr><td class="number">2</td><td><span class="p">#include "timer.hpp"</span></td></tr><tr><td class="number">3</td><td>&#160;</td></tr><tr><td class="number">4</td><td><span class="c">// High resolution timer code for Windows. Call start_timer first and then call</span></td></tr><tr><td class="number">5</td><td><span class="c">// check_timer with the required accuracy range.</span></td></tr><tr><td class="number">6</td><td><span class="c">// The timer is more accurate than the default Allegro timers..</span></td></tr><tr><td class="number">7</td><td>&#160;</td></tr><tr><td class="number">8</td><td><span class="k1">struct</span> timer timer<span class="k2">;</span></td></tr><tr><td class="number">9</td><td>&#160;</td></tr><tr><td class="number">10</td><td><span class="k1">void</span> start_timer<span class="k2">(</span><span class="k1">void</span><span class="k2">)</span></td></tr><tr><td class="number">11</td><td><span class="k2">{</span></td></tr><tr><td class="number">12</td><td>timer.high_freq <span class="k3">=</span> QueryPerformanceFrequency<span class="k2">(</span><span class="k3">&amp;</span>timer.tticks<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">13</td><td>timer.logic_frames <span class="k3">=</span> <span class="n">0</span><span class="k2">;</span></td></tr><tr><td class="number">14</td><td>&#160;</td></tr><tr><td class="number">15</td><td><span class="k1">if</span> <span class="k2">(</span>timer.high_freq<span class="k2">)</span></td></tr><tr><td class="number">16</td><td><span class="k2">{</span></td></tr><tr><td class="number">17</td><td>QueryPerformanceCounter<span class="k2">(</span><span class="k3">&amp;</span>timer.tstart<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">18</td><td>timer.tlast <span class="k3">=</span> timer.tstart<span class="k2">;</span></td></tr><tr><td class="number">19</td><td><span class="k2">}</span></td></tr><tr><td class="number">20</td><td><span class="k2">}</span></td></tr><tr><td class="number">21</td><td>&#160;</td></tr><tr><td class="number">22</td><td><span class="k1">void</span> reset_timer<span class="k2">(</span><span class="k1">void</span><span class="k2">)</span></td></tr><tr><td class="number">23</td><td><span class="k2">{</span></td></tr><tr><td class="number">24</td><td><span class="k1">if</span> <span class="k2">(</span>timer.high_freq<span class="k2">)</span></td></tr><tr><td class="number">25</td><td><span class="k2">{</span></td></tr><tr><td class="number">26</td><td>&#160;</td></tr><tr><td class="number">27</td><td>QueryPerformanceCounter<span class="k2">(</span><span class="k3">&amp;</span>timer.tnow<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">28</td><td>timer.tstart <span class="k3">=</span> timer.tnow<span class="k2">;</span></td></tr><tr><td class="number">29</td><td><span class="k2">}</span></td></tr><tr><td class="number">30</td><td><span class="k2">}</span></td></tr><tr><td class="number">31</td><td>&#160;</td></tr><tr><td class="number">32</td><td><span class="k1">int</span> check_timer<span class="k2">(</span><span class="k1">int</span> frac_sec<span class="k2">)</span></td></tr><tr><td class="number">33</td><td><span class="k2">{</span></td></tr><tr><td class="number">34</td><td><span class="k1">int</span> t<span class="k2">;</span></td></tr><tr><td class="number">35</td><td>&#160;</td></tr><tr><td class="number">36</td><td><span class="k1">if</span> <span class="k2">(</span>timer.high_freq<span class="k2">)</span></td></tr><tr><td class="number">37</td><td><span class="k2">{</span></td></tr><tr><td class="number">38</td><td>QueryPerformanceCounter<span class="k2">(</span><span class="k3">&amp;</span>timer.tnow<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">39</td><td>t <span class="k3">=</span> <span class="k2">(</span><span class="k1">int</span><span class="k2">)</span> <span class="k2">(</span><span class="k2">(</span><span class="k2">(</span>timer.tnow.QuadPart <span class="k3">-</span> timer.tstart.QuadPart<span class="k2">)</span> <span class="k3">*</span> frac_sec<span class="k2">)</span> <span class="k3">/</span> timer.tticks.QuadPart<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">40</td><td>&#160;</td></tr><tr><td class="number">41</td><td><span class="c">// Have we done 1 second since the timer was last reset?</span></td></tr><tr><td class="number">42</td><td><span class="k1">if</span> <span class="k2">(</span>t <span class="k3">&gt;</span> <span class="n">240</span><span class="k2">)</span></td></tr><tr><td class="number">43</td><td><span class="k2">{</span></td></tr><tr><td class="number">44</td><td><span class="c">// Yes, so reset again and update details.</span></td></tr><tr><td class="number">45</td><td><span class="c">// If we reset the timer after each check we get errors building up causing a lack</span></td></tr><tr><td class="number">46</td><td><span class="c">// of precision. We also reset it here to make it as fast as possible.</span></td></tr><tr><td class="number">47</td><td>&#160;</td></tr><tr><td class="number">48</td><td>timer.tstart <span class="k3">=</span> timer.tlast<span class="k2">;</span></td></tr><tr><td class="number">49</td><td>t <span class="k3">-</span><span class="k3">=</span> timer.logic_frames<span class="k2">;</span></td></tr><tr><td class="number">50</td><td>timer.logic_fps <span class="k3">=</span> timer.logic_frames<span class="k2">;</span></td></tr><tr><td class="number">51</td><td>timer.logic_frames <span class="k3">=</span> <span class="n">0</span><span class="k2">;</span></td></tr><tr><td class="number">52</td><td>&#160;</td></tr><tr><td class="number">53</td><td>timer.gfx_fps <span class="k3">=</span> timer.gfx_frames<span class="k2">;</span></td></tr><tr><td class="number">54</td><td>timer.gfx_frames <span class="k3">=</span> <span class="n">0</span><span class="k2">;</span></td></tr><tr><td class="number">55</td><td><span class="k2">}</span></td></tr><tr><td class="number">56</td><td>timer.tlast <span class="k3">=</span> timer.tnow<span class="k2">;</span></td></tr><tr><td class="number">57</td><td><span class="k1">return</span> t<span class="k2">;</span></td></tr><tr><td class="number">58</td><td><span class="k2">}</span></td></tr><tr><td class="number">59</td><td>&#160;</td></tr><tr><td class="number">60</td><td><span class="k1">return</span> <span class="n">0</span><span class="k2">;</span></td></tr><tr><td class="number">61</td><td><span class="k2">}</span></td></tr></tbody></table></div></div><p>

my loop
</p><div class="source-code"><div class="toolbar"></div><div class="inner"><table width="100%"><tbody><tr><td class="number">1</td><td>start_timer<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">2</td><td><span class="k1">do</span></td></tr><tr><td class="number">3</td><td> <span class="k2">{</span> </td></tr><tr><td class="number">4</td><td><span class="c">//Richard's timer runs at 240fps, so I did this to get a 60fps</span></td></tr><tr><td class="number">5</td><td><span class="c">// 240/4 = 60, then check_timer(240)%4 = {0,4,8,12,16,20,24,28,32,36...} = 60FPS</span></td></tr><tr><td class="number">6</td><td>&#160;</td></tr><tr><td class="number">7</td><td>        <span class="k1">if</span><span class="k2">(</span><span class="k2">(</span>check_timer<span class="k2">(</span><span class="n">240</span><span class="k2">)</span>%<span class="n">4</span><span class="k2">)</span> <span class="k3">=</span><span class="k3">=</span> <span class="n">0</span><span class="k2">)</span><span class="k2">{</span></td></tr><tr><td class="number">8</td><td>      <span class="c">//draw background and show FPS</span></td></tr><tr><td class="number">9</td><td>            <a href="http://www.allegro.cc/manual/draw_sprite" target="_blank"><span class="a">draw_sprite</span></a><span class="k2">(</span>background, bg.get_frame<span class="k2">(</span><span class="k2">)</span>,<span class="n">0</span>,<span class="n">0</span><span class="k2">)</span><span class="k2">;</span>      </td></tr><tr><td class="number">10</td><td>      textprintf<span class="k2">(</span>background, <a href="http://www.allegro.cc/manual/font" target="_blank"><span class="a">font</span></a>, <span class="n">0</span>,<span class="n">0</span>, <a href="http://www.allegro.cc/manual/makecol" target="_blank"><span class="a">makecol</span></a><span class="k2">(</span><span class="n">205</span>, <span class="n">215</span>, <span class="n">255</span><span class="k2">)</span>, <span class="s">"FPS %d"</span>, timer.gfx_fps<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">11</td><td>      <span class="c">//draw sprites</span></td></tr><tr><td class="number">12</td><td>           <a href="http://www.allegro.cc/manual/draw_trans_sprite" target="_blank"><span class="a">draw_trans_sprite</span></a><span class="k2">(</span>background, my_frame.get_frame<span class="k2">(</span><span class="k2">)</span>, <a href="http://www.allegro.cc/manual/mouse_x" target="_blank"><span class="a">mouse_x</span></a><span class="k3">+</span><span class="n">111</span>, <a href="http://www.allegro.cc/manual/mouse_y" target="_blank"><span class="a">mouse_y</span></a><span class="k3">+</span><span class="n">101</span><span class="k2">)</span><span class="k2">;</span>          </td></tr><tr><td class="number">13</td><td>&#160;</td></tr><tr><td class="number">14</td><td>      <span class="c">//blit to screen   </span></td></tr><tr><td class="number">15</td><td>            <a href="http://www.allegro.cc/manual/blit" target="_blank"><span class="a">blit</span></a><span class="k2">(</span>background, <a href="http://www.allegro.cc/manual/screen" target="_blank"><span class="a">screen</span></a>, <span class="n">0</span>, <span class="n">0</span>, <span class="n">0</span>, <span class="n">0</span>, <span class="n">640</span>, <span class="n">480</span><span class="k2">)</span><span class="k2">;</span>    </td></tr><tr><td class="number">16</td><td>            timer.gfx_frames<span class="k3">+</span><span class="k3">+</span><span class="k2">;</span></td></tr><tr><td class="number">17</td><td>       <span class="k2">}</span>      </td></tr><tr><td class="number">18</td><td>  <span class="c">// Wait until we press Escape.</span></td></tr><tr><td class="number">19</td><td> <span class="k2">}</span> <span class="k1">while</span> <span class="k2">(</span><span class="k3">!</span><a href="http://www.allegro.cc/manual/key" target="_blank"><span class="a">key</span></a><span class="k2">[</span>KEY_ESC<span class="k2">]</span><span class="k2">)</span><span class="k2">;</span></td></tr></tbody></table></div></div><p>
.<br />.<br />.<br />Well, this loops works OK at 60fps, but when some sprites disappear the FPS grows(the game runs faster), with few sprites my game runs faster and with more sprites it runs slower.<br />What can be wrong?<br />.<br />.<br />.<br />.<br />.<br />.</p><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
Paul: read this, especially where he says &quot;How to use KC&#39;s routines:&quot;
</p></div></div><p>

</p><div class="quote_container"><div class="title">thread&#39;s title said:</div><div class="quote"><p>

I need a high resolution timer with <b>QPC</b>
</p></div></div><p>

</p><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
You should not use high resolution timers in main loops
</p></div></div><p>

I disagree.</p><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
You are totally high jacking the thread.
</p></div></div><p>

I agree.</p><p>.<br />.<br />.<br />[EDIT]<br />GullRaDriel I&#39;ll try that now, thanks!
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Paul whoknows)</author>
		<pubDate>Fri, 26 Jan 2007 04:06:37 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>
Paul, did you try that change the 240 to 60 thing I mentioned?
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Richard Phipps)</author>
		<pubDate>Fri, 26 Jan 2007 04:10:06 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>From Pmask libray you have test.c and test2.c which use Orz&#39;s timing routines so all your need are filled .
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (GullRaDriel)</author>
		<pubDate>Fri, 26 Jan 2007 04:11:12 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
Paul, did you try that change the 240 to 60 thing I mentioned?
</p></div></div><p>

Yes, I tried several times, but it allways run at 240 or more without reset_timer()<br />With reset_timer() it seems that works, but then timer.gfx_fps shows allways 0
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Paul whoknows)</author>
		<pubDate>Fri, 26 Jan 2007 04:15:51 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>
I can&#39;t see how that would happen if you had no 240 references anymore.. but anyway, try Orz&#39;s code. <img src="http://www.allegro.cc/forums/smileys/smiley.gif" alt=":)" />
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Richard Phipps)</author>
		<pubDate>Fri, 26 Jan 2007 04:17:43 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>How should I use Orz&#39;s routines?<br />I need to see a main loop implemented with those routines to understand how they work.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Paul whoknows)</author>
		<pubDate>Fri, 26 Jan 2007 04:28:36 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
Here are Orz&#39;s routines for timing:<br />...<br />All these examples comes from pmask library [sourceforge.net], by Orz.</p><p>I think looking at it will definitely solve your problem Paul.
</p></div></div><p>

Yeah, that&#39;s my timing measurement code.  A few caveats:<br />1.  the gettimeofday() implemenation there is bugged... just some easily fixed typos, fixed in my lastest version of that file (so far existing on my computer only...)<br />2.  while that&#39;s in the PMASK download for use by the examples, I consider it to not be a part of the examples, not the library itself.  </p><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
thread&#39;s title said:<br />I need a high resolution timer with QPC
</p></div></div><p>
That was the title, but your original post said</p><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
I found a lot of timer routines using QPC but there is no explanation about how to use these routines in the main loop
</p></div></div><p>
So I posted code that demonstrated how to use a timer function in a games main loop, independant of whether that timer function used QPC.  Though, for usage with QPC, its best with the ints changed to doubles.  i.e.
</p><div class="source-code"><div class="toolbar"></div><div class="inner"><table width="100%"><tbody><tr><td class="number">1</td><td>  <span class="k1">double</span> next_tick_ms <span class="k3">=</span> get_time_ms<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">2</td><td>  <span class="k1">double</span> ticks_since_last_frame <span class="k3">=</span> <span class="n">0</span><span class="k2">;</span></td></tr><tr><td class="number">3</td><td>  <span class="k1">double</span> ms_per_tick <span class="k3">=</span> <span class="n">1000</span>.<span class="n">0</span> <span class="k3">/</span> <span class="n">60</span><span class="k2">;</span><span class="c">//60 hertz</span></td></tr><tr><td class="number">4</td><td>  <span class="k1">double</span> last_frame_ms <span class="k3">=</span> <span class="n">0</span><span class="k2">;</span></td></tr><tr><td class="number">5</td><td>  <span class="k1">while</span> <span class="k2">(</span><span class="k3">!</span>quitting<span class="k2">)</span> <span class="k2">{</span></td></tr><tr><td class="number">6</td><td>    <span class="k1">bool</span> do_frame <span class="k3">=</span> <span class="k1">false</span><span class="k2">;</span></td></tr><tr><td class="number">7</td><td>    <span class="k1">double</span> current_ms <span class="k3">=</span> get_time_ms<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">8</td><td>    <span class="k1">if</span> <span class="k2">(</span>current_ms <span class="k3">&gt;</span><span class="k3">=</span> next_tick_ms<span class="k2">)</span> <span class="k2">{</span></td></tr><tr><td class="number">9</td><td>      calculate_physics<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">10</td><td>      next_tick_ms <span class="k3">+</span><span class="k3">=</span> ms_per_tick<span class="k2">;</span></td></tr><tr><td class="number">11</td><td>      <span class="c">//we're too far behind</span></td></tr><tr><td class="number">12</td><td>      <span class="k1">if</span> <span class="k2">(</span>next_tick_ms <span class="k3">&lt;</span> current_ms <span class="k3">-</span> <span class="n">20</span><span class="k2">)</span> next_tick_ms <span class="k3">=</span> current_ms <span class="k3">-</span> <span class="n">20</span><span class="k2">;</span></td></tr><tr><td class="number">13</td><td>      ticks_since_last_frame<span class="k3">+</span><span class="k3">+</span><span class="k2">;</span></td></tr><tr><td class="number">14</td><td>      <span class="k1">if</span> <span class="k2">(</span>ticks_since_last_frame <span class="k3">&gt;</span> <span class="n">5</span><span class="k2">)</span> do_frame <span class="k3">=</span> <span class="k1">true</span><span class="k2">;</span></td></tr><tr><td class="number">15</td><td>    <span class="k2">}</span></td></tr><tr><td class="number">16</td><td>    <span class="k1">else</span> <span class="k2">{</span></td></tr><tr><td class="number">17</td><td>      <span class="k1">if</span> <span class="k2">(</span>ticks_since_last_frame <span class="k3">|</span><span class="k3">|</span> current_ms <span class="k3">&gt;</span> last_frame_ms <span class="k3">+</span> <span class="n">100</span><span class="k2">)</span></td></tr><tr><td class="number">18</td><td>        do_frame <span class="k3">=</span> <span class="k1">true</span><span class="k2">;</span></td></tr><tr><td class="number">19</td><td>    <span class="k2">}</span></td></tr><tr><td class="number">20</td><td>    <span class="k1">if</span> <span class="k2">(</span>do_frame<span class="k2">)</span> <span class="k2">{</span></td></tr><tr><td class="number">21</td><td>      render_frame<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">22</td><td>      ticks_since_last_frame <span class="k3">=</span> <span class="n">0</span><span class="k2">;</span></td></tr><tr><td class="number">23</td><td>      last_frame_ms <span class="k3">=</span> current_ms<span class="k2">;</span></td></tr><tr><td class="number">24</td><td>    <span class="k2">}</span></td></tr><tr><td class="number">25</td><td>  <span class="k2">}</span></td></tr></tbody></table></div></div><p>
edit: fixed a typo in the code (mispelled since as sicne in one case), added a value of ms_per_tick</p><p>The only thing necessary (with or without changing the ints to doubles) to make that into a functional QPC-timed game loop is a QPC based timer such as:
</p><div class="source-code"><div class="toolbar"></div><div class="inner"><table width="100%"><tbody><tr><td class="number">1</td><td><span class="k1">double</span> ms_per_QPC_tick<span class="k3">=</span><span class="n">0</span><span class="k2">;</span></td></tr><tr><td class="number">2</td><td><span class="k1">void</span> init_get_time_ms<span class="k2">(</span><span class="k2">)</span> <span class="k2">{</span></td></tr><tr><td class="number">3</td><td>  LARGE_INTEGER fred<span class="k2">;</span></td></tr><tr><td class="number">4</td><td>  <span class="k1">if</span> <span class="k2">(</span>QueryPerformanceFrequency<span class="k2">(</span><span class="k3">&amp;</span>fred<span class="k2">)</span><span class="k2">)</span> <span class="k2">{</span></td></tr><tr><td class="number">5</td><td>    ms_per_QPC_tick <span class="k3">=</span> <span class="n">1000</span>.<span class="n">0</span> <span class="k3">/</span> fred.QuadPart<span class="k2">;</span></td></tr><tr><td class="number">6</td><td>  <span class="k2">}</span></td></tr><tr><td class="number">7</td><td>  <span class="k1">return</span> <span class="k3">-</span><span class="n">1</span><span class="k2">;</span><span class="c">//do whatever you do on an error</span></td></tr><tr><td class="number">8</td><td><span class="k2">}</span></td></tr><tr><td class="number">9</td><td><span class="k1">volatile</span> <span class="k1">double</span> get_time_ms<span class="k2">(</span><span class="k2">)</span> <span class="k2">{</span></td></tr><tr><td class="number">10</td><td>  LARGE_INTEGER bob<span class="k2">;</span></td></tr><tr><td class="number">11</td><td>  <span class="k1">if</span> <span class="k2">(</span>QueryPerformanceCounter<span class="k2">(</span><span class="k3">&amp;</span>bob<span class="k2">)</span><span class="k2">)</span> <span class="k2">{</span></td></tr><tr><td class="number">12</td><td>    <span class="k1">return</span> bob.QuadPart <span class="k3">*</span> ms_per_QPC_tick<span class="k2">;</span></td></tr><tr><td class="number">13</td><td>  <span class="k2">}</span></td></tr><tr><td class="number">14</td><td>  <span class="k1">return</span> <span class="k3">-</span><span class="n">1</span><span class="k2">;</span><span class="c">//do whatever you do on an error</span></td></tr><tr><td class="number">15</td><td><span class="k2">}</span></td></tr></tbody></table></div></div><p>

edit:
</p><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
How should I use Orz&#39;s routines?<br />I need to see a main loop implemented with those routines to understand how they work.
</p></div></div><p>
That is the main loop there in my first post, and again in this post.  It&#39;s untested, but is a demonstration of the concepts.  If you want one with delta-timing instead, just ask.  </p><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
From Pmask libray you have test.c and test2.c which use Orz&#39;s timing routines so all your need are filled .
</p></div></div><p>

Hm... not necessarily a good idea... (edit: I feel kinda stupid saying that something of mine isn&#39;t a good example for some purpose, but really the PMASK tests weren&#39;t written with this is mind... perhaps I should clean up test2.c sometime...)<br />test.c does not use any timing routines from my get_time.c or anything else except Allegro.  It does not use high resolution time.  So, it is not really a good example.  edit: its timing method is also totally inappropriate for a game<br />test.2 does use my timing routines.  However, it&#39;s not the best example as the main loop is kinda quick-and-dirty, cluttered up with text output and keyboard input stuff, and whatnot.  Still, it is an example of using my time functions to time something in a relatively smart manner compared to many allegro example programs.  It&#39;s also undocumented, and uses different priorities than many games might prefer. (for instance it will never use more than 50% of CPU time on graphics)
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (orz)</author>
		<pubDate>Fri, 26 Jan 2007 04:29:13 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>Thank you very much! I&#39;ll try to implement your routines now!
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Paul whoknows)</author>
		<pubDate>Fri, 26 Jan 2007 05:23:30 +0000</pubDate>
	</item>
</rss>
