Определение тактовой частоты процессора (на ядро, на процессор)
программы, такие как CPUz, очень хорошо дают подробную информацию о системе (скорость шины, тайминги памяти и т. д.)
однако есть ли программный способ вычисления частоты на ядро (и на процессор, в многопроцессорных системах с несколькими ядрами на процессор) без необходимости иметь дело с конкретной информацией о процессоре.
Я пытаюсь разработать анти-инструмент обмана (для использования с часами ограниченных контрольных соревнований), который сможет записывать часы CPU во время выполнения теста для всех активных ядер в системе (на всех процессорах.)
6 ответов
я расширю свои комментарии здесь. Это слишком большой и глубокий для меня, чтобы вписаться в комментарии.
то, что вы пытаетесь сделать, очень сложно-до такой степени непрактично по следующим причинам:
- нет портативного способа получить частоту процессора.
rdtsc
тут не всегда дайте правильную частоту из-за эффектов, таких как SpeedStep и Turbo Boost. - все известные методы измерения частота требует точного измерения времени. Тем не менее, решительный мошенник может вмешаться во все часы и таймеры в системе.
- точное считывание частоты процессора, а также времени в защищенном от взлома способе потребует доступа на уровне ядра. Это подразумевает подписание драйверов для Windows.
нет портативного способа получить частоту процессора:
"простой" способ получить частоту процессора - звоните rdtsc
дважды с фиксированной продолжительностью времени между ними. Тогда деление разницы даст вам частоту.
проблема в том, что rdtsc
не дает истинной частоты процессора. Потому что приложения реального времени, такие как игры, полагаются на него, rdtsc
должен быть последовательным через дросселирование процессора и Turbo Boost. Итак, как только ваша система загрузится,rdtsc
всегда будет работать с той же скоростью (если вы не начнете возиться со скоростью шины с SetFSB или что-то).
например, на моем Core i7 2600K,rdtsc
всегда будет показывать частоту в 3.4 GHz
. Но на самом деле, он бездельничает на 1.6 GHz
часов и до 4.6 GHz
под нагрузкой через разогнанный множитель Turbo Boost на 46x
.
но как только вы найдете способ измерить истинную частоту (или вы достаточно довольны rdtsc
), вы можете легко получить частоту каждого ядра используя нить-сродства.
получение истинной частоты:
чтобы получить истинную частоту процессора, вам нужно получить доступ либо к MSRs (регистрам конкретной модели), либо к счетчикам производительности оборудования.
это инструкции уровня ядра и поэтому требуют использования драйвера. Если вы пытаетесь сделать это в Windows с целью распространения, вам нужно будет пройти соответствующую подпись драйвера протокол. Кроме того, код будет отличаться по марке и модели процессора, поэтому вам понадобится другой код обнаружения для каждого поколения процессора.
как только вы доберетесь до этой стадии, есть множество способов прочитать частоту.
на процессорах Intel аппаратные счетчики позволяют подсчитывать необработанные циклы процессора. В сочетании с методом точного измерения реального времени (следующий раздел) вы можете вычислить истинную частоту. ОПС даст вам доступ к другой информации, такой как умножитель частоты процессора.
все известные методы измерения частоты требуют точного измерения времени:
это, пожалуй, самая большая проблема. Для измерения частоты нужен таймер. Способный хакер сможет подделать все часы, которые вы можете использовать в C / C++. Это включает в себя все следующий:
clock()
gettimeofday()
QueryPerformanceCounter()
- etc...
список продолжается и на. Другими словами, вы не можете доверять ни одному из таймеров, поскольку способный хакер сможет обмануть их всех. Например clock()
и gettimeofday()
можно обмануть, изменив системные часы непосредственно в ОС. Дурачить!--13--> сложнее.
получение истинного измерения Время:
все часы, перечисленные выше, уязвимы, потому что они часто выводятся из одних и тех же системных базовых часов тем или иным образом. И эти системные базовые часы часто привязаны к системным базовым часам, которые могут быть изменены после того, как система уже загрузилась с помощью утилит разгона.
таким образом, единственный способ получить надежное и надежное измерение времени-это читать внешние часы, такие как HPET или ACPI в. К сожалению, они также требуют доступа на уровне ядра.
Подведем Итоги:
создание любого вида тестового теста, защищенного от взлома, почти наверняка потребует написания драйвера в режиме ядра, который требует подписи сертификата для Windows. Это часто слишком большая нагрузка для случайных авторов-бенчмарков.
это привело к нехватке контрольных показателей, которые, вероятно, способствовали общий спад конкурентного сообщества разгона в последние годы.
один из самых простых способов сделать это с помощью RDTSC
, но, поскольку это для механизмов защиты от обмана, я бы поставил это как драйвер ядра или резидентный фрагмент кода hyper-visor.
вам, вероятно, также нужно будет свернуть свой собственный код синхронизации**, который снова можно сделать с RDTSC
(QPC, как используется в приведенном ниже примере, использует RDTSC
, и его на самом деле очень просто перепроектировать и использовать локальную копию, что означает, чтобы вмешаться в нее, вам нужно будет вмешаться в ваш водитель.)
void GetProcessorSpeed()
{
CPUInfo* pInfo = this;
LARGE_INTEGER qwWait, qwStart, qwCurrent;
QueryPerformanceCounter(&qwStart);
QueryPerformanceFrequency(&qwWait);
qwWait.QuadPart >>= 5;
unsigned __int64 Start = __rdtsc();
do
{
QueryPerformanceCounter(&qwCurrent);
}while(qwCurrent.QuadPart - qwStart.QuadPart < qwWait.QuadPart);
pInfo->dCPUSpeedMHz = ((__rdtsc() - Start) << 5) / 1000000.0;
}
* * * Я бы это для безопасности, как @ Mystical упоминалось, но, поскольку я никогда не чувствовал побуждения подрывать механизмы синхронизации системы низкого уровня, могло бы быть больше вовлечено, было бы неплохо, если бы Mystical мог что-то добавить на это :)
Я ранее опубликовал на эту тему (Вместе с основным алгоритмом):здесь. Насколько мне известно алгоритм (см. обсуждение) очень точный. Например, Windows 7 сообщает мои часы процессора как 2.00 GHz, CPU-Z как 1994-1996 МГц и мой алгоритм как 1995025-1995075 кГц.
алгоритм выполняет много циклов для этого, что приводит к увеличению частоты процессора до максимума (как и во время тестов), поэтому программное обеспечение для регулирования скорости не будет входить играть.
дополнительная информация здесь и здесь.
по вопросу о регулировании скорости я действительно не вижу в этом проблемы, если приложение не использует значения скорости для определения прошедших времен и что сами времена чрезвычайно важны. Например, если для разделения требуется X тактовых циклов, не имеет значения, работает ли процессор на частоте 3 ГГц или 300 МГц: ему все равно понадобится x тактовых циклов, и единственная разница в том, что он будет завершите разделение в десятой части времени на @ 3 GHz.
Я понимаю, что это уже ответили. Я также понимаю, что это в основном черное искусство, поэтому, пожалуйста, возьмите его или оставьте - или предложите обратную связь.
в стремлении найти тактовую частоту на дросселированных (благодаря microsft,hp и dell) хостах HyperV (ненадежный счетчик perf) и гостях HyperV (можно получить только запасную скорость процессора, а не текущую), мне удалось, через пробную ошибку и fluke, создать цикл, который петляет ровно один раз за сутки.
код следующим образом-C# 5.0, SharpDev, 32bit, Target 3.5, Optimize on (crucial), нет активного отладчика (crucial)
long frequency, start, stop;
double multiplier = 1000 * 1000 * 1000;//nano
if (Win32.QueryPerformanceFrequency(out frequency) == false)
throw new Win32Exception();
Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(1);
const int gigahertz= 1000*1000*1000;
const int known_instructions_per_loop = 1;
int iterations = int.MaxValue;
int g = 0;
Win32.QueryPerformanceCounter(out start);
for( i = 0; i < iterations; i++)
{
g++;
g++;
g++;
g++;
}
Win32.QueryPerformanceCounter(out stop);
//normal ticks differs from the WMI data, i.e 3125, when WMI 3201, and CPUZ 3199
var normal_ticks_per_second = frequency * 1000;
var ticks = (double)(stop - start);
var time = (ticks * multiplier) /frequency;
var loops_per_sec = iterations / (time/multiplier);
var instructions_per_loop = normal_ticks_per_second / loops_per_sec;
var ratio = (instructions_per_loop / known_instructions_per_loop);
var actual_freq = normal_ticks_per_second / ratio;
Console.WriteLine( String.Format("Perf counhter freq: {0:n}", normal_ticks_per_second));
Console.WriteLine( String.Format("Loops per sec: {0:n}", loops_per_sec));
Console.WriteLine( String.Format("Perf counter freq div loops per sec: {0:n}", instructions_per_loop));
Console.WriteLine( String.Format("Presumed freq: {0:n}", actual_freq));
Console.WriteLine( String.Format("ratio: {0:n}", ratio));
Примечания
- 25 инструкций на цикл, если отладчик активен
- подумайте о запуске цикла 2 или 3 секунд перед рукой, чтобы раскрутить процессор (или, по крайней мере, попытаться раскрутить, зная, как сильно серверы дросселируются в эти дни)
- протестировано на 64-битном Core2 и Haswell Pentium и сравнивается с CPU-Z
следует обратиться к этой Белой книге:технология Intel® Turbo Boost в процессорах на базе микроархитектуры Intel® Core™ (Nehalem). В принципе, произведите несколько считываний фиксированного счетчика производительности UCC в течение периода выборки T.
Relative.Freq = Delta(UCC) / T
Where:
Delta() = UCC @ period T
- UCC @ period T-1
начиная с архитектуры Nehalem, UCC увеличивает и уменьшает количество тиков щелчка относительно несоленого состояния ядра.
когда SpeedStep или Turbo Boost активированы, расчетная частота использование UCC будет измеряться соответственно; в то время как TSC остается постоянным. Например, Turbo Boost в действии показывает, что Delta(UCC) больше или равна Delta (TSC)
пример функции Core_Cycle
функция at Cyring / CoreFreq GitHub.