Use the Pentium's rdtsc instruction (if available) to implement
QueryPerformanceCounter.
This commit is contained in:
parent
2859af9060
commit
4570478a6e
|
@ -518,6 +518,9 @@ typedef struct _SINGLE_LIST_ENTRY {
|
||||||
#define PF_MMX_INSTRUCTIONS_AVAILABLE 3
|
#define PF_MMX_INSTRUCTIONS_AVAILABLE 3
|
||||||
#define PF_PPC_MOVEMEM_64BIT_OK 4
|
#define PF_PPC_MOVEMEM_64BIT_OK 4
|
||||||
#define PF_ALPHA_BYTE_INSTRUCTIONS 5
|
#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 */
|
/* The Win32 register context */
|
||||||
|
|
|
@ -198,6 +198,8 @@ VOID WINAPI GetSystemInfo(
|
||||||
PF[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE;
|
PF[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE;
|
||||||
if (strstr(value,"mmx"))
|
if (strstr(value,"mmx"))
|
||||||
PF[PF_MMX_INSTRUCTIONS_AVAILABLE] = TRUE;
|
PF[PF_MMX_INSTRUCTIONS_AVAILABLE] = TRUE;
|
||||||
|
if (strstr(value,"tsc"))
|
||||||
|
PF[PF_RDTSC_INSTRUCTION_AVAILABLE] = TRUE;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
/* Misc. new functions - they should be moved into appropriate files
|
/* Misc. new functions - they should be moved into appropriate files
|
||||||
at a later date. */
|
at a later date. */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -19,6 +20,69 @@ DEFAULT_DEBUG_CHANNEL(win32);
|
||||||
DECLARE_DEBUG_CHANNEL(debug);
|
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)
|
* QueryPerformanceCounter (KERNEL32.564)
|
||||||
*/
|
*/
|
||||||
|
@ -26,9 +90,23 @@ BOOL WINAPI QueryPerformanceCounter(PLARGE_INTEGER counter)
|
||||||
{
|
{
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
|
||||||
gettimeofday(&tv,NULL);
|
if (!QUERYPERF_Initialized)
|
||||||
counter->s.LowPart = tv.tv_usec+tv.tv_sec*1000000;
|
QUERYPERF_Init();
|
||||||
counter->s.HighPart = 0;
|
|
||||||
|
#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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,9 +115,20 @@ BOOL WINAPI QueryPerformanceCounter(PLARGE_INTEGER counter)
|
||||||
*/
|
*/
|
||||||
BOOL WINAPI QueryPerformanceFrequency(PLARGE_INTEGER frequency)
|
BOOL WINAPI QueryPerformanceFrequency(PLARGE_INTEGER frequency)
|
||||||
{
|
{
|
||||||
frequency->s.LowPart = 1000000;
|
if (!QUERYPERF_Initialized)
|
||||||
frequency->s.HighPart = 0;
|
QUERYPERF_Init();
|
||||||
|
|
||||||
|
#if defined(__i386__) && defined(__GNUC__)
|
||||||
|
if (QUERYPERF_RDTSC_Use)
|
||||||
|
{
|
||||||
|
frequency->QuadPart = QUERYPERF_RDTSC_Frequency;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
frequency->s.LowPart = 1000000;
|
||||||
|
frequency->s.HighPart = 0;
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
|
Loading…
Reference in New Issue