(Scheduler Latency Part II)

J

John Lafrowda

Hi all,

after my last posting, I received some information that original windows
timers are limited by the internal clock precision which is normally set to
10 ~ 15 ms. I also learned that this can be changed by undocumented kernel
methods (NtSetTimerResolution). However, I have also found information that
describes a simpler way to generate a faster / more precise timer. According
to this information, the multimedia timers should do the job. The
MM-Timer-API looks quite basic to me - but nevertheless, I cannoz get it to
work properly. When I try to estabilsh a periodic timer on a 1 ms basis
(which was done by other people as they say in NGs), I still end up with a
timer that is directly called again after it is finished (--> with 0 ms
delay) or alternatively with the 15 ms delay of the original clock rate. The
result is the same as with standard timers: In _average_, the timer produces
a delay of 1 ms.

Below is my code. It creates an MM timer with a perodic event to be called
every 1 ms. After establishing the timer, the main thread is going to sleep
for half a second. Then, the timer is killed and the delay times that were
detected by the first 10 calls to the timer method are presented.

Can anyone tell me where I went wrong?

Regards,

John


#include <windows.h>
#include <stdio.h>

int d[1000];
int dc;
int OldTime;
int NewTime;

void CALLBACK TimerProc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD
dw2){
NewTime = GetTickCount();
d[dc] = NewTime-OldTime;
OldTime = NewTime;
dc++;
}

int main(){
int i;
TIMECAPS TimeCaps;
MMRESULT TimerID;

dc = 0;
timeGetDevCaps(&TimeCaps, sizeof(TIMECAPS));
printf("Min: %d, Max: %d\n", TimeCaps.wPeriodMin, TimeCaps.wPeriodMax);
OldTime = GetTickCount();
timeBeginPeriod(1);
TimerID = timeSetEvent(1, 0, TimerProc, 0,
TIME_PERIODIC|TIME_CALLBACK_FUNCTION);
Sleep(500);
timeKillEvent(TimerID);
timeEndPeriod(1);
for(i = 0; i < 10; i++){
printf("Delay[%d]: %d\n", i, d);
}
return 0;
}
 
L

Lucian Wischik

John Lafrowda said:
work properly. When I try to estabilsh a periodic timer on a 1 ms basis
(which was done by other people as they say in NGs), I still end up with a
timer that is directly called again after it is finished (--> with 0 ms
delay) or alternatively with the 15 ms delay of the original clock rate. The
result is the same as with standard timers: In _average_, the timer produces
a delay of 1 ms.
...
void CALLBACK TimerProc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD
dw2){
NewTime = GetTickCount();
dc++;
}

Just a guess... but I suspect Windows maintains an internal tick count
which is incremented every 15ms using the normal coarse timers; when
you call GetTickCount it returns this internal count.

Therefore, even if your MMtimers are working perfectly and are being
called every 1ms, then your code will fail to measure this accurately.


(sorry, can't read up on MSDN just now to confirm my explanation...
every time I attempt to navigate to the page on "timeSetEvent" it
crashes on me!)
 
J

John Lafrowda

Thanks to Pavel A. and Lucian!

The problem was finally related to the fact, that I have produced a precise
timer but GetTickCount() cannot measure it. Using QueryPerformanceCounter in
combination with QueryPerformanceFrequency() solved the problem down to the
real minimum rate which is approx. 1 ms.

For interested parties, here is the working code:

#include <windows.h>
#include <stdio.h>

int counter;
LARGE_INTEGER Time[1000];

void CALLBACK TimerProc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD
dw2){
QueryPerformanceCounter(&Time[counter]);
counter++;
}

int main(){
int i;
double f;
TIMECAPS TimeCaps;
MMRESULT TimerID;
LARGE_INTEGER Frequency;

timeGetDevCaps(&TimeCaps, sizeof(TIMECAPS));
printf("Min: %d, Max: %d\n", TimeCaps.wPeriodMin, TimeCaps.wPeriodMax);
counter = 0;
timeBeginPeriod(1);
TimerID = timeSetEvent(1, 0, TimerProc, 0,
TIME_PERIODIC|TIME_CALLBACK_FUNCTION);
Sleep(500);
timeKillEvent(TimerID);
timeEndPeriod(1);
QueryPerformanceFrequency(&Frequency);
f = double(Frequency.QuadPart/1000);
printf("%d\n", Frequency.QuadPart);
for(i = 0; i < 10; i++){
printf("Delay[%d]: %lf\n", i,
(((double)Time[i+1].QuadPart-(double)Time.QuadPart)/f));
}
return 0;
}



Regards,

John
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top