Use the Pentium's rdtsc instruction (if available) to implement

QueryPerformanceCounter.
This commit is contained in:
James Abbatiello 2001-02-13 20:20:27 +00:00 committed by Alexandre Julliard
parent 2859af9060
commit 4570478a6e
3 changed files with 99 additions and 5 deletions

View File

@ -518,6 +518,9 @@ typedef struct _SINGLE_LIST_ENTRY {
#define PF_MMX_INSTRUCTIONS_AVAILABLE 3
#define PF_PPC_MOVEMEM_64BIT_OK 4
#define PF_ALPHA_BYTE_INSTRUCTIONS 5
#define PF_XMMI_INSTRUCTIONS_AVAILABLE 6
#define PF_AMD3D_INSTRUCTIONS_AVAILABLE 7
#define PF_RDTSC_INSTRUCTION_AVAILABLE 8
/* The Win32 register context */

View File

@ -198,6 +198,8 @@ VOID WINAPI GetSystemInfo(
PF[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE;
if (strstr(value,"mmx"))
PF[PF_MMX_INSTRUCTIONS_AVAILABLE] = TRUE;
if (strstr(value,"tsc"))
PF[PF_RDTSC_INSTRUCTION_AVAILABLE] = TRUE;
}
}

View File

@ -7,6 +7,7 @@
/* Misc. new functions - they should be moved into appropriate files
at a later date. */
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
@ -19,6 +20,69 @@ DEFAULT_DEBUG_CHANNEL(win32);
DECLARE_DEBUG_CHANNEL(debug);
static BOOL QUERYPERF_Initialized = 0;
#if defined(__i386__) && defined(__GNUC__)
static BOOL QUERYPERF_RDTSC_Use = 0;
static LONGLONG QUERYPERF_RDTSC_Frequency = 0;
#endif
static void QUERYPERF_Init(void)
{
#if defined(__i386__) && defined(__GNUC__)
/* We are running on i386 and compiling on GCC.
* Do a runtime check to see if we have the rdtsc instruction available
*/
FILE *fp;
char line[256], *s, *value;
double cpuMHz;
TRACE("()\n");
if (IsProcessorFeaturePresent( PF_RDTSC_INSTRUCTION_AVAILABLE ))
{
/* rdtsc is available. However, in order to use it
* we also need to be able to get the processor's
* speed. Currently we do this by reading /proc/cpuinfo
* which makes it Linux-specific.
*/
TRACE("rdtsc available\n");
fp = fopen( "/proc/cpuinfo", "r" );
if (fp)
{
while(fgets( line, sizeof(line), fp ))
{
/* NOTE: the ':' is the only character we can rely on */
if (!(value = strchr( line, ':' )))
continue;
/* terminate the valuename */
*value++ = '\0';
/* skip any leading spaces */
while (*value == ' ') value++;
if ((s = strchr( value, '\n' )))
*s = '\0';
if (!strncasecmp( line, "cpu MHz", strlen( "cpu MHz" ) ))
{
if (sscanf( value, "%lf", &cpuMHz ) == 1)
{
QUERYPERF_RDTSC_Frequency = (LONGLONG)(cpuMHz * 1000000.0);
QUERYPERF_RDTSC_Use = TRUE;
TRACE("using frequency: %lldHz\n", QUERYPERF_RDTSC_Frequency);
break;
}
}
}
fclose(fp);
}
}
#endif
QUERYPERF_Initialized = TRUE;
}
/****************************************************************************
* QueryPerformanceCounter (KERNEL32.564)
*/
@ -26,9 +90,23 @@ BOOL WINAPI QueryPerformanceCounter(PLARGE_INTEGER counter)
{
struct timeval tv;
gettimeofday(&tv,NULL);
counter->s.LowPart = tv.tv_usec+tv.tv_sec*1000000;
counter->s.HighPart = 0;
if (!QUERYPERF_Initialized)
QUERYPERF_Init();
#if defined(__i386__) && defined(__GNUC__)
if (QUERYPERF_RDTSC_Use)
{
/* i586 optimized version */
__asm__ __volatile__ ( "rdtsc"
: "=a" (counter->s.LowPart), "=d" (counter->s.HighPart) );
return TRUE;
}
/* fall back to generic routine (ie, for i386, i486) */
#endif
/* generic routine */
gettimeofday( &tv, NULL );
counter->QuadPart = (LONGLONG)tv.tv_usec + (LONGLONG)tv.tv_sec * 1000000LL;
return TRUE;
}
@ -37,9 +115,20 @@ BOOL WINAPI QueryPerformanceCounter(PLARGE_INTEGER counter)
*/
BOOL WINAPI QueryPerformanceFrequency(PLARGE_INTEGER frequency)
{
frequency->s.LowPart = 1000000;
frequency->s.HighPart = 0;
if (!QUERYPERF_Initialized)
QUERYPERF_Init();
#if defined(__i386__) && defined(__GNUC__)
if (QUERYPERF_RDTSC_Use)
{
frequency->QuadPart = QUERYPERF_RDTSC_Frequency;
return TRUE;
}
#endif
frequency->s.LowPart = 1000000;
frequency->s.HighPart = 0;
return TRUE;
}
/****************************************************************************