> is this known behavior of the KeQueryPerformanceCounter() API in single
processor systems?
Any help would be appreciated.
Here is the um code I successfully use[d].
The idea (whose idea? Mark’s, of course, who else…) is to replace
QueryPerformanceCounter by a Pentium instruction RDTSC.
Times I am getting from RDTSC are NOT comnpatible with those
fetched through the QueryPerformanceCounter wrapper.
It’s easy to port this snippet to km, but beware of time comparisons!
Either do it through RDTSC in both worlds or … .
Hope it helps.
// HighResTimer.cpp
#include “HighResTimer.h”
// time-measuring stuff - start
// after John Panzer (C/C++ Users Journal, January 1999 Volume 17 Number 1,
// Automatic Code Instrumentation).
// We define void queryTicks(__int64* pTicks) to be as fast as possible in
Pentium case.
// If it’s not Pentium, it’s just a thin wrapper around
QueryPerformanceCounter.
#define PENTIUM
//#undef PENTIUM
#ifdef PENTIUM
inline void RDTSC(DWORD& low, long& high) { // Pentium-specific RDTSC
instruction -
DWORD L; long H; // from www.sysinternals.com
_asm {
push eax
push edx
_emit 0Fh
_emit 31h
mov DWORD PTR [L], eax
mov DWORD PTR [H], edx
pop edx
pop eax
}
low = L; high = H;
}
void queryTickFreq(__int64* pTickFreq) {
static __int64 ticksPerSec=0;
if(!ticksPerSec) { // first time here - calculate ratio
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
__int64 qpf1, qpf2, qc1, qc2;
QueryPerformanceCounter((LARGE_INTEGER*)&qpf1);
RDTSC(((LARGE_INTEGER&)qc1).LowPart,
((LARGE_INTEGER&)qc1).HighPart);
Sleep(100);
QueryPerformanceCounter((LARGE_INTEGER*)&qpf2);
RDTSC(((LARGE_INTEGER&)qc2).LowPart,
((LARGE_INTEGER&)qc2).HighPart);
__int64 qpcTicks=qpf2 - qpf1;
__int64 qcTicks=qc2 - qc1;
long double ratio=((long double)qcTicks)/((long double)qpcTicks);
ticksPerSec=(__int64)(ratio*(long double)freq.QuadPart);
}
*pTickFreq=ticksPerSec;
}
// inline
void queryTicks(__int64* pTicks) {
RDTSC(((LARGE_INTEGER*)pTicks)->LowPart,
((LARGE_INTEGER*)pTicks)->HighPart);
}
#else // not a Pentium:
void queryTickFreq(__int64* pTickFreq) {
QueryPerformanceFrequency((LARGE_INTEGER*)pTickFreq);
}
// inline
void queryTicks(__int64* pTicks) {
QueryPerformanceCounter((LARGE_INTEGER*)pTicks);
}
#endif
double diffSecs(__int64 start, __int64 finish) {
__int64 diff=finish-start, temp;
double ddiff=(double)diff;
queryTickFreq(&temp);
return ddiff / temp;
}
//
****************************************************************************
/*1*
inline void RDTSC_LI(DWORD& low, long& high) { // Pentium-specific RDTSC
instruction -
DWORD L; long H; // from www.sysinternals.com
_asm {
push eax
push edx
_emit 0Fh
_emit 31h
mov DWORD PTR [L], eax
mov DWORD PTR [H], edx
pop edx
pop eax
}
low = L; high = H;
}
void queryTickFreqLI(PLARGE_INTEGER pFreq) {
static LARGE_INTEGER ticksPerSec;
if(!ticksPerSec.QuadPart) { // first time here - calculate ratio
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
LARGE_INTEGER qpf1, qpf2, qc1, qc2;
QueryPerformanceCounter((LARGE_INTEGER*)&qpf1);
RDTSC_LI(((LARGE_INTEGER&)qc1).LowPart, ((LARGE_INTEGER&)qc1).HighPart);
Sleep(100);
QueryPerformanceCounter((LARGE_INTEGER*)&qpf2);
RDTSC_LI(((LARGE_INTEGER&)qc2).LowPart, ((LARGE_INTEGER&)qc2).HighPart);
LARGE_INTEGER qpcTicks;
qpcTicks.QuadPart=qpf2.QuadPart-qpf1.QuadPart;
LARGE_INTEGER qcTicks;
qcTicks.QuadPart=qc2.QuadPart-qc1.QuadPart;
long double ratio=((long double)qcTicks.QuadPart)/((long
double)qpcTicks.QuadPart);
ticksPerSec.QuadPart=(LONGLONG)(ratio*(long double)freq.QuadPart);
}
*pFreq=ticksPerSec;
}
long double queryRatioLI_k(PLARGE_INTEGER pFreq) {
static LARGE_INTEGER ticksPerSec;
static long double ratio;
if(!ticksPerSec.QuadPart) { // first time here - calculate ratio
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
LARGE_INTEGER qpf1, qpf2, qc1, qc2;
QueryPerformanceCounter((LARGE_INTEGER*)&qpf1);
RDTSC_LI(((LARGE_INTEGER&)qc1).LowPart, ((LARGE_INTEGER&)qc1).HighPart);
Sleep(100);
QueryPerformanceCounter((LARGE_INTEGER*)&qpf2);
RDTSC_LI(((LARGE_INTEGER&)qc2).LowPart, ((LARGE_INTEGER&)qc2).HighPart);
LARGE_INTEGER qpcTicks;
qpcTicks.QuadPart=qpf2.QuadPart-qpf1.QuadPart;
LARGE_INTEGER qcTicks;
qcTicks.QuadPart=qc2.QuadPart-qc1.QuadPart;
ratio=((long double)qcTicks.QuadPart)/((long double)qpcTicks.QuadPart);
ticksPerSec.QuadPart=(LONGLONG)(ratio*(long double)freq.QuadPart);
}
*pFreq=ticksPerSec;
return ratio;
}
void queryTicksLI(PLARGE_INTEGER pTicks) {
RDTSC_LI(pTicks->LowPart, pTicks->HighPart);
}
double diffSecsLI(LARGE_INTEGER start, LARGE_INTEGER finish) {
LARGE_INTEGER diff, temp;
diff.QuadPart=finish.QuadPart-start.QuadPart;
double ddiff=(double)diff.QuadPart;
queryTickFreqLI(&temp);
return ddiff/temp.QuadPart;
}
double diffSecsLI_uk(LARGE_INTEGER start_u, LARGE_INTEGER finish_k) {
LARGE_INTEGER diff, temp;
diff.QuadPart=finish_k.QuadPart-(__int64)(start_u.QuadPart*queryRatioLI_k(&temp));
double ddiff=(double)diff.QuadPart;
// queryTickFreqLI(&temp);
return ddiff/temp.QuadPart;
}
*1*/
/*2*/
void queryTickFreqLI(PLARGE_INTEGER pFreq) {
QueryPerformanceFrequency(pFreq);
}
void queryTicksLI(PLARGE_INTEGER pTicks) {
QueryPerformanceCounter(pTicks);
}
double diffSecsLI(LARGE_INTEGER start, LARGE_INTEGER finish) {
LARGE_INTEGER diff, temp;
diff.QuadPart=finish.QuadPart-start.QuadPart;
double ddiff=(double)diff.QuadPart;
queryTickFreqLI(&temp);
return ddiff/temp.QuadPart;
}
/*2*/
//
****************************************************************************
----- Original Message -----
From: Nixon, Brian M
To: Windows System Software Devs Interest List
Sent: Friday, December 09, 2005 6:40 PM
Subject: [ntdev] KeQueryPerformanceCounter() anomalies
I ran into a problem in the last few days, and I’m wondering if it’s
something that anyone else has ever encountered. The basic problem is that
I have an ISR that needs to run at a particular periodic rate, and I need to
know whether or not it is hitting that rate. We’ve seen a variety of
systems that have had problems with maintaining that rate, and this has been
a good way to verify that we couldn’t maintain the tick rate, and to know
how many ticks to process to catch up.
Until today that is. Today, on several systems, I noticed something that I
didn’t think was possible. Running on a single CPU system (P4) without
hyperthreading, subsequent calls to KeQueryPerformanceCounter() returned
*smaller* numbers.
For example:
Call 1 returned: 222643334
Call 2 returned: 222624197
Call 3 returned: 222648107
Call 2 was supposed to return something in the neighborhood of 222644527, as
each function call is supposed to be made 2ms after the previous call. What
I can’t figure out is why call 2 returns a timestamp that is about 16ms
*before* call 1, and then call 3 is 4 ms after call 1 (as expected), but 20
ms after call 2 (not expected).
Did I just figure out how to tear the fabric of the universe with my driver,
or is this known behavior of the KeQueryPerformanceCounter() API in single
processor systems? Any help would be appreciated.
Thanks in advance,
Brian
Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256
You are currently subscribed to ntdev as: unknown lmsubst tag argument: ‘’
To unsubscribe send a blank email to xxxxx@lists.osr.com