Подтвердить что ты не робот

Определение частоты процессора (на ядро, на процессор)

Такие программы, как CPUz, очень хорошо дают подробную информацию о системе (скорость шины, тайминги памяти и т.д.).

Однако существует ли программный способ вычисления каждого ядра (и для каждого процессора в многопроцессорных системах с несколькими ядрами на процессор), без необходимости иметь дело с информацией о ЦП.

Я пытаюсь разработать анти-чит-инструмент (для использования с часами с ограниченным тестированием), которые смогут записывать часы процессора во время эталонного прогона для всех активных ядер в системе (для всех процессоров).

4b9b3361

Ответ 1

Я расскажу о своих комментариях здесь. Это слишком большое и подробное для меня, чтобы вписаться в комментарии.

То, что вы пытаетесь сделать, очень сложно - с точки зрения непрактичности по следующим причинам:

  • Нет никакого портативного способа получить частоту процессора. 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), вы можете легко получить частоту каждого ядра с помощью нити-аффинности.

Получение истинной частоты:

Чтобы получить истинную частоту процессора, вам необходимо получить доступ к MSR (регистрам, специфичным для модели) или счетчикам производительности оборудования.

Это инструкции на уровне ядра и поэтому требуют использования драйвера. Если вы пытаетесь это сделать в Windows для распространения, вам необходимо будет пройти соответствующий протокол подписания драйверов. Кроме того, код будет отличаться процессором и моделью, поэтому вам понадобится другой код обнаружения для каждого поколения процессоров.

Как только вы дойдете до этой стадии, существует множество способов прочитать частоту.

В процессорах Intel аппаратные счетчики позволяют подсчитывать необработанные циклы процессора. В сочетании с методом точного измерения реального времени (следующий раздел) вы можете вычислить истинную частоту. MSR предоставляют вам доступ к другой информации, такой как множитель частоты процессора.


Все известные методы измерения частоты требуют точного измерения времени:

Это, пожалуй, большая проблема. Для измерения частоты вам нужен таймер. Способный хакер сможет изменять все часы, которые вы можете использовать в C/С++. Это включает в себя все следующее:

  • clock()
  • gettimeofday()
  • QueryPerformanceCounter()
  • и т.д...

Список можно продолжать и продолжать. Другими словами, вы не можете доверять ни одному из таймеров, поскольку способный хакер сможет обмануть всех из них. Например, clock() и gettimeofday() можно обмануть, изменив системные часы непосредственно в ОС. Обмануть QueryPerformanceCounter() сложнее.

Получение истинного измерения времени:

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

Таким образом, единственный способ получить надежное и безошибочное измерение времени - прочитать внешние часы, такие как HPET или ACPI. К сожалению, для них также требуется доступ на уровне ядра.


Подводя итог:

Построение любого типа тестов, защищенных от несанкционированного доступа, почти наверняка потребует написания драйвера режима ядра, который требует подписания сертификата для Windows. Это часто является слишком большим бременем для случайных сценаристов.

Это привело к нехватке доказательств, подтверждающих несанкционированность, что, вероятно, способствовало общему снижению конкурентного сообщества разгона в последние годы.

Ответ 2

Один из самых простых способов сделать это - использовать RDTSC, но, видя, что это касается механизмов анти-обмана, я бы поставил это как драйвер ядра или кусок кода с гипер-козырьком.

Вероятно, вам также понадобится свернуть собственный временной код **, что также можно сделать с помощью 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 мог что-то добавить: )

Ответ 3

Я уже писал на эту тему (наряду с основным алгоритмом): здесь. Насколько мне известно, алгоритм (см. Обсуждение) очень точен. Например, Windows 7 сообщает о тактах процессора как 2,00 ГГц, CPU-Z как 1994-1996 МГц и мой алгоритм 1995025-1995075 кГц.

Алгоритм выполняет много циклов, чтобы сделать так, чтобы частота процессора увеличивалась до максимальной (как и во время тестов), поэтому программное обеспечение для регулирования скорости не вступит в игру.

Дополнительная информация здесь и здесь.

В вопросе о быстром дросселировании я действительно не рассматриваю его как проблему, если приложение не использует значения скорости для определения прошедших времен и что сами времена чрезвычайно важны. Например, если для разделения требуется x тактовых циклов для завершения, не имеет значения, работает ли процессор на частоте 3 ГГц или 300 МГц: ему все еще понадобятся тактовые циклы x, и единственная разница в том, что он завершит деление на десятую времени при @3 ГГц.

Ответ 4

Я понимаю, что это уже ответили. Я также понимаю, что это в основном черное искусство, поэтому, пожалуйста, возьмите его или оставьте - или предложите обратную связь.

В стремлении найти тактовую частоту на дросселированных (спасибо microsft, hp и dell) хосты HyperV (ненадежный счетчик перфораторов) и гости HyperV (могут получить только скорость центрального процессора, а не текущую), мне удалось пробную ошибку и случайность, чтобы создать цикл, который петли ровно один раз за такт.

Код следующим образом: С# 5.0, SharpDev, 32bit, Target 3.5, Оптимизация (критическая), отсутствие активного отладчика (критическое)

        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

Ответ 5

Следует отметить этот технический документ: Технология 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 в Cyring | CoreFreq GitHub.

Ответ 6

Вам нужно использовать CallNtPowerInformation. Здесь пример кода из putil. При этом вы можете получить текущую и максимальную частоту процессора. Насколько я знаю, невозможно получить частоту процессора.