Commit 69e609d9 authored by Mike Hearn's avatar Mike Hearn Committed by Alexandre Julliard

Merge CPU detection code into misc/cpu.c.

Add support for Mhz registry key.
parent af86c992
...@@ -36,6 +36,10 @@ ...@@ -36,6 +36,10 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#define NONAMELESSUNION #define NONAMELESSUNION
#define NONAMELESSSTRUCT #define NONAMELESSSTRUCT
...@@ -91,6 +95,7 @@ static inline int have_cpuid(void) ...@@ -91,6 +95,7 @@ static inline int have_cpuid(void)
} }
static BYTE PF[64] = {0,}; static BYTE PF[64] = {0,};
static ULONGLONG cpuHz = 1000000000; /* default to a 1GHz */
static void create_registry_keys( const SYSTEM_INFO *info ) static void create_registry_keys( const SYSTEM_INFO *info )
{ {
...@@ -102,6 +107,7 @@ static void create_registry_keys( const SYSTEM_INFO *info ) ...@@ -102,6 +107,7 @@ static void create_registry_keys( const SYSTEM_INFO *info )
static const WCHAR cpuW[] = {'C','e','n','t','r','a','l','P','r','o','c','e','s','s','o','r',0}; 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 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 SysidW[] = {'A','T',' ','c','o','m','p','a','t','i','b','l','e',0};
static const WCHAR mhzKeyW[] = {'~','M','H','z',0};
int i; int i;
HKEY hkey, system_key, cpu_key; HKEY hkey, system_key, cpu_key;
...@@ -138,10 +144,14 @@ static void create_registry_keys( const SYSTEM_INFO *info ) ...@@ -138,10 +144,14 @@ static void create_registry_keys( const SYSTEM_INFO *info )
if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
{ {
WCHAR idW[20]; WCHAR idW[20];
DWORD cpuMHz = cpuHz / 1000000;
sprintf( id, "CPU %ld", info->dwProcessorType ); sprintf( id, "CPU %ld", info->dwProcessorType );
RtlMultiByteToUnicodeN( idW, sizeof(idW), NULL, id, strlen(id)+1 ); RtlMultiByteToUnicodeN( idW, sizeof(idW), NULL, id, strlen(id)+1 );
NtSetValueKey( hkey, &valueW, 0, REG_SZ, idW, (strlenW(idW)+1)*sizeof(WCHAR) ); NtSetValueKey( hkey, &valueW, 0, REG_SZ, idW, (strlenW(idW)+1)*sizeof(WCHAR) );
RtlInitUnicodeString( &valueW, mhzKeyW );
NtSetValueKey( hkey, &valueW, 0, REG_DWORD, &cpuMHz, sizeof(DWORD) );
NtClose( hkey ); NtClose( hkey );
} }
RtlFreeUnicodeString( &nameW ); RtlFreeUnicodeString( &nameW );
...@@ -151,6 +161,49 @@ static void create_registry_keys( const SYSTEM_INFO *info ) ...@@ -151,6 +161,49 @@ static void create_registry_keys( const SYSTEM_INFO *info )
NtClose( system_key ); 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) );
counter->QuadPart = counter->QuadPart / 1000; /* see below */
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__)
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 = cpuHz / 1000;
return TRUE;
}
#endif
frequency->s.LowPart = 1000000;
frequency->s.HighPart = 0;
return TRUE;
}
/*********************************************************************** /***********************************************************************
* GetSystemInfo [KERNEL32.@] * GetSystemInfo [KERNEL32.@]
...@@ -179,6 +232,7 @@ VOID WINAPI GetSystemInfo( ...@@ -179,6 +232,7 @@ VOID WINAPI GetSystemInfo(
static int cache = 0; static int cache = 0;
static SYSTEM_INFO cachedsi; static SYSTEM_INFO cachedsi;
TRACE("si=0x%p\n", si);
if (cache) { if (cache) {
memcpy(si,&cachedsi,sizeof(*si)); memcpy(si,&cachedsi,sizeof(*si));
return; return;
...@@ -306,6 +360,14 @@ VOID WINAPI GetSystemInfo( ...@@ -306,6 +360,14 @@ VOID WINAPI GetSystemInfo(
if (sscanf(value,"%d",&x)) if (sscanf(value,"%d",&x))
cachedsi.wProcessorRevision = x; cachedsi.wProcessorRevision = x;
} }
if (!strncasecmp(line, "cpu MHz",strlen("cpu MHz"))) {
double cmz;
if (sscanf( value, "%lf", &cmz ) == 1) {
/* SYSTEMINFO doesn't have a slot for cpu speed, so store in a global */
cpuHz = cmz * 1000 * 1000;
TRACE("CPU speed read as %lld\n", cpuHz);
}
}
if ( !strncasecmp(line,"flags",strlen("flags")) || if ( !strncasecmp(line,"flags",strlen("flags")) ||
!strncasecmp(line,"features",strlen("features")) !strncasecmp(line,"features",strlen("features"))
) { ) {
......
...@@ -45,117 +45,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(win32); ...@@ -45,117 +45,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(win32);
WINE_DECLARE_DEBUG_CHANNEL(debug); 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.@) * FlushInstructionCache (KERNEL32.@)
*/ */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment