Come ottengo il conteggio del ciclo della CPU in Win32?
-
02-07-2019 - |
Domanda
In Win32, c'è un modo per ottenere un conteggio unico del ciclo della CPU o qualcosa di simile che sarebbe uniforme per più processi / lingue / sistemi / ecc.
Sto creando alcuni file di registro, ma devo produrre più file di registro perché stiamo ospitando il runtime .NET e vorrei evitare di chiamare dall'uno all'altro per accedere. In quanto tale, stavo pensando di produrre solo due file, combinarli e quindi ordinarli, per ottenere una sequenza temporale coerente che includesse chiamate tra paesi.
Tuttavia, GetTickCount non aumenta per ogni chiamata, quindi non è affidabile. C'è un numero migliore, in modo che le chiamate siano nell'ordine giusto durante l'ordinamento?
Modifica : grazie a @Greg che mi hanno messo sulla buona strada per QueryPerformanceCounter , che ha fatto il trucco.
Soluzione
Puoi utilizzare le RDTSC istruzione CPU (presupponendo x86). Questa istruzione fornisce il contatore del ciclo della CPU, ma tieni presente che aumenterà molto rapidamente al suo valore massimo, quindi reimposta su 0. Come menzionato nell'articolo di Wikipedia, potresti essere meglio usando funzione QueryPerformanceCounter .
Altri suggerimenti
Ecco un articolo interessante! dice di non usare RDTSC, ma di usa invece QueryPerformanceCounter .
Conclusione:
Usare il vecchio
timeGetTime()
normale per fare il tempismo non è affidabile su molti Sistemi operativi basati su Windows perché la granularità del sistema il timer può arrivare fino a 10-15 millisecondi, nel senso chetimeBeginPeriod(1)
è solo preciso 10-15 millisecondi. [Si noti che il granularità elevate si verificano su base NT sistemi operativi come Windows NT, 2000 e XP. Windows 95 e 98 tendono avere una granularità molto migliore, circa 1-5 ms.]Tuttavia, se chiami
timeEndPeriod(1)
all'inizio di il tuo programma (eSleep()
a alla fine),Sleep(1)
di solito diventare accurato di 1-2 millisecondi, e ti fornirà estremamente informazioni precise sui tempi.
Sleep(2)
si comporta in modo simile; la lunghezza di tempo cheQueryPerformanceFrequency
dorme effettivamente perché va di pari passo con il granularità diQueryPerformanceCounter
, quindi dopo chiamando <=> una volta, <=> dormirà effettivamente per 1-2 millisecondi, <=> per 2-3 e così via acceso (invece di dormire con incrementi fino a 10-15 ms).Per tempi più precisi (precisione inferiore al millisecondo), lo farai probabilmente voglio evitare di usare il assemblaggio RDTSC mnemonico perché lo è difficile da calibrare ; invece, usa <=> e <=>, che sono preciso a meno di 10 microsecondi (0,00001 secondi).
Per un tempismo semplice, entrambi timeGetTime e QueryPerformanceCounter funzionano bene, e QueryPerformanceCounter è ovviamente più preciso. Tuttavia, se devi fare qualsiasi tipo di " cronometrato pause quot &; (come quelli necessari per framerate limiting), devi esserlo attento a stare seduto in un loop chiamando QueryPerformanceCounter, in attesa di per raggiungere un certo valore; questo sarà consumare il 100% del tuo processore. Invece, considera uno schema ibrido, dove chiami Sleep (1) (non dimenticare timeBeginPeriod (1) prima!) ogni volta devi superare più di 1 ms di ora, quindi immettere solo il QueryPerformanceCounter loop 100% occupato per finire l'ultimo < 1/1000 di a secondo del ritardo necessario. Questo ti darà ritardi estremamente precisi (preciso a 10 microsecondi), con utilizzo della CPU molto minimo. Vedi il codice sopra.
System.Diagnostics.Stopwatch.GetTimestamp () restituisce il numero di cicli della CPU da un'origine temporale (forse all'avvio del computer, ma non sono sicuro) e non l'ho mai visto aumentare tra 2 chiamate.
I cicli della CPU saranno specifici per ciascun computer, quindi non è possibile utilizzarlo per unire il file di registro tra 2 computer.
L'uscita RDTSC può dipendere dalla frequenza di clock del core corrente, che per le CPU moderne non è né costante né, in una macchina multicore, coerente.
Utilizza l'ora di sistema e, se hai a che fare con feed di più sistemi, usa un'origine temporale NTP. In questo modo è possibile ottenere letture del tempo affidabili e coerenti; se il sovraccarico è eccessivo per i tuoi scopi, utilizzando HPET per calcolare il tempo trascorso dal l'ultima lettura affidabile dell'ora nota è migliore dell'uso dell'HPET da solo.
Utilizzare GetTickCount e aggiungere un altro contatore quando si uniscono i file di registro. Non ti darà una sequenza perfetta tra i diversi file di registro, ma almeno manterrà tutti i registri di ciascun file nell'ordine corretto.