ChangeLog: - Move performance frequency code to misc/cpu.c - New function, get_cpu_speed() - Make MHz registry key and QueryPerformanceFrequency use it
Index: win32/newfns.c =================================================================== RCS file: /home/wine/wine/win32/newfns.c,v retrieving revision 1.47 diff -u -r1.47 newfns.c --- win32/newfns.c 22 May 2003 03:41:27 -0000 1.47 +++ win32/newfns.c 4 Jul 2003 18:37:56 -0000 @@ -45,117 +45,6 @@ WINE_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.@) - */ -BOOL WINAPI QueryPerformanceCounter(PLARGE_INTEGER counter) -{ - struct timeval tv; - - 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 * 1000000; - return TRUE; -} - -/**************************************************************************** - * QueryPerformanceFrequency (KERNEL32.@) - */ -BOOL WINAPI QueryPerformanceFrequency(PLARGE_INTEGER frequency) -{ - 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; -} - /**************************************************************************** * FlushInstructionCache (KERNEL32.@) */ Index: misc/cpu.c =================================================================== RCS file: /home/wine/wine/misc/cpu.c,v retrieving revision 1.34 diff -u -r1.34 cpu.c --- misc/cpu.c 30 Jun 2003 18:28:08 -0000 1.34 +++ misc/cpu.c 4 Jul 2003 18:37:57 -0000 @@ -36,6 +36,10 @@ #include <string.h> #include <stdio.h> #include <stdlib.h> +#ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +#endif + #define NONAMELESSUNION #define NONAMELESSSTRUCT @@ -90,6 +94,48 @@ #endif } +static LONGLONG get_cpu_speed() { + +#ifdef linux + FILE *fp; + char line[256], *s, *value; + double cpuMHz; + + 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) { + LONGLONG res = (LONGLONG)(cpuMHz * 1000000.0); + + TRACE("frequency retrieved as: %lldHz\n", res); + fclose(fp); + return res; + } + } + } + fclose(fp); + } + ERR("Could not locate CPU speed in /proc/cpuinfo, please report to http://bugs.winehq.com/ with the contents of that file\n"); + ERR("Defaulting to 1000Mhz\n"); +#endif + + /* either a fault or we're not on linux */ + return 1000000000; +} + + static BYTE PF[64] = {0,}; static void create_registry_keys( const SYSTEM_INFO *info ) @@ -102,6 +148,7 @@ static const WCHAR cpuW[] = {'C','e','n','t','r','a','l','P','r','o','c','e','s','s','o','r',0}; static const WCHAR IdentifierW[] = {'I','d','e','n','t','i','f','i','e','r',0}; static const WCHAR SysidW[] = {'A','T',' ','c','o','m','p','a','t','i','b','l','e',0}; + static const WCHAR mhzKeyW[] = {'~','M','H','z',0}; int i; HKEY hkey, system_key, cpu_key; @@ -130,7 +177,7 @@ { for (i = 0; i < info->dwNumberOfProcessors; i++) { - char num[10], id[20]; + char num[10], id[20]; attr.RootDirectory = cpu_key; sprintf( num, "%d", i ); @@ -138,10 +185,15 @@ if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) { WCHAR idW[20]; + DWORD speed = get_cpu_speed() / 1000; sprintf( id, "CPU %ld", info->dwProcessorType ); RtlMultiByteToUnicodeN( idW, sizeof(idW), NULL, id, strlen(id)+1 ); NtSetValueKey( hkey, &valueW, 0, REG_SZ, idW, (strlenW(idW)+1)*sizeof(WCHAR) ); + + RtlFreeUnicodeString( &valueW ); + RtlInitUnicodeString( &valueW, mhzKeyW); + NtSetValueKey( hkey, &valueW, 0, REG_DWORD, &speed, sizeof(DWORD) ); NtClose( hkey ); } RtlFreeUnicodeString( &nameW ); @@ -151,6 +203,52 @@ NtClose( system_key ); } +/**************************************************************************** + * QueryPerformanceCounter (KERNEL32.@) + */ +BOOL WINAPI QueryPerformanceCounter(PLARGE_INTEGER counter) +{ + struct timeval tv; + +#if defined(__i386__) && defined(__GNUC__) + if (IsProcessorFeaturePresent( PF_RDTSC_INSTRUCTION_AVAILABLE )) { + /* i586 optimized version */ + __asm__ __volatile__ ( "rdtsc" + : "=a" (counter->s.LowPart), "=d" (counter->s.HighPart) ); + return TRUE; + } +#endif + + /* fall back to generic routine (ie, for i386, i486) */ + gettimeofday( &tv, NULL ); + counter->QuadPart = (LONGLONG)tv.tv_usec + (LONGLONG)tv.tv_sec * 1000000; + return TRUE; +} + + +/**************************************************************************** + * QueryPerformanceFrequency (KERNEL32.@) + */ +BOOL WINAPI QueryPerformanceFrequency(PLARGE_INTEGER frequency) +{ + +#if defined(__i386__) && defined(__GNUC__) && 0 + if (IsProcessorFeaturePresent( PF_RDTSC_INSTRUCTION_AVAILABLE )) { + /* The way Windows calculates this value is unclear, however simply using the CPU frequency + gives a value out by approximately a thousand. That can cause some applications to crash, + so we divide here to make our number more similar to the one Windows gives */ + frequency->QuadPart = get_cpu_speed() / 1000; + TRACE("returning %lld\n", frequency->QuadPart); + return TRUE; + } +#endif + + frequency->s.LowPart = 1000000; + frequency->s.HighPart = 0; + TRACE("returning %lld\n", frequency->QuadPart); + return TRUE; +} + /*********************************************************************** * GetSystemInfo [KERNEL32.@]