Vă mulțumim pentru susținere

Este garantat că timpul de întâlnire () este de rezoluție microsecundă?

Deci, mă găsesc portând un joc, care a fost inițial scris pentru API-ul Win32, la Linux (bine, portând portul OS X al portului Win32 către Linux). Am implementat QueryPerformanceCounter dând uSeconds de la pornirea procesului:

BOOL QueryPerformanceCounter(LARGE_INTEGER* performanceCount)
{
    gettimeofday(&currentTimeVal, NULL);
    performanceCount->QuadPart = (currentTimeVal.tv_sec - startTimeVal.tv_sec);
    performanceCount->QuadPart *= (1000 * 1000);
    performanceCount->QuadPart += (currentTimeVal.tv_usec - startTimeVal.tv_usec);

    return true;
}

Acest lucru, împreună cu QueryPerformanceFrequency () dând o constantă 1,000,000 ca frecvență, funcționează bine pe mașina mea , oferindu-mi o variabilă pe 64 de biți, care conține uSeconds de la lansarea programului. Deci, este acest portabil? Nu doresc să descopere că funcționează în mod diferit în cazul în care kernel-ul a fost compilat într-un anumit fel sau ceva de genul asta. Sunt bine cu ea fiind non-portabil la altceva decât Linux, cu toate acestea.

0
adăugat editat

10 răspunsuri

Din experiența mea și din ceea ce am citit pe internet, răspunsul este "Nu", nu este garantat. Depinde de viteza procesorului, sistemul de operare, aroma de Linux etc.

0
adăugat

Rezoluția reală a gettimeofday () depinde de arhitectura hardware. Procesoarele Intel precum și mașinile SPARC oferă cronometre de înaltă rezoluție care măsoară microsecunde. Alte arhitecturi hardware revin temporizatorului sistemului, care este de obicei setat la 100 Hz. În astfel de cazuri, rezoluția de timp va fi mai puțin exactă.

I obtained this answer from High Resolution Time Measurement and Timers, Part I

0
adăugat

Poate. Dar aveți probleme mai mari. gettimeofday () poate duce la incorecte temporizări dacă există procese pe sistemul dvs. care schimbă cronometrul (adică ntpd). Pe un linux "normal", însă, cred că rezoluția gettimeofday () este 10us. Poate să sară înainte și înapoi și în timp, în consecință, pe baza proceselor care rulează pe sistemul dvs. Acest lucru face ca răspunsul la întrebarea dvs. să nu.

Ar trebui să căutați clock_gettime (CLOCK_MONOTONIC) pentru intervalele de timp. Acesta suferă de mai puține probleme cauzate de lucruri precum sistemele multi-core și setările ceasului extern.

De asemenea, căutați funcția clock_getres () .

0
adăugat
A fost introdus în 2001, dar nu este obligatoriu până la POSIX 2008.
adăugat autor R..
Din FAQ-ul Linux pentru lock_gettime (a se vedea răspunsul lui David Schlosnagle) "CLOCK_MONOTONIC ... este frecvența ajustată de NTP prin adjtimex (). În viitor (încă încerc să-mi iau patch-ul) va exista un CLOCK_MONOTONIC_RAW care nu va să fie modificat la toate și va avea o corelație liniară cu contoarele hardware. " Nu cred că ceasul _RAW a făcut-o vreodată în kernel (dacă nu a fost redenumit _HR, dar cercetările mele sugerează că și eforturile sunt abandonate).
adăugat autor Tony Delroy
@ vitaly.v.ch este POSIX, deci nu este doar Linux și "newist"? chiar distributii „Enterprise“, cum ar fi Red Hat Enterprise Linux se bazează pe 2.6.18, care nu are clock_gettime deci nu, nu foarte nou .. (data manpage în RHEL 2004-martie-12, astfel că a fost în jurul pentru un timp) decât dacă ești vorbind despre FTM Frumoase vechi WTF vrei sa spui?
adăugat autor Spudd86
clock_gettime este prezent numai pe cel mai nou Linux. alt sistem are doar gettimeofday ()
adăugat autor vitaly.v.ch
clock_gettime a fost inclus în POSIX în 2001. Din câte știu, clock_gettime () implementat în Linux 2.6 și qnx. dar linux 2.4 este utilizat în prezent în multe sisteme de producție.
adăugat autor vitaly.v.ch

Vinul utilizează de fapt gettimeofday () pentru a implementa QueryPerformanceCounter () și se știe că multe jocuri Windows funcționează pe Linux și Mac.

Starts http://source.winehq.org/source/dlls/kernel32/cpu.c#L312

leads to http://source.winehq.org/source/dlls/ntdll/time.c#L448

0
adăugat

Rezoluție înaltă, temporizare redusă pentru procesoarele Intel

Dacă sunteți pe hardware Intel, iată cum puteți citi contorul de instrucțiuni în timp real al procesorului. Acesta vă va indica numărul de cicluri de CPU executate de la pornirea procesorului. Acesta este probabil cel mai bun contra-granulat pe care îl puteți obține pentru măsurarea performanțelor.

Rețineți că acesta este numărul de cicluri de CPU. Pe linux puteți obține viteza CPU din / proc / cpuinfo și împărțiți pentru a obține numărul de secunde. Conversia acestui lucru la un dublu este destul de la îndemână.

Când o dau pe cutie, o să-l găsesc

11867927879484732
11867927879692217
it took this long to call printf: 207485

Iată ghidul dezvoltatorului Intel care oferă detalii de detaliu.

#include 
#include 

inline uint64_t rdtsc() {
    uint32_t lo, hi;
    __asm__ __volatile__ (
      "xorl %%eax, %%eax\n"
      "cpuid\n"
      "rdtsc\n"
      : "=a" (lo), "=d" (hi)
      :
      : "%ebx", "%ecx");
    return (uint64_t)hi << 32 | lo;
}

main()
{
    unsigned long long x;
    unsigned long long y;
    x = rdtsc();
    printf("%lld\n",x);
    y = rdtsc();
    printf("%lld\n",y);
    printf("it took this long to call printf: %lld\n",y-x);
}
0
adăugat
Codul dvs. nu ar trebui să utilizeze din nou CPUID după prima instrucțiune RDTSC și înainte de a executa codul care face obiectul evaluării? În caz contrar, ce înseamnă să oprești codul benchmarked executat înainte / în paralel cu primul cod RDTSC și, prin urmare, subreprezentat în delta RDTSC ?
adăugat autor Tony Delroy
Rețineți că TSC s-ar putea să nu fie întotdeauna sincronizat între nuclee, s-ar putea să-i oprească sau să-și schimbe frecvența atunci când procesorul intră în moduri de alimentare mai scăzute (și nu ai cum să știi că a procedat astfel) și, în general, nu este întotdeauna de încredere. Kernel-ul poate detecta când este fiabil, detectează alte alternative cum ar fi timer-ul HPET și ACPI PM și selectează automat cel mai bun. Este o idee bună să folosiți mereu kernel-ul pentru momentul în care nu sunteți sigur că TSC este stabil și monoton.
adăugat autor CesarB
Platforma TSC pe platformele Intel și Intel este sincronizată între mai multe creșteri și CPU-uri la o frecvență constantă independentă de stările de gestionare a alimentării. Consultați Manualul dezvoltatorului de software Intel, Vol. 3 Secțiunea 18.10. Cu toate acestea, rata la care incrementările contorului este nu aceeași cu frecvența procesorului. TSC crește la "frecvența maximă rezolvată a platformei, care este egală cu produsul de frecvență a magistralei scalabile și raportului maxim de autobuz rezolvat"? Intel Software Developer's Manual, Vol. 3 Secțiunea 18.18.5. O
adăugat autor sstock
Puteți obține frecvența magistralei scalabile și raportul bus maxim rezolvat prin interogarea registrelor specifice ale modelului (MSR) ale procesorului după cum urmează: Frecventa scalabilă a magistralei == MSR_FSB_FREQ [2: 0] id 0xCD, Raportul bus maxim rezolvat == MSR_PLATFORM_ID [ 12: 8] id 0x17. Consultați Intel SDM Vol.3 Apendicele B.1 pentru a interpreta valorile registrului. Puteți folosi instrumentul msr-tools pe Linux pentru a interoga registrele. kernel.org/pub/linux/utils/cpu/msr-tools
adăugat autor sstock

@Bernard:

Trebuie să recunosc că majoritatea exemplului tău a mers direct peste cap. Se compilează și pare să funcționeze. Este sigur acest lucru pentru sistemele SMP sau SpeedStep?

Aceasta este o întrebare bună ... Cred că codul este bine. Din punct de vedere practic, îl folosim în fiecare zi în compania mea, și vom rula pe o gamă destul de largă de cutii, totul de la 2-8 nuclee. Desigur, YMMV, etc, dar pare a fi o încredere și low-overhead (deoarece nu face o schimbare de context în spațiu sistem) de sincronizare.

În general, cum funcționează este:

  • declarați blocul de cod care urmează să fie asamblat (și volatil, deci Optimizatorul îl va lăsa singur.)
  • executați instrucțiunea CPUID. În plus față de obținerea unor informații despre procesor (la care nu facem nimic) sincronizează tamponul de execuție al procesorului astfel încât calendarul să nu fie afectat de executarea în afara ordinelor.
  • executați executarea rdtsc (citirea timestamp). Atinge numărul de ciclurile de mașină executate de la resetarea procesorului. Acesta este un 64-bit valoare, astfel încât cu viteze curente CPU se va înfășura în jurul valorii de la fiecare 194 de ani sau cam asa ceva. Interesant este faptul că, în originalul referință Pentium, ei notează că se înfășoară în jurul fiecăruia 5800 de ani sau cam asa ceva.
  • ultimele două linii stochează valorile din registre variabilele hi și lo și le puneți în valoarea de returnare pe 64 de biți.

Note specifice:

  • Execuția în afara ordinii poate provoca rezultate incorecte, așa că executăm "cpuid" instrucțiune care în plus față de a vă oferi unele informații despre cpu, de asemenea, sincronizează orice execuție de instrucțiuni în afara ordinii.

  • Cele mai multe sisteme de operare sincronizează contoarele pe procesoare atunci când încep, așa că răspunsul este bun la câteva nano-secunde.

  • Comentariul de hibernare este probabil adevărat, dar în practică vă probabil nu-mi pasă de sincronizări în limitele hibernării.

  • în ceea ce privește accelerarea: procesoarele Intel mai noi compensează viteza modifică și returnează un număr ajustat. Am făcut o scanare rapidă unele dintre cutiile din rețeaua noastră și au găsit o singură cutie nu a avut-o: un Pentium 3 care rulează un server de baze de date vechi. (acestea sunt cutii linux, așa că am verificat cu: grep constant_tsc / proc / cpuinfo)

  • Nu sunt sigur de procesoarele AMD, suntem în primul rând un magazin Intel, deși știu că unii dintre guru-ul nostru de nivel scăzut au făcut un lucru Evaluare AMD.

Sper că acest lucru îți satisface curiozitatea, este interesant și (IMHO) zona de programare sub-studiată. Știți când au fost Jeff și Joel vorbind despre dacă un programator ar trebui să știe C sau nu? am fost strigând la ei, "uitați că acel lucru de înalt nivel ... asamblor este ceea ce ar trebui să învățați dacă doriți să știți ce este computerul face!"

0
adăugat
Pentru referință, întrebarea pe care am adresat-o (Într-un răspuns separat - înainte de comentarii) a fost: "Trebuie să recunosc că majoritatea exemplului dvs. a mers direct peste capul meu, compilează și pare să funcționeze. Sistemele SMP sau SpeedStep? "
adăugat autor Bernard
... Oamenii kernel-ului încearcă să-i facă pe oameni să nu mai folosească rdtsc pentru o perioadă de timp ... și, în general, să evite utilizarea acestuia în kernel, pentru că este doar atât de nesigur.
adăugat autor Spudd86

Deci, se spune microsecunde în mod explicit, dar se spune că rezoluția ceasului de sistem nu este specificată. Presupun că rezolvarea în acest context înseamnă modul în care va fi sporită cea mai mică sumă?

Structura datelor este definită ca având microsecunde ca unitate de măsură, dar aceasta nu înseamnă că ceasul sau sistemul de operare este de fapt capabil să măsoare în mod fin.

După cum au sugerat alte persoane, gettimeofday () este rău, deoarece setarea timpului poate cauza oblicarea ceasului și aruncarea calculului. clock_gettime (CLOCK_MONOTONIC) este ceea ce doriți și clock_getres () vă va indica precizia ceasului.

0
adăugat
@ mpez0 nu o face
adăugat autor Spudd86
Deci, ce se întâmplă în cod atunci când gettimeofday () sare înainte sau înapoi cu economii de zi?
adăugat autor mpez0
clock_gettime este prezent numai pe cel mai nou Linux. alt sistem are doar gettimeofday ()
adăugat autor vitaly.v.ch

This answer mentions problems with the clock being adjusted. Both your problems guaranteeing tick units and the problems with the time being adjusted are solved in C++11 with the library.

Ceasul std :: chrono :: steady_clock este garantat să nu fie ajustat și, în plus, va avansa la o rată constantă față de timpul real, astfel încât tehnologiile precum SpeedStep nu trebuie să îl afecteze.

Aveți posibilitatea să obțineți unități typeafe convertindu-vă la una dintre specializările std :: chrono :: duration , cum ar fi std :: chrono :: microseconds . Cu acest tip nu există nicio ambiguitate cu privire la unitățile utilizate de valoarea de bifare. Cu toate acestea, rețineți că ceasul nu are neapărat această rezoluție. Aveți posibilitatea să convertiți o durată de timp până la două secunde fără a avea un ceas exact.

0
adăugat

Citirea RDTSC nu este fiabilă în sistemele SMP, deoarece fiecare CPU își păstrează propriul contor și fiecare contor nu este garantat prin sincronizarea cu un alt procesor.

S-ar putea sugera încercarea clock_gettime (CLOCK_REALTIME) . Manualul posix indică faptul că acest lucru ar trebui implementat pe toate sistemele compatibile. Acesta poate oferi un număr de nanosecunde, dar probabil că doriți să verificați clock_getres (CLOCK_REALTIME) din sistemul dvs. pentru a vedea care este rezoluția reală.

0
adăugat
clock_getres (CLOCK_REALTIME) nu va da rezoluția reală. Întotdeauna se întoarce "1 ns" (câte o nanosecundă) când sunt disponibile dispozitivele de control, verificați fișierul include / linux / hrtimer.h pentru definește HIGH_RES_NSEC 1 „http://stackoverflow.com/a/23044075/196561">stackoverflow.com/a/23044075/196561 )
adăugat autor osgx
0
adăugat