Is gettimeofday () gegarandeerd microseconde resolutie te zijn?

stemmen
82

Ik ben porting een spel, die oorspronkelijk voor de Win32 API werd geschreven, naar Linux (nou ja, porting het OS X-poort van de Win32 haven naar Linux).

Ik heb uitgevoerd QueryPerformanceCounterdoor het geven van de uSeconds aangezien het proces opstarten:

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, in combinatie met QueryPerformanceFrequency()het geven van een constante 1000000 naarmate de frequentie, werkt goed op mijn machine , geeft me een 64 bit variabele die bevat uSeconds, aangezien het programma opstarten.

Dus is deze draagbare? Ik wil niet om te ontdekken dat werkt anders als de kernel werd gecompileerd op een bepaalde manier of iets dergelijks. Ik ben prima met het feit dat het niet-overdraagbaar naar iets anders dan Linux, echter.

De vraag is gesteld op 01/08/2008 om 15:36
bron van user
In andere talen...                            


10 antwoorden

stemmen
4

Vanuit mijn ervaring, en van wat ik heb gelezen over het internet, is het antwoord "Nee," het is niet gegarandeerd. Het is afhankelijk van CPU-snelheid, het besturingssysteem, de smaak van Linux, etc.

antwoordde op 01/08/2008 om 15:46
bron van user

stemmen
54

Kan zijn. Maar je hebt grotere problemen. gettimeofday()kan leiden tot verkeerde timings als er processen op uw systeem dat de timer te veranderen (dat wil zeggen, ntpd). Op een "normale" linux, hoewel, ik denk dat de resolutie van gettimeofday()is 10US. Het kan vooruit en achteruit springen en tijd, dus op basis van de processen die op uw systeem. Dit maakt effectief het antwoord op uw vraag niet.

Je moet kijken naar clock_gettime(CLOCK_MONOTONIC)voor timing intervallen. Hij lijdt aan een aantal minder problemen als gevolg van zaken als multi-core systemen en externe klok instellingen.

Ook op zoek naar de clock_getres()functie.

antwoordde op 01/08/2008 om 15:53
bron van user

stemmen
8

De werkelijke resolutie van gettimeofday () is afhankelijk van de hardware architectuur. Intel-processors evenals SPARC machines bieden hoge resolutie timers die microseconden te meten. Andere hardware-architecturen terugvallen om de timer van het systeem, die doorgaans wordt ingesteld op 100 Hz. In dergelijke gevallen zal de tijdsresolutie minder nauwkeurig zijn.

Ik kreeg dit antwoord van hoge resolutie Tijd Meet- en Timers, deel I

antwoordde op 01/08/2008 om 15:55
bron van user

stemmen
39

Hoge resolutie, lage overhead Timing voor Intel-processors

Als je op Intel hardware, hier is hoe de CPU real-time instructie teller te lezen. Het zal u vertellen het aantal CPU-cycli uitgevoerd, omdat de processor werd opgestart. Dit is waarschijnlijk de beste korrels teller je kunt krijgen voor het meten van prestaties.

Let op: dit is het aantal CPU-cycli. Op Linux kunt u de CPU-snelheid van / proc / cpuinfo en te verdelen naar het aantal seconden te krijgen. Het omzetten van dit tot een dubbele is heel handig.

Toen ik dit draaien op mijn vak, krijg ik

11867927879484732
11867927879692217
it took this long to call printf: 207485

Hier is de gids Intel ontwikkelaar die tonnen detail geeft.

#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);
}
antwoordde op 02/08/2008 om 09:08
bron van user

stemmen
9

Zo staat het microseconden expliciet, maar zegt dat de resolutie van het systeem klok is niet gespecificeerd. Ik neem aan dat de resolutie betekent in deze context hoe de kleinste bedrag dat zij ooit zal worden verhoogd?

De gegevensstructuur wordt gedefinieerd als microseconden als een meeteenheid, maar dat betekent niet dat de klok of besturingssysteem daadwerkelijk kan meten die fijn.

Net als andere mensen hebben gesuggereerd, gettimeofday()is slecht, omdat het instellen van de klok scheef kan leiden en af te werpen uw berekening. clock_gettime(CLOCK_MONOTONIC)is wat je wilt, en clock_getres()geeft je de precisie van uw klok te vertellen.

antwoordde op 02/08/2008 om 18:57
bron van user

stemmen
18

@Bernard:

Ik moet toegeven, de meeste van uw voorbeeld ging meteen over mijn hoofd. Het doet compileren en lijkt te werken, dat wel. Is dit veilig voor SMP systemen of SpeedStep?

Dat is een goede vraag ... Ik denk dat de code's ok. Vanuit praktisch oogpunt, gebruiken we het in mijn bedrijf elke dag, en we draaien op een vrij breed scala aan dozen, alles 2-8 kernen. Natuurlijk YMMV, etc, maar het lijkt een betrouwbare en weinig overhead (omdat het niet een contextschakelaar naar systeemspecifieke ruimte te maken) Werkwijze timing.

In het algemeen hoe het werkt is:

  • verklaren het blok van de code om assembler (en vluchtig, zodat de optimizer zal laten staan).
  • voer de CPUID instructie. Naast het krijgen van een aantal CPU-gegevens (die we doen er niets mee te doen) synchroniseert de uitvoering van de CPU buffer zodat de timings niet worden beïnvloed door de uitvoering 'out-of-order.
  • voer de RDTSC (lees tijdstempel) uitvoering. Dit haalt het aantal machine-cycli uitgevoerd, omdat de processor is gereset. Dit is een 64-bits waarde, dus met de huidige CPU snelheden zal het wikkelen rond elke 194 jaar of zo. Interessant is dat in de oorspronkelijke Pentium referentie, merken zij op het rond elke 5800 jaar of zo.
  • de laatste paar lijnen opslaan van de waarden van de registers in de variabelen hi en lo en we deze in de 64-bit retourwaarde.

Specifieke opmerkingen:

  • out-of-order uitvoering kan leiden tot onjuiste resultaten, dus we voeren de "cpuid" instructie die in aanvulling op het geven van u wat informatie over de cpu ook synchroniseert een out-of-order instructie uitvoering.

  • De meeste OS's synchroniseren van de tellers op de CPU's wanneer ze beginnen, dus het antwoord is het goed om binnen een paar nano-seconden.

  • De winterslaap commentaar is waarschijnlijk waar, maar in de praktijk heb je waarschijnlijk niet de zorg over timings over winterslaap grenzen.

  • met betrekking tot speedstep: Nieuwer Intel CPU's te compenseren voor de snelheid verandert en geeft een aangepaste tellen. Ik heb een snelle scan over een aantal van de dozen op ons netwerk en vond slechts één doos, die het niet hebben: een Pentium 3 draaien van een oude database server. (Dit zijn linux dozen, dus ik gecontroleerd: grep constant_tsc / proc / cpuinfo)

  • Ik ben niet zeker over de AMD CPU's, zijn we in de eerste plaats een Intel winkel, hoewel ik weet dat sommige van onze low-level systemen goeroes deden een AMD evalueren.

Hoop dat dit voldoet aan uw nieuwsgierigheid, het is een interessant en (IMHO) onder bestudeerde gebied van de programmering. U weet wanneer Jeff en Joel spraken over het al dan niet een programmeur moet weten C? Ik schreeuwde naar hen, "hey vergeten dat op hoog niveau C stuff ... assembler is wat je moet leren als je wilt weten wat de computer aan het doen!"

antwoordde op 04/08/2008 om 01:51
bron van user

stemmen
11

Wijn wordt daadwerkelijk gebruikt gettimeofday () uit te voeren QueryPerformanceCounter () en het is bekend om vele Windows-games werken op Linux en Mac.

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

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

antwoordde op 04/08/2008 om 15:44
bron van user

stemmen
3

Het lezen van de RDTSC is niet betrouwbaar in SMP-systemen, omdat elke CPU onderhoudt hun eigen teller en elke teller is niet gegarandeerd door gesynchroniseerd met betrekking tot een andere CPU.

Ik zou kunnen suggereren proberen clock_gettime(CLOCK_REALTIME). De posix handleiding geeft aan dat dit moet worden uitgevoerd op alle compatibele systemen. Het kan een nanoseconde telling te bieden, maar zal je waarschijnlijk wilt controleren clock_getres(CLOCK_REALTIME)op uw systeem om te zien wat de werkelijke resolutie is.

antwoordde op 18/08/2008 om 16:40
bron van user

stemmen
14

U kunt geïnteresseerd in Linux FAQ voorclock_gettime(CLOCK_REALTIME)

antwoordde op 18/08/2008 om 16:51
bron van user

stemmen
5

Dit antwoord noemt problemen met de klok wordt aangepast. Zowel uw problemen garanderen tick-eenheden en de problemen met de tijd wordt aangepast worden opgelost in C ++ 11 met de <chrono>bibliotheek.

De klok std::chrono::steady_clockwordt niet gegarandeerd worden aangepast en bovendien zal vooruit met een constante snelheid ten opzichte van realtime dus technologieën zoals SpeedStep mag geen invloed op.

U kunt Typesafe eenheden krijgen door het omzetten van een van de std::chrono::durationspecialisaties, zoals std::chrono::microseconds. Met dit type is er geen onduidelijkheid over de eenheden die door de teek waarde. Houd er echter rekening mee dat de klok deze resolutie niet per se hoeft te hebben. U kunt een duur converteren naar attoseconden zonder daadwerkelijk een klok die nauwkeurig.

antwoordde op 26/06/2012 om 16:57
bron van user

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more