Vra

Ek dra 'n speletjie, wat oorspronklik vir die Win32 API geskryf is, na Linux oor (wel, porteer die OS X-poort van die Win32-poort na Linux).

Ek het geïmplementeer QueryPerformanceCounter deur die uSeconds te gee sedert die proses begin het:

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

Dit, tesame met QueryPerformanceFrequency() gee 'n konstante 1000000 as die frekwensie, werk goed op my masjien, gee my 'n 64-bis veranderlike wat bevat uSeconds sedert die program begin het.

Dus is dit draagbaar? Ek wil nie ontdek dit werk anders as die kern op 'n sekere manier saamgestel is of so iets nie.Ek is egter goed daarmee dat dit nie oordraagbaar is na iets anders as Linux nie.

Was dit nuttig?

Oplossing

Kan wees.Maar jy het groter probleme. gettimeofday() kan lei tot verkeerde tydsberekeninge as daar prosesse op jou stelsel is wat die timer verander (bv. ntpd).Op 'n "normale" Linux glo ek egter die resolusie van gettimeofday() is 10 ons.Dit kan vorentoe en agtertoe spring en tyd, gevolglik, gebaseer op die prosesse wat op jou stelsel loop.Dit maak effektief die antwoord op jou vraag nr.

Jy moet kyk na clock_gettime(CLOCK_MONOTONIC) vir tydsberekeningsintervalle.Dit ly aan verskeie minder probleme as gevolg van dinge soos multi-kern stelsels en eksterne klok instellings.

Kyk ook na die clock_getres() funksie.

Ander wenke

Hoë resolusie, lae oorhoofse tydsberekening vir Intel-verwerkers

As jy op Intel-hardeware is, lees die SVE-intydse instruksieteller hier.Dit sal jou die aantal SVE-siklusse vertel wat uitgevoer is sedert die verwerker gelaai is.Dit is waarskynlik die fynste toonbank wat jy vir prestasiemeting kan kry.

Let daarop dat dit die aantal SVE-siklusse is.Op Linux kan jy die SVE-spoed van /proc/cpuinfo kry en verdeel om die aantal sekondes te kry.Om dit om te skakel na 'n dubbel is nogal handig.

Wanneer ek dit op my boks laat loop, kry ek

11867927879484732
11867927879692217
it took this long to call printf: 207485

Hier is die Intel ontwikkelaar se gids dit gee tonne detail.

#include <stdio.h>
#include <stdint.h>

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

@Bernard:

Ek moet erken, die meeste van jou voorbeeld het reguit oor my kop gegaan.Dit stel wel saam, en blyk egter te werk.Is dit veilig vir SMP-stelsels of SpeedStep?

Dis 'n goeie vraag...Ek dink die kode is ok.Vanuit 'n praktiese oogpunt gebruik ons ​​dit elke dag in my onderneming, en ons hardloop op 'n taamlike wye verskeidenheid bokse, alles van 2-8 kerns.Natuurlik blyk YMMV, ens., Maar dit blyk 'n betroubare en lae oorkop te wees (omdat dit nie 'n konteks oorgaan na die stelsel-ruimte nie) metode van tydsberekening.

Oor die algemeen is hoe dit werk:

  • Verklaar die blok van die kode om monteerder te wees (en wisselvallig, sodat die optimiseerder dit met rus laat).
  • voer die CPUID-instruksie uit.Benewens die verkryging van 'n paar SVE-inligting (waarmee ons niks doen nie), sinchroniseer dit die uitvoeringsbuffer van die SVE, sodat die tydsberekening nie beïnvloed word deur uitvoering buite die orde nie.
  • voer die rdtsc (lees tydstempel) uitvoering uit.Dit haal die aantal masjiensiklusse wat uitgevoer is sedert die verwerker teruggestel is.Dit is 'n 64-bis-waarde, dus met die huidige SVE-snelhede sal dit elke 194 jaar of so draai.Interessant genoeg, in die oorspronklike Pentium -verwysing, let hulle op dat dit elke 5800 jaar of so draai.
  • Die laaste paar reëls stoor die waardes van die registers in die veranderlikes HI en LO, en plaas dit in die 64-bis-opbrengswaarde.

Spesifieke notas:

  • Out-of-orde-uitvoering kan verkeerde resultate veroorsaak, dus voer ons die "CPUID" -instruksie uit, wat benewens u inligting oor die SVE gee, ook enige buite-orde-instruksie-uitvoering sinchroniseer.

  • Die meeste OS's sinchroniseer die toonbanke op die SVE's as hulle begin, so die antwoord is goed om binne 'n paar nano-sekondes te wees.

  • Die hibernerende opmerking is waarskynlik waar, maar in die praktyk gee u waarskynlik nie om oor tydsberekening oor die winterslaapgrense nie.

  • oor speedstep:Nuwer Intel CPU's vergoed vir die snelheidsveranderings en gee 'n aangepaste telling.Ek het 'n vinnige skandering oor sommige van die bokse op ons netwerk gedoen en net een boks gevind wat dit nie gehad het nie:'n Pentium 3 met 'n ou databasisbediener.(hierdie is linux-bokse, so ek het nagegaan met:grep constant_tsc /proc/cpuinfo)

  • Ek is nie seker oor die AMD-CPU's nie, ons is hoofsaaklik 'n Intel-winkel, hoewel ek weet dat sommige van ons lae-vlak-stelsels wat Gurus 'n AMD-evaluering gedoen het.

Hoop dit bevredig u nuuskierigheid, dit is 'n interessante en (IMHO) ondergestudeerde programmering.Weet jy wanneer Jeff en Joel gepraat het oor die vraag of 'n programmeerder C moet weet of nie?Ek het op hulle geskree: "Hey vergeet daardie hoë-vlak C-dinge ...As u moet leer as u wil weet wat die rekenaar doen! "

Wine gebruik eintlik gettimeofday() om QueryPerformanceCounter() te implementeer en dit is bekend dat dit baie Windows-speletjies op Linux en Mac laat werk.

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

lei tot http://source.winehq.org/source/dlls/ntdll/time.c#L448

Dit sê dus uitdruklik mikrosekondes, maar sê die resolusie van die stelselklok is ongespesifiseer.Ek veronderstel resolusie in hierdie konteks beteken hoe die kleinste bedrag dit ooit verhoog sal word?

Die datastruktuur word gedefinieer as om mikrosekondes as 'n eenheid van meting te hê, maar dit beteken nie dat die horlosie of bedryfstelsel eintlik in staat is om dit fyn te meet nie.

Soos ander mense voorgestel het, gettimeofday() is sleg, want die stel van die tyd kan klok skeef veroorsaak en jou berekening afgooi. clock_gettime(CLOCK_MONOTONIC) is wat jy wil hê, en clock_getres() sal jou die akkuraatheid van jou horlosie vertel.

Die werklike resolusie van gettimeofday() hang af van die hardeware-argitektuur.Intel-verwerkers sowel as SPARC-masjiene bied timers met 'n hoë resolusie wat mikrosekondes meet.Ander hardeware-argitekture val terug na die stelsel se timer, wat tipies op 100 Hz gestel is.In sulke gevalle sal die tydresolusie minder akkuraat wees.

Ek het hierdie antwoord gekry van Hoë resolusie tydmeting en tydtellers, Deel I

Hierdie antwoord noem probleme met die klok wat verstel word.Beide jou probleme wat regmerkie-eenhede waarborg en die probleme met die tyd wat aangepas word, word in C++11 opgelos met die <chrono> biblioteek.

Die horlosie std::chrono::steady_clock word gewaarborg om nie aangepas te word nie, en verder sal dit teen 'n konstante tempo vorder relatief tot reële tyd, so tegnologieë soos SpeedStep moet dit nie beïnvloed nie.

Jy kan tipeveilige eenhede kry deur om te skakel na een van die std::chrono::duration spesialisasies, soos std::chrono::microseconds.Met hierdie tipe is daar geen onduidelikheid oor die eenhede wat deur die regmerkie-waarde gebruik word nie.Hou egter in gedagte dat die horlosie nie noodwendig hierdie resolusie het nie.Jy kan 'n duur omskakel na attosekondes sonder om eintlik 'n klok so akkuraat te hê.

Uit my ervaring, en uit wat ek op die internet gelees het, is die antwoord "Nee," dit is nie gewaarborg nie.Dit hang af van SVE-spoed, bedryfstelsel, geur van Linux, ens.

Die lees van die RDTSC is nie betroubaar in SMP-stelsels nie, aangesien elke SVE hul eie teller handhaaf en elke teller word nie gewaarborg deur gesinchroniseer met betrekking tot 'n ander SVE nie.

Ek kan voorstel om te probeer clock_gettime(CLOCK_REALTIME).Die posix-handleiding dui aan dat dit op alle stelsels geïmplementeer moet word.Dit kan 'n nanosekonde-telling verskaf, maar jy sal waarskynlik wil kyk clock_getres(CLOCK_REALTIME) op jou stelsel om te sien wat die werklike resolusie is.

Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top