web-dev-qa-db-fra.com

Connaître la fréquence d'horloge du processeur (par cœur, par processeur)

Des programmes tels que CPUz sont très efficaces pour donner des informations détaillées sur le système (vitesse du bus, minutage de la mémoire, etc.)

Cependant, existe-t-il une méthode de calcul permettant de calculer la fréquence par cœur (et par processeur, dans les systèmes à plusieurs processeurs avec plusieurs cœurs par processeur) sans avoir à traiter les informations spécifiques au processeur.

J'essaie de développer un outil anti-triche (pour une utilisation avec des compétitions à horloge limitée) qui sera capable d'enregistrer l'horloge du processeur lors de l'exécution de l'analyse pour tous les cœurs actifs du système (sur tous les processeurs).

34
kidoman

Je me rends compte que cela a déjà été répondu. Je me rends également compte qu’il s’agit essentiellement d’un art noir, alors prenez-le ou laissez-le - ou offrez vos commentaires.

Dans une quête pour trouver la fréquence d'horloge sur les hôtes limités (merci microsft, hp et Dell), les hôtes HyperV (compteurs de performances non fiables) et les invités HyperV (le processeur ne peut obtenir que la vitesse du processeur d'origine, pas actuelle), fluke, pour créer une boucle qui boucle exactement une fois par horloge. 

Code comme suit: C # 5.0, SharpDev, 32 bits, cible 3.5, optimisé le (crucial), aucun débogueur actif (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));

Remarques

  • 25 instructions par boucle si le débogueur est actif
  • Pensez à exécuter une boucle de 2 ou 3 secondes avant de démarrer le processeur (ou au moins essayez de le faire, sachant à quel point les serveurs sont étranglés ces jours-ci).
  • Testé sur un Pentium 64 bits Core2 et Haswell et comparé à CPU-Z
3
Patrick

J'ai déjà posté sur ce sujet (avec un algorithme de base): ici . À ma connaissance, l'algorithme (voir la discussion) est très précis. Par exemple, Windows 7 signale l’horloge de mon processeur à 2,00 GHz, celle de CPU-Z à 1994-1996 MHz et mon algorithme à 1995025-1995075 kHz.

Pour ce faire, l'algorithme effectue de nombreuses boucles, ce qui entraîne une augmentation maximale de la fréquence de l'UC (comme ce sera également le cas lors des tests), de sorte qu'un logiciel de contrôle de la vitesse ne sera pas utilisé.

Informations supplémentaires ici et ici .

En ce qui concerne la limitation de la vitesse, je ne vois vraiment pas cela comme un problème, sauf si une application utilise les valeurs de vitesse pour déterminer les temps écoulés et que les temps eux-mêmes sont extrêmement importants. Par exemple, si une division nécessite x cycles d’horloge, le processeur fonctionne à 3 GHz ou à 300 MHz: il aura toujours besoin de x cycles d’horloge et la seule différence est que la division sera achevée dans un dixième. du temps à @ 3 GHz.

2
Olof Forshell

Il convient de se reporter à ce livre blanc: Technologie Intel® Turbo Boost dans les processeurs à processeur Intel® Core ™ Microarchitecture (Nehalem) . Fondamentalement, produire plusieurs lectures du compteur de performance fixe UCC sur une période d'échantillonnage T.

Relative.Freq = Delta(UCC)  / T

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

À partir de l'architecture Nehalem, UCC augmente et diminue le nombre de ticks par rapport à l'état non compressé du noyau.

Lorsque SpeedStep ou Turbo Boost sont activés, la fréquence estimée en utilisant UCC sera mesurée en conséquence; tandis que TSC reste constant. Par exemple, Turbo Boost en action révèle que Delta (UCC) est supérieur ou égal à Delta (TSC).

Exemple dans la fonction Core_Cycle fonction dans Cyring | CoreFreq GitHub.

1
CyrIng

L'un des moyens les plus simples de le faire consiste à utiliser RDTSC, mais comme il s'agit d'un mécanisme anti-triche, je l'insérerais comme pilote du noyau ou élément de code résidant dans l'hyperverseur.

Vous auriez probablement aussi besoin de lancer votre propre code temporel **, ce qui peut encore être fait avec RDTSC (QPC, comme dans l'exemple ci-dessous, utilise RDTSC, et il est en fait très simple de procéder à une ingénierie inverse et à une copie locale, qui moyen de le modifier, vous devez modifier votre pilote).

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

** Ce serait pour la sécurité comme l'a mentionné @Mystical, mais comme je n'ai jamais ressenti l'envie de subvertir les mécanismes de synchronisation du système de bas niveau, il pourrait être plus compliqué. Ce serait bien si Mystical pouvait ajouter quelque chose à ce sujet :)

1
Necrolis

Vous devez utiliser CallNtPowerInformation . Voici un exemple de code extrait de putil projet . Vous pouvez ainsi obtenir la fréquence actuelle et maximale du processeur. Autant que je sache, il n'est pas possible d'obtenir une fréquence par processeur.

0
Giampaolo Rodolà