[WinAPI] Cum aflu frecventa procesorului?

Folosire Windows API in programe C/C++ (forum moderat)
Post Reply
User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3776
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi

[WinAPI] Cum aflu frecventa procesorului?

Post by Ovidiu Cucu » 02 Jan 2012, 15:45

Intrebare
Cum aflu frecventa curenta a microprocesorului?

Raspuns
Se pot folosi functiile API QueryPerformanceCounter si QueryPerformanceFrequency in combinatie cu instructiune procesor RDTSC (Read Time-Stamp Counter).

Exemplu

Code: Select all

ULONG GetCPUFrequency()
{
   LARGE_INTEGER nCntFrequency;
   if(!::QueryPerformanceFrequency(&nCntFrequency))
      return 0; // high-resolution performance counter not supported
   
   LARGE_INTEGER nCnt0, nCnt1;
   ULONG  nTs0, nTs1;
   
   HANDLE hThread = ::GetCurrentThread();
   int nPriority  = ::GetThreadPriority(hThread);
   ::SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL);

   ::QueryPerformanceCounter(&nCnt1);
   __asm
   {
      _emit 0x0f _asm _emit 0x31 // RDTSC
      MOV nTs0, EAX
   }
   nCnt0.LowPart  = nCnt1.LowPart;		
 
   while(((ULONG)nCnt1.LowPart - (ULONG)nCnt0.LowPart) < 300000)
   {
      ::QueryPerformanceCounter(&nCnt1);
      __asm
      {
         _emit 0x0f _asm _emit 0x31 // RDTSC
         MOV nTs1, EAX
      }
   }
   ::SetThreadPriority(hThread, nPriority);

   ULONG nCycles = nTs1 - nTs0;
   ULONG nTicks  = (ULONG)(nCnt1.LowPart - nCnt0.LowPart);
   nTicks *= 10000;
   nTicks /= (nCntFrequency.LowPart / 100);

   return nCycles / nTicks; // MHz
}

Resurse Vezi si
<< Back to Windows API Index



User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3776
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi

[WinAPI] Cum aflu frecventa procesorului? (2)

Post by Ovidiu Cucu » 02 Jan 2012, 16:04

Raspuns
O metoda simpla este utilizand functia CallNtPowerInformation.

Exemplu

Code: Select all

#include <windows.h>
#include <Powrprof.h>
#include <iostream>

typedef struct _PROCESSOR_POWER_INFORMATION {
  ULONG  Number;
  ULONG  MaxMhz;
  ULONG  CurrentMhz;
  ULONG  MhzLimit;
  ULONG  MaxIdleState;
  ULONG  CurrentIdleState;
} PROCESSOR_POWER_INFORMATION;

#pragma comment(lib, "Powrprof.lib")

int main()
{
   PROCESSOR_POWER_INFORMATION ppi = {0};
   ::CallNtPowerInformation(ProcessorInformation, NULL, 0, &ppi, sizeof(PROCESSOR_POWER_INFORMATION));

   std::cout << "Current processor frequency: " 
      << ppi.CurrentMhz << " MHz" << std::endl;

   system("pause");
   return 0;
}
Note
  1. Exemplul de mai sus functioneaza pe Windows XP. Totusi, un vechi amic a sesizat faptul ca pe versiuni mai noi de Windows, in cazul cand exista mai multe procesoare, functia CallNtPowerInformation da kix cu eroarea STATUS_BUFFER_TOO_SMALL.
    Exemplul urmator corecteaza aceasta greseala:

    Code: Select all

    #include <NTstatus.h>
    #define WIN32_NO_STATUS
    #include <windows.h>
    #include <Powrprof.h>
    #include <iostream>
    
    typedef struct _PROCESSOR_POWER_INFORMATION {
       ULONG  Number;
       ULONG  MaxMhz;
       ULONG  CurrentMhz;
       ULONG  MhzLimit;
       ULONG  MaxIdleState;
       ULONG  CurrentIdleState;
    } PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION;
    
    #pragma comment(lib, "Powrprof.lib")
    
    int main()
    {
       SYSTEM_INFO si = {0};
       ::GetSystemInfo(&si);
       const int size = si.dwNumberOfProcessors * sizeof(PROCESSOR_POWER_INFORMATION);
    
       LPBYTE pBuffer = new BYTE[size]; 
       NTSTATUS status = ::CallNtPowerInformation(ProcessorInformation, NULL, 0, pBuffer, size);
       if(STATUS_SUCCESS == status)
       {
          PPROCESSOR_POWER_INFORMATION ppi = (PPROCESSOR_POWER_INFORMATION)pBuffer;
          for(DWORD nIndex = 0; nIndex < si.dwNumberOfProcessors; nIndex++)
          {
             std::cout << "Processor #" << ppi->Number << " frequency: " 
                << ppi->CurrentMhz << " MHz" << std::endl;
             ppi++;
          }
       }
       else
       {
          std::cout << "CallNtPowerInformation failed. Status: " << status << std::endl;
       }
       delete []pBuffer;
       system("pause");
       return status;
    }
  2. In general ma stradui sa testez exemplele inainte de a le posta. Totusi, ca peste tot, nu este exclus sa scape erori/omisiuni/greseli. Cand apar, va rog sa le sesizati in forum.
    Thank you!
Resurse
<< Back to Windows API Index

Post Reply