Merge CPU detection code into misc/cpu.c.
Add support for Mhz registry key.
This commit is contained in:
parent
af86c99260
commit
69e609d9e5
62
misc/cpu.c
62
misc/cpu.c
|
@ -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
|
||||
|
@ -91,6 +95,7 @@ static inline int have_cpuid(void)
|
|||
}
|
||||
|
||||
static BYTE PF[64] = {0,};
|
||||
static ULONGLONG cpuHz = 1000000000; /* default to a 1GHz */
|
||||
|
||||
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 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;
|
||||
|
@ -138,10 +144,14 @@ static void create_registry_keys( const SYSTEM_INFO *info )
|
|||
if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
|
||||
{
|
||||
WCHAR idW[20];
|
||||
DWORD cpuMHz = cpuHz / 1000000;
|
||||
|
||||
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) );
|
||||
|
||||
RtlInitUnicodeString( &valueW, mhzKeyW );
|
||||
NtSetValueKey( hkey, &valueW, 0, REG_DWORD, &cpuMHz, sizeof(DWORD) );
|
||||
NtClose( hkey );
|
||||
}
|
||||
RtlFreeUnicodeString( &nameW );
|
||||
|
@ -151,6 +161,49 @@ static void create_registry_keys( const SYSTEM_INFO *info )
|
|||
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.@]
|
||||
|
@ -179,6 +232,7 @@ VOID WINAPI GetSystemInfo(
|
|||
static int cache = 0;
|
||||
static SYSTEM_INFO cachedsi;
|
||||
|
||||
TRACE("si=0x%p\n", si);
|
||||
if (cache) {
|
||||
memcpy(si,&cachedsi,sizeof(*si));
|
||||
return;
|
||||
|
@ -306,6 +360,14 @@ VOID WINAPI GetSystemInfo(
|
|||
if (sscanf(value,"%d",&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")) ||
|
||||
!strncasecmp(line,"features",strlen("features"))
|
||||
) {
|
||||
|
|
111
win32/newfns.c
111
win32/newfns.c
|
@ -45,117 +45,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(win32);
|
|||
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.@)
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue