Attachment "perfcounter.c" to
ticket [3002022fff]
added by
hgiese
2010-05-15 14:25:38.
#include <stdio.h>
#include <windows.h>
#define TCL_OK 0
#define TCL_ERROR 1
//
// From tclWin32Dll.c
//
/*
*------------------------------------------------------------------------
*
* TclWinCPUID --
*
* Get CPU ID information on an Intel box under Windows
*
* Results:
* Returns TCL_OK if successful, TCL_ERROR if CPUID is not supported or
* fails.
*
* Side effects:
* If successful, stores EAX, EBX, ECX and EDX registers after the CPUID
* instruction in the four integers designated by 'regsPtr'
*
*----------------------------------------------------------------------
*/
int
TclWinCPUID(
unsigned int index, /* Which CPUID value to retrieve. */
unsigned int *regsPtr) /* Registers after the CPUID. */
{
#ifdef HAVE_NO_SEH
EXCEPTION_REGISTRATION registration;
#endif
int status = TCL_ERROR;
#if defined(__GNUC__) && !defined(_WIN64)
/*
* Execute the CPUID instruction with the given index, and store results
* off 'regPtr'.
*/
__asm__ __volatile__(
/*
* Construct an EXCEPTION_REGISTRATION to protect the CPUID
* instruction (early 486's don't have CPUID)
*/
"leal %[registration], %%edx" "\n\t"
"movl %%fs:0, %%eax" "\n\t"
"movl %%eax, 0x0(%%edx)" "\n\t" /* link */
"leal 1f, %%eax" "\n\t"
"movl %%eax, 0x4(%%edx)" "\n\t" /* handler */
"movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */
"movl %%esp, 0xc(%%edx)" "\n\t" /* esp */
"movl %[error], 0x10(%%edx)" "\n\t" /* status */
/*
* Link the EXCEPTION_REGISTRATION on the chain
*/
"movl %%edx, %%fs:0" "\n\t"
/*
* Do the CPUID instruction, and save the results in the 'regsPtr'
* area.
*/
"movl %[rptr], %%edi" "\n\t"
"movl %[index], %%eax" "\n\t"
"cpuid" "\n\t"
"movl %%eax, 0x0(%%edi)" "\n\t"
"movl %%ebx, 0x4(%%edi)" "\n\t"
"movl %%ecx, 0x8(%%edi)" "\n\t"
"movl %%edx, 0xc(%%edi)" "\n\t"
/*
* Come here on a normal exit. Recover the EXCEPTION_REGISTRATION and
* store a TCL_OK status.
*/
"movl %%fs:0, %%edx" "\n\t"
"movl %[ok], %%eax" "\n\t"
"movl %%eax, 0x10(%%edx)" "\n\t"
"jmp 2f" "\n"
/*
* Come here on an exception. Get the EXCEPTION_REGISTRATION that we
* previously put on the chain.
*/
"1:" "\t"
"movl %%fs:0, %%edx" "\n\t"
"movl 0x8(%%edx), %%edx" "\n\t"
/*
* Come here however we exited. Restore context from the
* EXCEPTION_REGISTRATION in case the stack is unbalanced.
*/
"2:" "\t"
"movl 0xc(%%edx), %%esp" "\n\t"
"movl 0x8(%%edx), %%ebp" "\n\t"
"movl 0x0(%%edx), %%eax" "\n\t"
"movl %%eax, %%fs:0" "\n\t"
:
/* No outputs */
:
[index] "m" (index),
[rptr] "m" (regsPtr),
[registration] "m" (registration),
[ok] "i" (TCL_OK),
[error] "i" (TCL_ERROR)
:
"%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
status = registration.status;
#elif defined(_MSC_VER) && !defined(_WIN64)
/*
* Define a structure in the stack frame to hold the registers.
*/
_try {
_asm {
push ebx
push ecx
push edx
mov eax, regs.dw0
cpuid
mov regs.dw0, eax
mov regs.dw1, ebx
mov regs.dw2, ecx
mov regs.dw3, edx
pop edx
pop ecx
pop ebx
}
/*
* Copy regs back out to the caller.
*/
regsPtr[0] = regs.dw0;
regsPtr[1] = regs.dw1;
regsPtr[2] = regs.dw2;
regsPtr[3] = regs.dw3;
status = TCL_OK;
} __except(EXCEPTION_EXECUTE_HANDLER) {
/* do nothing */
}
#elif defined(__BORLANDC__)
// Code from
// http://groups.google.com/group/borland.public.cppbuilder.language/browse_thread/thread/b497c052f5554d96/6ae833b0f70b8e84?q=cpuid+OR+cpu-id+group:borland.public.cppbuilder*#6ae833b0f70b8e84
__asm {
PUSH EBX // Save affected register
PUSH EDI
MOV EDI,regsPtr // destination
MOV EAX,index
DW 0xA20F // CPUID Command}
STOSD // CPUID[1]
MOV EAX,EBX
STOSD // CPUID[2]
MOV EAX,ECX
STOSD // CPUID[3]
MOV EAX,EDX
STOSD // CPUID[4]
POP EDI // Restore registers
POP EBX
}
status = TCL_OK;
#else
/*
* Don't know how to do assembly code for this compiler and/or
* architecture.
*/
#endif
return status;
}
// Adapted from tclWinTime.c
int main(void) {
unsigned int regs[5], tmp, res;
LARGE_INTEGER frequ;
// Show the counter's frequency
if (! QueryPerformanceFrequency(&frequ)) {
printf("No performance counter.\n");
} else {
printf("Performance counter's frequency: %lu Hz.\n", frequ.QuadPart);
}
// Info for code '0'
if (TclWinCPUID(0, regs) != TCL_OK) {
printf("TclWinCPUID with code '0' failed.\n");
return 1;
}
// Show info: Have to re-arrange the content of 'regs'
regs[4] = 0; // delimit string
// swap regs[2] & regs[3]
tmp = regs[2];
regs[2] = regs[3];
regs[3] = tmp;
printf("Results of CPUID(0): %s\n", ®s[1]);
res = (strcmp((const char *)®s[1], "GenuineIntel") == 0);
printf("'performance counter available' (test part 1) (1 == ok)? %d\n", res);
// Info for code '1'
if (TclWinCPUID(1, regs) != TCL_OK) {
printf("TclWinCPUID with code '1' failed.\n");
return 1;
}
// Apply the test from NativeGetTime (2nd part)
/* Pentium 4 */
res = (regs[0]&0x00000F00) == 0x00000F00
/* Extended family Hyperthread */
|| ((regs[0] & 0x00F00000) && (regs[3] & 0x10000000));
printf("Results of CPUID(1)\n");
printf("'performance counter available' (test part 2) (1 == ok)? %d\n", res);
printf("Detailed results\n");
printf("regs[0] = 0x%08X, regs[1] = 0x%08X, regs[3] = 0x%08X\n",
regs[0], regs[1], regs[3]);
return 0;
}