QueryPerformanceCounter

James Abbatiello abbeyj at WPI.EDU
Wed Feb 7 01:19:02 CST 2001


Changelog:
	James Abbatiello <jabbey at codeweavers.com>
	Use the Pentium's rdtsc instruction (if available) to implement 
QueryPerformanceCounter.

-- 
James Abbatiello

-------------- next part --------------
Index: misc/cpu.c
===================================================================
RCS file: /home/wine/wine/misc/cpu.c,v
retrieving revision 1.17
diff -u -r1.17 cpu.c
--- misc/cpu.c	2000/12/13 20:22:47	1.17
+++ misc/cpu.c	2001/02/07 07:05:26
@@ -198,6 +198,8 @@
 				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;
 
 		}
 	}
Index: win32/newfns.c
===================================================================
RCS file: /home/wine/wine/win32/newfns.c,v
retrieving revision 1.27
diff -u -r1.27 newfns.c
--- win32/newfns.c	2000/11/28 22:33:46	1.27
+++ win32/newfns.c	2001/02/07 07:05:26
@@ -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 @@
 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 @@
 {
     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 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;
 }
 
 /****************************************************************************
Index: include/winnt.h
===================================================================
RCS file: /home/wine/wine/include/winnt.h,v
retrieving revision 1.82
diff -u -r1.82 winnt.h
--- include/winnt.h	2001/01/22 02:17:30	1.82
+++ include/winnt.h	2001/02/07 07:05:27
@@ -514,6 +514,9 @@
 #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 */


More information about the wine-patches mailing list