Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Подсказки / Подсчет скорости процессоров в многоядерной системе

Подсчет скорости процессоров в многоядерной системе

Автор:

Вероятно, многие из вас при инициализации движка проводят тестирование системы. Рассмотрим один из моментов такого тестирования — нахождение скорости отдельных процессоров/(ядер) в многопроцессорной/(многоядерной) системе.

Для начала нам нужна функция точного замера тактов процессора. Для этих целей во всех современных процессорах есть инструкция RDTSC (Read Time Stamp Counter) записывающая в EAX:EDX 64-bit текущее значение счетчика тактов. Однако проблема состоит в том, что на многоядерных системах эта инструкция может выдавать некорректные результаты в связи с ее асинхронной работой (такое было замечено мной пока только на процессорах от AMD). То есть для получения корректного результата нам нужен синхронизатор, коим может выступить, к примеру, CPUID с EAX=0 (совет от Intel'а).

Функция, возвращающая текущее количество тактов:

typedef unsigned __int64  qword;

#if _MSC_VER >= 1400
  #include <intrin.h>
  #pragma intrinsic(__rdtsc)
  #define GetCycleNumber  __rdtsc
#else
  inline qword GetCycleNumber( void )
  {
    //  =[ 0r@ngE ]= - in multi-core systems
    //  RDTSC can give us incorrect results,
    //  because work of this instruction is asyncronous,
    //  that's why I need this slow-and-heavy cpuid instruction,
    //  which works as sync'er =)
    qword count = 0;
    __asm
    {
      xor    eax, eax
      xor    ebx, ebx
      xor    ecx, ecx
      xor    edx, edx
      cpuid
      rdtsc
      lea    edi, [count]
      mov    dword ptr[edi + 0], eax
      mov    dword ptr[edi + 4], edx
      xor    eax, eax
    }
    return count;
  }
#endif

Следующая функция замеряет скорость конкретного процессора (cpu = 0,1,2,3,.....)

Замер скорости проходит 5 раз, для того, чтобы вывести процессор из возможного состояния эргономики.
Возращаемое значение = наибольший результат пяти замеров.

qword CalculateClockSpeed( ulong cpu )
{
  HANDLE curThread = GetCurrentThread();
  ulong saveMask = SetThreadAffinityMask( curThread, 1 << cpu );
  Sleep( 0 );  // Ensure system to switch to the right CPU

  const int numResults = 5;
  qword results[numResults] = {0};
  qword ret = 0;

  int i;
  for ( i = 0; i < numResults; i++ )
  {
    LARGE_INTEGER waitTime, startCount, curCount;
    QueryPerformanceCounter( &startCount );
    QueryPerformanceFrequency( &waitTime );
    int scale = 5;    // Take 1/32 of a second for the measurement.
    waitTime.QuadPart >>= scale;

    qword start = GetCycleNumber();
    do
    {
      QueryPerformanceCounter( &curCount );
    } while ( curCount.QuadPart - startCount.QuadPart < waitTime.QuadPart );
    qword end = GetCycleNumber();

    results[i] = ( ( end - start ) << scale );
  }

  SetThreadAffinityMask( curThread, saveMask );

  ret = results[0];
  for ( i = 1; i < numResults; i++ )
    if ( results[i] > ret )
      ret = results[i];

  return ret;
}

P.S.: Узнать количество процессоров в системе можно функцией GetSystemInfo():

  SYSTEM_INFO sysInfo;
  GetSystemInfo( &sysInfo );
  numCpus = sysInfo.dwNumberOfProcessors;

6 ноября 2009

#ASM, #CPU

2001—2017 © GameDev.ru — Разработка игр