PDA

View Full Version : Timing, FPS + CPU Throttle


millka
04-02-2005, 12:05 PM
Hi,

i just noticed that someone (mashiharu ?) is working on the rendering loop to throttle the CPU usage.

As far as i understand the new code, it uses a maximum setting for FPS (e.g. 20 frames per second = 50 ms (millisec) per frame). At the end of each frame drawn, it checks how long it took to draw that frame (e.g. 33 ms). If that time is less than the time derived from the max FPS setting (e.g. 50 - 33 = 17 ms), the rendering loop doesnt start to draw the next frame, but "sleeps" for the rest of the frames time (e.g. 17 ms), using Thread.Sleep (). That allows other threads to run and lowers the CPU usage.

Since the standard Win32 timing APIs (e.g. GetTickCount) are not exact enough for really precise timing stuff, the new code uses the Win32 APIs QueryPerformanceCounter instead.

The new timing code splits the time to sleep into two parts. To sleep during part one, it calls the API Thread.Sleep, which gives up that threads time slice, allows other threads to run, and lowers CPU usage of the sleeping thread to idle. After that passive sleep phase follows an active sleep phase. During part two, the thread loops checking the QueryPerformanceTimer APIs, until the time of part two is over. The active sleep of course uses 100 % CPU ..

Recently at work, i had to solve a quite similar timing problem (although not graphics related). So i would like to share what ive learned there.

The QueryPerformance APIs (aka high res timer) works with one of the following two frequencies:
3,579,545 Hz = 0.279 µs (microsec) (on newer machines, e.g. Pentium 3 or better)
1,193,180 Hz = 0.838 µs (on older machines)
These frequencies are derived from hardware - google for those exact Hz numbers to find out more ...

Anyway, the QueryPerformance APIs allow a resolution of at least 1 µs or even better. Unfortunately, most Win32 timing APIs (GetTickCount, GetSystemTime / GetSystemTimeAsFileTime, Sleep and Thread.Sleep) seem to ignore that resolution and stick to a resolution of 10 ms (or 55 ms on very old machines).

That means, if a thread wants to sleep for 12 ms, it will sleep for 20 ms instead.

I would like to suggest two changes to the new timing code in function WorldWindow.RunMainLoop (), which should allow WorldWind to use more precise sleep times.

Using my example values from above, WW needs to sleep exactly e.g. 17 ms after the frame just drawn. The new timing code splits the sleep time (T) into two parts (Tp and Ta). During the first (passive) part, it sleeps using the API Thread.Sleep for Tp ms. After that it loops, checking the QueryPerformanceTimer APIs, until T is over.

Right now, Tp is calculated as T - SleepOverHeadSeconds (= 2ms).

E.g.: T = 17 ms, Tp = 15 ms.

Thread.Sleep is called with 15 ms, but will sleep 20 ms instead, because it rounds up its parameter to the next integral multiple of 10 ms.

Change A: Change the constant SleepOverHeadSeconds from 0.002 (= 2 ms) to 0.010 (= 10 ms) to avoid sleeping too long.

E.g.: T = 17 ms, Tp = 7 ms.

Thread.Sleep will be called with 7 ms, but will sleep for 10 ms instead. That leaves 7 ms for the active sleep phase.

Change B: While burning time in sleep phase two, use Thread.Sleep (0) to reduce CPU usage in phase two.

Maybe the timing stuff works a bit different when DirectX is active, but i would be very surprised by that ...

However, all that still leaves a problem:
If the passive sleep phase (using Thread.Sleep) always is a little bit too long, the CPU usage will be low (cause there will be no active sleep phase), but the FPS wont be exact.
If the passive sleep phase always is a little bit too short (which will happen with my suggested change a), the CPU usage will be higher, but the FPS would be more precise.

I cant see how that problem really can be solved, until MS decides to implement a more precise Sleep API, which sleeps for exactly x ms ..

Which means, we will have to fiddle with SleepOverHeadSeconds values between 1 and 10 ms, until we find an acceptable balance of those two extreme cases ..

Beansprout
04-02-2005, 12:14 PM
Hi,
Feel free to look at / join the CVS group, and come into http://chat.worldwindcentral.com - that's the best place to talk to the devs, and mashi is around now.

Manveru
04-02-2005, 01:31 PM
Hi,
Fps locking is a good idea. In addition I recommend to add a option witch allows the user to define the cpu priotity directly out of the program. The chosen priority is then saved of course for further WW sessions.

I came across this idea because I use WW often along with other programs (browser, winamp, etc.) and don't wanna be disturbed while surfing or listening to music.
So I set WW to "Below normal" priority.

It would be very nice, if I hadn't to do it every single time I start WW.

Greets Manveru

Unregistered
09-05-2006, 11:17 PM
Call timeBeginPeriod(1) at start of your application.
Call timeEndPeriod(1) at end of your application.
And your thread will wait for more or less 1ms when you call Sleep ( 1 ).

Doing a Sleep ( 0 ) do not release CPU usage, sleep at least 1ms to see the CPU usage going down, which is mainly useful only on laptop to save the precious battery power.

Cheers :)

Alexis.