Averiguar la frecuencia de reloj de la CPU (por núcleo, por procesador)


Los programas como CPUz son muy buenos para dar información en profundidad sobre el sistema (velocidad de bus, tiempos de memoria, etc.)

Sin embargo, existe una forma programática de calcular la frecuencia por núcleo (y por procesador, en sistemas multi procesador con múltiples núcleos por CPU) sin tener que lidiar con información específica de la CPU.

Estoy tratando de desarrollar una herramienta anti engaño (para su uso con las competiciones de referencia limitada reloj) que será capaz de grabar el reloj de la CPU durante el ejecución de benchmark para todos los núcleos activos del sistema (en todos los procesadores.)

Author: kidoman, 2011-12-02

6 answers

Voy a ampliar mis comentarios aquí. Esto es demasiado grande y profundo para que pueda encajar en los comentarios.

Lo que estás tratando de hacer es muy difícil - hasta el punto de ser poco práctico por las siguientes razones:{[18]]}

  • No hay una forma portátil de obtener la frecuencia del procesador. rdtsc hace NO siempre da la frecuencia correcta debido a efectos como SpeedStep y Turbo Boost.
  • Todos los métodos conocidos para medir la frecuencia requieren una precisión medición del tiempo. Sin embargo, un tramposo determinado puede manipular todos los relojes y temporizadores en el sistema.
  • Leer con precisión tanto la frecuencia del procesador como el tiempo de una manera a prueba de manipulaciones requerirá acceso a nivel del núcleo. Esto implica la firma de controladores para Windows.

No hay forma portátil de obtener la frecuencia del procesador:

La forma "fácil" de obtener la frecuencia de la CPU es llamar rdtsc dos veces con un tiempo fijo-duración en entre. Entonces dividiendo la diferencia le dará la frecuencia.

El problema es que rdtsc no da la verdadera frecuencia del procesador. Debido a que las aplicaciones en tiempo real, como los juegos, dependen de él, rdtsc debe ser consistente a través de la limitación de la CPU y el Turbo Boost. Así que una vez que su sistema arranca, rdtsc siempre se ejecutará a la misma velocidad (a menos que comience a jugar con las velocidades de bus con SetFSB o algo así).

Por ejemplo, en mi Core i7 2600K, {[0] } mostrar siempre la frecuencia en 3.4 GHz. Pero en realidad, está inactivo en 1.6 GHz y relojes hasta 4.6 GHz bajo carga a través del multiplicador Turbo Boost overclockeado en 46x.

Pero una vez que encuentras una manera de medir la frecuencia verdadera, (o estás lo suficientemente feliz con rdtsc), puedes obtener fácilmente la frecuencia de cada núcleo usando afinidades de hilo.

Obtener la Verdadera Frecuencia:

Para obtener la verdadera frecuencia del procesador, debe acceder a los MSR (registros específicos del modelo) o los contadores de rendimiento del hardware.

Estas son instrucciones a nivel del núcleo y por lo tanto requieren el uso de un controlador. Si está intentando esto en Windows con el propósito de distribución, por lo tanto, deberá pasar por el protocolo de firma de controladores adecuado. Además, el código diferirá según la marca y el modelo del procesador, por lo que necesitará un código de detección diferente para cada generación del procesador.

Una vez que llegas a esta etapa, hay una variedad de formas de leer la frecuencia.

En los procesadores Intel, los contadores de hardware le permiten contar los ciclos de CPU sin procesar. Combinado con un método de medición precisa en tiempo real (sección siguiente), puede calcular la frecuencia verdadera. Los MSR le dan acceso a otra información, como el multiplicador de frecuencia de la CPU.


Todos los métodos conocidos para medir la frecuencia requieren una medición precisa del tiempo:

Este es quizás el mayor problema. Necesitas un temporizador para poder para medir la frecuencia. Un hacker capaz será capaz de manipular todos los relojes que se pueden utilizar en C/C++. Esto incluye todo lo siguiente:

  • clock()
  • gettimeofday()
  • QueryPerformanceCounter()
  • etc...

La lista sigue y sigue. En otras palabras, no puedes confiar en ninguno de los temporizadores, ya que un hacker capaz podrá falsificarlos a todos. Por ejemplo, clock() y gettimeofday() se pueden engañar cambiando el reloj del sistema directamente dentro del sistema operativo. Engañar QueryPerformanceCounter() es duro.

Obtener una Verdadera Medición del Tiempo:

Todos los relojes enumerados anteriormente son vulnerables porque a menudo se derivan del mismo reloj base del sistema de una manera u otra. Y ese reloj base del sistema a menudo está vinculado al reloj base del sistema, que se puede cambiar después de que el sistema ya se haya iniciado mediante utilidades de overclocking.

Así que la única manera de obtener una medición de tiempo confiable y a prueba de manipulaciones es leer relojes externos como el HPETo el ACPI. Desafortunadamente, estos también parecen requerir acceso a nivel del núcleo.


Para Resumir:

La construcción de cualquier tipo de prueba de referencia a prueba de manipulaciones casi seguramente requerirá escribir un controlador de modo kernel que requiere la firma de certificados para Windows. Esto es a menudo demasiado de una carga para los escritores de benchmark casuales.

Esto ha dado lugar a una escasez de puntos de referencia a prueba de manipulaciones que probablemente ha contribuido a la disminución general de la comunidad competitiva de overclocking en los últimos años.

 31
Author: Mysticial,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-03 22:35:33

Una de las formas más simples de hacerlo es usando RDTSC, pero viendo que esto es para mecanismos anti-trampas, lo pondría como un controlador del núcleo o una pieza de código residente de hyper-visor.

Es probable que también tenga que rodar su propio código de tiempo**, que de nuevo se puede hacer con RDTSC (QPC como se utiliza en el ejemplo a continuación utiliza RDTSC, y es de hecho muy simple de ingeniería inversa y utilizar una copia local de, lo que significa que para manipular con él, controlador).

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;
}

** Yo esto sería por seguridad como @Mystical mencionó, pero como nunca he sentido la necesidad de subvertir los mecanismos de sincronización del sistema de bajo nivel, podría haber más involucrados, sería bueno si Mystical pudiera agregar algo sobre eso:)

 1
Author: Necrolis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-02 07:32:09

He publicado anteriormente sobre este tema (junto con un algoritmo básico): aquí. Que yo sepa, el algoritmo (ver la discusión) es muy preciso. Por ejemplo, Windows 7 reporta mi reloj de CPU como 2.00 GHz, CPU-Z como 1994-1996 MHz y mi algoritmo como 1995025-1995075 kHz.

El algoritmo realiza muchos bucles para hacer esto, lo que hace que la frecuencia de la CPU aumente al máximo (como también lo hará durante los puntos de referencia), por lo que el software de aceleración de velocidad no entrará en jugar.

Información Adicional aquí y aquí.

Sobre la cuestión de la aceleración de la velocidad realmente no lo veo como un problema a menos que una aplicación utilice los valores de velocidad para determinar los tiempos transcurridos y que los tiempos en sí son extremadamente importantes. Por ejemplo, si una división requiere x ciclos de reloj para completar, no importa si la CPU se ejecuta a 3 GHz o 300 MHz: todavía necesitará x ciclos de reloj y la única diferencia es que completará la división en una décima parte del tiempo a @ 3 GHz.

 1
Author: Olof Forshell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:45:48

Me doy cuenta de que esto ya ha sido contestado. También me doy cuenta de que esto es básicamente un arte negro, así que por favor tómelo o déjelo, u ofrezca comentarios.

En una búsqueda para encontrar la velocidad de reloj en hosts HyperV (gracias microsft,hp y dell) (contador de perf no confiable) e invitados HyperV (solo pueden obtener velocidad de CPU de stock, no actual), he logrado, a través de error de prueba y fluke, crear un bucle que se repite exactamente una vez por reloj.

Code as follows-C # 5.0, SharpDev, 32bit, Target 3.5, Optimizar en (crucial), no debuger activo (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));

Notas

  • 25 instrucciones por bucle si el depurador está activo
  • Considere ejecutar un bucle de 2 o 3 segundos antes de la mano para activar el procesador (o al menos intentar activar, sabiendo cuán fuertemente los servidores están limitados en estos días)
  • Probado en un Core2 de 64 bits y Haswell Pentium y comparado con CPU-Z
 1
Author: Patrick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-08 10:41:53

Uno debe consultar este documento técnico: Tecnología Intel® Turbo Boost en Procesadores basados en Microarquitectura Intel® Coretm (Nehalem) . Básicamente, producir varias lecturas del contador de rendimiento fijo UCC durante un período de muestra T.

Relative.Freq = Delta(UCC)  / T

Where:
   Delta() = UCC @ period T
                 - UCC @ period T-1

A partir de la arquitectura Nehalem, UCC aumenta y disminuye el número de clics relativamente al estado sin interrupción del núcleo.

Cuando se activan SpeedStep o Turbo Boost, la frecuencia estimada usando UCC será medido en consecuencia; mientras que TSC permanece constante. Por ejemplo, Turbo Boost en acción revela que Delta(UCC) es mayor o igual a Delta (TSC)

Ejemplo en function Core_Cyclefunction at Cyring | CoreFreq GitHub.

 1
Author: CyrIng,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-25 20:27:34

Necesita usar CallNtPowerInformation. Aquí hay un ejemplo de código del proyecto putil. Con esto puede obtener la frecuencia de CPU actual y máxima. Por lo que sé no es posible obtener la frecuencia por CPU.

 -1
Author: Giampaolo Rodolà,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-20 17:39:36