Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

255 lines
6.8 KiB

/******************************Module*Header*******************************\
* Module Name: Perf.c
*
* Performance counter functions. Uses the Pentium performance counters
* if they are available, otherwise falls back to the system QueryPerformance
* api's.
*
* InitPerfCounter MUST be called before using the QUERY_PERFORMANCE_XXX macros
* as it initializes the two global functions pointers.
*
*
*
* Created: 13-10-95
* Author: Stephen Estrop [StephenE]
*
* Copyright (c) 1994 - 1995 Microsoft Corporation. All Rights Reserved.
\**************************************************************************/
#include <windows.h>
#include "Perf.h"
PERFFUNCTION lpQueryPerfCounter;
PERFFUNCTION lpQueryPerfFreqency;
void
GetFrequencyEstimate(
LARGE_INTEGER *li
);
#ifdef TEST
#include <stdio.h>
/******************************Public*Routine******************************\
* main
*
* Program entry point.
*
* History:
* dd-mm-95 - StephenE - Created
*
\**************************************************************************/
int __cdecl main( void )
{
LARGE_INTEGER liP1;
LARGE_INTEGER liP2;
LARGE_INTEGER liPf;
InitPerfCounter();
QUERY_PERFORMANCE_FREQUENCY(&liPf);
// Time a 50 milli second sleep
QUERY_PERFORMANCE_COUNTER(&liP1);
Sleep(50);
QUERY_PERFORMANCE_COUNTER(&liP2);
printf("Pentium counter frequency = %u\n", liPf.LowPart );
printf("Pentium counter %#X%X - %#X%X = %u\n",
liP2.HighPart, liP2.LowPart, liP1.HighPart, liP1.LowPart,
liP2.LowPart - liP1.LowPart
);
printf("Time taken = %6.6f seconds\n",
(double)(liP2.LowPart - liP1.LowPart) / (double)liPf.QuadPart);
return 0;
}
#endif
/******************************Public*Routine******************************\
* InitPerfCounter
*
* Determine (at runtime) if it is possible to use the Pentium performance
* counter. If it is not fall back to the system performance counter.
*
* History:
* dd-mm-95 - StephenE - Created
*
\**************************************************************************/
void
InitPerfCounter(
void
)
{
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
if (sysInfo.dwProcessorType == PROCESSOR_INTEL_PENTIUM) {
lpQueryPerfFreqency = QueryPerfFrequency;
lpQueryPerfCounter = QueryPerfCounter;
}
else {
lpQueryPerfFreqency = (PERFFUNCTION)QueryPerformanceFrequency;
lpQueryPerfCounter = (PERFFUNCTION)QueryPerformanceCounter;
}
}
/******************************Public*Routine******************************\
* QueryPerfFrequency
*
* Determines the clock frequency of a (Pentium) microprocessor. Takes an
* averaged estimate of the clk frequency and then matches it to known
* Pentium clock frequencies. Returns the estimate if a match is not found.
*
* This is an expensive call in cpu terms as it takes at least 16 milli seconds
* just to calculate an averaged estimate of the clock speed. You only need
* to call this function once, make sure you don't call it more times.
*
* History:
* 13-10-95 - StephenE - Created
*
\**************************************************************************/
void WINAPI
QueryPerfFrequency(
LARGE_INTEGER *li
)
{
#ifdef _X86_
#define SAMPLE_SIZE 8
LARGE_INTEGER est;
int i;
li->QuadPart = 0;
for (i = 0; i < SAMPLE_SIZE; i++) {
GetFrequencyEstimate(&est);
li->QuadPart += est.QuadPart;
}
li->QuadPart /= SAMPLE_SIZE;
//
// At the moment Pentiums come in 60, 66, 75, 90, 100, 120 and 133 MHz
// clock speeds. So use the above estimation of the clock frequency
// to determine the real clock frequency.
//
// 59Mhz to 61Mhz assume its a 60 Mhz
if (li->QuadPart >= 59000000 && li->QuadPart < 61000000) {
li->QuadPart = 60000000;
}
// 65Mhz to 67Mhz assume its a 66 Mhz
else if (li->QuadPart >= 65000000 && li->QuadPart < 67000000) {
li->QuadPart = 66000000;
}
// 74Mhz to 76Mhz assume its a 75 Mhz
else if (li->QuadPart >= 74000000 && li->QuadPart < 76000000) {
li->QuadPart = 75000000;
}
// 89Mhz to 91Mhz assume its a 90 Mhz
else if (li->QuadPart >= 89000000 && li->QuadPart < 91000000) {
li->QuadPart = 90000000;
}
// 99Mhz to 101Mhz assume its a 100 Mhz
else if (li->QuadPart >= 99000000 && li->QuadPart < 101000000) {
li->QuadPart = 100000000;
}
// 119Mhz to 121Mhz assume its a 120 Mhz
else if (li->QuadPart >= 119000000 && li->QuadPart < 121000000) {
li->QuadPart = 120000000;
}
// 132Mhz to 134Mhz assume its a 133 Mhz
else if (li->QuadPart >= 132000000 && li->QuadPart < 134000000) {
li->QuadPart = 133000000;
}
// if use our estimate.
#else
li->QuadPart = -1;
#endif
}
/*****************************Private*Routine******************************\
* GetFrequencyEstimate
*
* Uses the system QueryPerformance counter to estimate the Pentium
* cpu clock * frequency
*
* History:
* 13-10-95 - StephenE - Created
*
\**************************************************************************/
void
GetFrequencyEstimate(
LARGE_INTEGER *li
)
{
LARGE_INTEGER liP1; // Pentium clk start
LARGE_INTEGER liP2; // Pentium clk end
LARGE_INTEGER liS1; // System clk end
LARGE_INTEGER liS2; // System clk end
LARGE_INTEGER liSf; // System clk frequency
QueryPerformanceFrequency(&liSf);
QueryPerformanceCounter(&liS1);
QueryPerfCounter(&liP1);
Sleep(2); // Sleep for approx 2 milli- seconds
QueryPerfCounter(&liP2);
QueryPerformanceCounter(&liS2);
//
// Determine the time recorded by both clocks.
//
liP2.QuadPart = liP2.QuadPart - liP1.QuadPart;
liS2.QuadPart = liS2.QuadPart - liS1.QuadPart;
li->QuadPart = (liP2.QuadPart * liSf.QuadPart) / liS2.QuadPart;
}
/******************************Public*Routine******************************\
* QueryPerfCounter
*
* Query the internal clock counter on the Pentium, uses the undocumented
* rdtsc instruction, which copies the current 64 bit clock count into
* edx:eax.
*
* History:
* 13-10-95 - StephenE - Created
*
\**************************************************************************/
void WINAPI
QueryPerfCounter(
LARGE_INTEGER *li
)
{
#ifdef _X86_
_asm mov ecx, dword ptr li // copy li pointer value to ecx
_asm _emit 0x0f // opcode 0x0F31 is rdtsc
_asm _emit 0x31
_asm mov dword ptr [ecx], eax // save result in li->LowPart
_asm mov dword ptr [ecx+4], edx // and li->HighPart
#else
;
#endif
}