Подсчет скорости процессоров в многоядерной системе
Автор: 0r@ngE
Вероятно, многие из вас при инициализации движка проводят тестирование системы. Рассмотрим один из моментов такого тестирования — нахождение скорости отдельных процессоров/(ядер) в многопроцессорной/(многоядерной) системе.
Для начала нам нужна функция точного замера тактов процессора. Для этих целей во всех современных процессорах есть инструкция 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