Movatterモバイル変換


[0]ホーム

URL:


Following system colour schemeSelected dark colour schemeSelected light colour scheme

Python Enhancement Proposals

PEP 418 – Add monotonic time, performance counter, and process time functions

Author:
Cameron Simpson <cs at cskk.id.au>,Jim J. Jewett <jimjjewett at gmail.com>,Stephen J. Turnbull <stephen at xemacs.org>,Victor Stinner <vstinner at python.org>
Status:
Final
Type:
Standards Track
Created:
26-Mar-2012
Python-Version:
3.3

Table of Contents

Abstract

This PEP proposes to addtime.get_clock_info(name),time.monotonic(),time.perf_counter() andtime.process_time() functions to Python 3.3.

Rationale

If a program uses the system time to schedule events or to implementa timeout, it may fail to run events at the right moment or stop thetimeout too early or too late when the system time is changed manually oradjusted automatically by NTP. A monotonic clock should be usedinstead to not be affected by system time updates:time.monotonic().

To measure the performance of a function,time.clock() can be usedbut it is very different on Windows and on Unix. On Windows,time.clock() includes time elapsed during sleep, whereas it doesnot on Unix.time.clock() resolution is very good on Windows, butvery bad on Unix. The newtime.perf_counter() function should beused instead to always get the most precise performance counter with aportable behaviour (ex: include time spend during sleep).

Until now, Python did not provide directly a portablefunction to measure CPU time.time.clock() can be used on Unix,but it has badresolution.resource.getrusage() oros.times() can also beused on Unix, but they require to compute the sum of timespent in kernel space and user space. The newtime.process_time()function acts as a portable counter that always measures CPU time(excluding time elapsed during sleep) and has the best availableresolution.

Each operating system implements clocks and performance countersdifferently, and it is useful to know exactly which function is usedand some properties of the clock like its resolution. The newtime.get_clock_info() function gives access to all availableinformation about each Python time function.

New functions:

  • time.monotonic(): timeout and scheduling, not affected by systemclock updates
  • time.perf_counter(): benchmarking, most precise clock for shortperiod
  • time.process_time(): profiling, CPU time of the process

Users of new functions:

  • time.monotonic(): concurrent.futures, multiprocessing, queue, subprocess,telnet and threading modules to implement timeout
  • time.perf_counter(): trace and timeit modules, pybench program
  • time.process_time(): profile module
  • time.get_clock_info(): pybench program to display information about thetimer like the resolution

Thetime.clock() function is deprecated because it is notportable: it behaves differently depending on the operating system.time.perf_counter() ortime.process_time() should be usedinstead, depending on your requirements.time.clock() is marked asdeprecated but is not planned for removal.

Limitations:

  • The behaviour of clocks after a system suspend is not defined in thedocumentation of new functions. The behaviour depends on theoperating system: see theMonotonic Clocks section below. Somerecent operating systems provide two clocks, one including timeelapsed during system suspend, one not including this time. Mostoperating systems only provide one kind of clock.
  • time.monotonic() and time.perf_counter() may or may not be adjusted.For example,CLOCK_MONOTONIC is slewed on Linux, whereasGetTickCount() is not adjusted on Windows.time.get_clock_info('monotonic')['adjustable'] can be used to checkif the monotonic clock is adjustable or not.
  • No time.thread_time() function is proposed by this PEP because it isnot needed by Python standard library nor a common asked feature.Such function would only be available on Windows and Linux. OnLinux, it is possible to usetime.clock_gettime(CLOCK_THREAD_CPUTIME_ID). On Windows, ctypes oranother module can be used to call theGetThreadTimes()function.

Python functions

New Functions

time.get_clock_info(name)

Get information on the specified clock. Supported clock names:

  • "clock":time.clock()
  • "monotonic":time.monotonic()
  • "perf_counter":time.perf_counter()
  • "process_time":time.process_time()
  • "time":time.time()

Return atime.clock_info object which has the following attributes:

  • implementation (str): name of the underlying operating systemfunction. Examples:"QueryPerformanceCounter()","clock_gettime(CLOCK_REALTIME)".
  • monotonic (bool): True if the clock cannot go backward.
  • adjustable (bool):True if the clock can be changed automatically(e.g. by a NTP daemon) or manually by the system administrator,Falseotherwise
  • resolution (float): resolution in seconds of the clock.

time.monotonic()

Monotonic clock, i.e. cannot go backward. It is not affected by systemclock updates. The reference point of the returned value isundefined, so that only the difference between the results ofconsecutive calls is valid and is a number of seconds.

On Windows versions older than Vista,time.monotonic() detectsGetTickCount() integer overflow (32 bits, roll-over after 49.7days). It increases an internal epoch (reference time by) 232 each time that an overflow is detected. The epoch is storedin the process-local state and sothe value oftime.monotonic() may be different in two Pythonprocesses running for more than 49 days. On more recent versions ofWindows and on other operating systems,time.monotonic() issystem-wide.

Availability: Windows, Mac OS X, Linux, FreeBSD, OpenBSD, Solaris.Not available on GNU/Hurd.

Pseudo-code[2]:

ifos.name=='nt':# GetTickCount64() requires Windows Vista, Server 2008 or laterifhasattr(_time,'GetTickCount64'):defmonotonic():return_time.GetTickCount64()*1e-3else:defmonotonic():ticks=_time.GetTickCount()ifticks<monotonic.last:# Integer overflow detectedmonotonic.delta+=2**32monotonic.last=ticksreturn(ticks+monotonic.delta)*1e-3monotonic.last=0monotonic.delta=0elifsys.platform=='darwin':defmonotonic():ifmonotonic.factorisNone:factor=_time.mach_timebase_info()monotonic.factor=timebase[0]/timebase[1]*1e-9return_time.mach_absolute_time()*monotonic.factormonotonic.factor=Noneelifhasattr(time,"clock_gettime")andhasattr(time,"CLOCK_HIGHRES"):defmonotonic():returntime.clock_gettime(time.CLOCK_HIGHRES)elifhasattr(time,"clock_gettime")andhasattr(time,"CLOCK_MONOTONIC"):defmonotonic():returntime.clock_gettime(time.CLOCK_MONOTONIC)

On Windows,QueryPerformanceCounter() is not used even though ithas a better resolution thanGetTickCount(). It is not reliableand has too many issues.

time.perf_counter()

Performance counter with the highest available resolution to measure ashort duration. It does include time elapsed during sleep and issystem-wide. The reference point of the returned value is undefined,so that only the difference between the results of consecutive callsis valid and is a number of seconds.

It is available on all platforms.

Pseudo-code:

ifos.name=='nt':def_win_perf_counter():if_win_perf_counter.frequencyisNone:_win_perf_counter.frequency=_time.QueryPerformanceFrequency()return_time.QueryPerformanceCounter()/_win_perf_counter.frequency_win_perf_counter.frequency=Nonedefperf_counter():ifperf_counter.use_performance_counter:try:return_win_perf_counter()exceptOSError:# QueryPerformanceFrequency() fails if the installed# hardware does not support a high-resolution performance# counterperf_counter.use_performance_counter=Falseifperf_counter.use_monotonic:# The monotonic clock is preferred over the system timetry:returntime.monotonic()exceptOSError:perf_counter.use_monotonic=Falsereturntime.time()perf_counter.use_performance_counter=(os.name=='nt')perf_counter.use_monotonic=hasattr(time,'monotonic')

time.process_time()

Sum of the system and user CPU time of the current process. It doesnot include time elapsed during sleep. It is process-wide bydefinition. The reference point of the returned value is undefined,so that only the difference between the results of consecutive callsis valid.

It is available on all platforms.

Pseudo-code[2]:

ifos.name=='nt':defprocess_time():handle=_time.GetCurrentProcess()process_times=_time.GetProcessTimes(handle)return(process_times['UserTime']+process_times['KernelTime'])*1e-7else:try:importresourceexceptImportError:has_resource=Falseelse:has_resource=Truedefprocess_time():ifprocess_time.clock_idisnotNone:try:returntime.clock_gettime(process_time.clock_id)exceptOSError:process_time.clock_id=Noneifprocess_time.use_getrusage:try:usage=resource.getrusage(resource.RUSAGE_SELF)returnusage[0]+usage[1]exceptOSError:process_time.use_getrusage=Falseifprocess_time.use_times:try:times=_time.times()cpu_time=times.tms_utime+times.tms_stimereturncpu_time/process_time.ticks_per_secondsexceptOSError:process_time.use_getrusage=Falsereturn_time.clock()if(hasattr(time,'clock_gettime')andhasattr(time,'CLOCK_PROF')):process_time.clock_id=time.CLOCK_PROFelif(hasattr(time,'clock_gettime')andhasattr(time,'CLOCK_PROCESS_CPUTIME_ID')):process_time.clock_id=time.CLOCK_PROCESS_CPUTIME_IDelse:process_time.clock_id=Noneprocess_time.use_getrusage=has_resourceprocess_time.use_times=hasattr(_time,'times')ifprocess_time.use_times:# sysconf("SC_CLK_TCK"), or the HZ constant, or 60process_time.ticks_per_seconds=_times.ticks_per_seconds

Existing Functions

time.time()

The system time which is usually the civil time. It is system-wide bydefinition. It can be set manually by the system administrator orautomatically by a NTP daemon.

It is available on all platforms and cannot fail.

Pseudo-code[2]:

ifos.name=="nt":deftime():return_time.GetSystemTimeAsFileTime()else:deftime():ifhasattr(time,"clock_gettime"):try:returntime.clock_gettime(time.CLOCK_REALTIME)exceptOSError:# CLOCK_REALTIME is not supported (unlikely)passifhasattr(_time,"gettimeofday"):try:return_time.gettimeofday()exceptOSError:# gettimeofday() should not failpassifhasattr(_time,"ftime"):return_time.ftime()else:return_time.time()

time.sleep()

Suspend execution for the given number of seconds. The actualsuspension time may be less than that requested because any caughtsignal will terminate thetime.sleep() following execution of thatsignal’s catching routine. Also, the suspension time may be longerthan requested by an arbitrary amount because of the scheduling ofother activity in the system.

Pseudo-code[2]:

try:importselectexceptImportError:has_select=Falseelse:has_select=hasattr(select,"select")ifhas_select:defsleep(seconds):returnselect.select([],[],[],seconds)elifhasattr(_time,"delay"):defsleep(seconds):milliseconds=int(seconds*1000)_time.delay(milliseconds)elifos.name=="nt":defsleep(seconds):milliseconds=int(seconds*1000)win32api.ResetEvent(hInterruptEvent);win32api.WaitForSingleObject(sleep.sigint_event,milliseconds)sleep.sigint_event=win32api.CreateEvent(NULL,TRUE,FALSE,FALSE)# SetEvent(sleep.sigint_event) will be called by the signal handler of SIGINTelifos.name=="os2":defsleep(seconds):milliseconds=int(seconds*1000)DosSleep(milliseconds)else:defsleep(seconds):seconds=int(seconds)_time.sleep(seconds)

Deprecated Function

time.clock()

On Unix, return the current processor time as a floating point numberexpressed in seconds. It is process-wide by definition. The resolution,and in fact the very definition of the meaning of “processor time”,depends on that of the C function of the same name, but in any case,this is the function to use for benchmarking Python or timingalgorithms.

On Windows, this function returns wall-clock seconds elapsed since thefirst call to this function, as a floating point number, based on theWin32 functionQueryPerformanceCounter(). The resolution istypically better than one microsecond. It is system-wide.

Pseudo-code[2]:

ifos.name=='nt':defclock():try:return_win_perf_counter()exceptOSError:# QueryPerformanceFrequency() fails if the installed# hardware does not support a high-resolution performance# counterpassreturn_time.clock()else:clock=_time.clock

Alternatives: API design

Other names for time.monotonic()

  • time.counter()
  • time.metronomic()
  • time.seconds()
  • time.steady(): “steady” is ambiguous: it means different things todifferent people. For example, on Linux, CLOCK_MONOTONIC isadjusted. If we uses the real time as the reference clock, we maysay that CLOCK_MONOTONIC is steady. But CLOCK_MONOTONIC getssuspended on system suspend, whereas real time includes any timespent in suspend.
  • time.timeout_clock()
  • time.wallclock(): time.monotonic() is not the system time aka the“wall clock”, but a monotonic clock with an unspecified startingpoint.

The name “time.try_monotonic()” was also proposed for an olderversion of time.monotonic() which would fall back to the systemtime when no monotonic clock was available.

Other names for time.perf_counter()

  • time.high_precision()
  • time.highres()
  • time.hires()
  • time.performance_counter()
  • time.timer()

Only expose operating system clocks

To not have to define high-level clocks, which is a difficult task, asimpler approach is to only expose operating system clocks.time.clock_gettime() and related clock identifiers were already addedto Python 3.3 for example.

time.monotonic(): Fallback to system time

If no monotonic clock is available, time.monotonic() falls back to thesystem time.

Issues:

  • It is hard to define such a function correctly in the documentation:is it monotonic? Is it steady? Is it adjusted?
  • Some users want to decide what to do when no monotonic clock isavailable: use another clock, display an error, or do somethingelse.

Different APIs were proposed to define such function.

One function with a flag: time.monotonic(fallback=True)

  • time.monotonic(fallback=True) falls back to the system time if nomonotonic clock is available or if the monotonic clock failed.
  • time.monotonic(fallback=False) raises OSError if monotonic clockfails and NotImplementedError if the system does not provide amonotonic clock

A keyword argument that gets passed as a constant in the caller isusually poor API.

Raising NotImplementedError for a function is something uncommon inPython and should be avoided.

One time.monotonic() function, no flag

time.monotonic() returns (time: float, is_monotonic: bool).

An alternative is to use a function attribute:time.monotonic.is_monotonic. The attribute value would be None beforethe first call to time.monotonic().

Choosing the clock from a list of constraints

The PEP as proposed offers a few new clocks, but their guaranteesare deliberately loose in order to offer useful clocks on differentplatforms. This inherently embeds policy in the calls, and thecaller must thus choose a policy.

The “choose a clock” approach suggests an additional API to letcallers implement their own policy if necessaryby making most platform clocks available and letting the caller pick amongst them.The PEP’s suggested clocks are still expected to be available for the commonsimple use cases.

To do this two facilities are needed:an enumeration of clocks, and metadata on the clocks to enable the user toevaluate their suitability.

The primary interface is a function make simple choices easy:the caller can usetime.get_clock(*flags) with some combination of flags.This includes at least:

  • time.MONOTONIC: clock cannot go backward
  • time.STEADY: clock rate is steady
  • time.ADJUSTED: clock may be adjusted, for example by NTP
  • time.HIGHRES: clock with the highest resolution

It returns a clock object with a .now() method returning the current time.The clock object is annotated with metadata describing the clock feature set;its .flags field will contain at least all the requested flags.

time.get_clock() returns None if no matching clock is found and so calls canbe chained using the or operator. Example of a simple policy decision:

T=get_clock(MONOTONIC)orget_clock(STEADY)orget_clock()t=T.now()

The available clocks always at least include a wrapper fortime.time(),so a final call with no flags can always be used to obtain a working clock.

Examples of flags of system clocks:

  • QueryPerformanceCounter: MONOTONIC | HIGHRES
  • GetTickCount: MONOTONIC | STEADY
  • CLOCK_MONOTONIC: MONOTONIC | STEADY (or only MONOTONIC on Linux)
  • CLOCK_MONOTONIC_RAW: MONOTONIC | STEADY
  • gettimeofday(): (no flag)

The clock objects contain other metadata including the clock flagswith additional feature flags above those listed above, the nameof the underlying OS facility, and clock precisions.

time.get_clock() still chooses a single clock; an enumerationfacility is also required.The most obvious method is to offertime.get_clocks() with thesame signature astime.get_clock(), but returning a sequenceof all clocks matching the requested flags.Requesting no flags would thus enumerate all available clocks,allowing the caller to make an arbitrary choice amongst them basedon their metadata.

Example partial implementation:clockutils.py.

Working around operating system bugs?

Should Python ensure that a monotonic clock is trulymonotonic by computing the maximum with the clock value and theprevious value?

Since it’s relatively straightforward to cache the last value returnedusing a static variable, it might be interesting to use this to makesure that the values returned are indeed monotonic.

  • Virtual machines provide less reliable clocks.
  • QueryPerformanceCounter() has known bugs (only one is not fixed yet)

Python may only work around a specific known operating system bug:KB274323 contains a code example to workaround the bug (useGetTickCount() to detect QueryPerformanceCounter() leap).

Issues with “correcting” non-monotonicities:

  • if the clock is accidentally set forward by an hour and then backagain, you wouldn’t have a useful clock for an hour
  • the cache is not shared between processes so different processeswouldn’t see the same clock value

Glossary

Accuracy:
The amount of deviation of measurements by a given instrument fromtrue values. See alsoAccuracy and precision.Inaccuracy in clocks may be caused by lack of precision, drift, or anincorrect initial setting of the clock (e.g., timing of threads isinherently inaccurate because perfect synchronization in resettingcounters is quite difficult).
Adjusted:
Resetting a clock to the correct time. This may be done eitherwith a <Step> or by <Slewing>.
Civil Time:
Time of day; external to the system. 10:45:13am is a Civil time;45 seconds is not. Provided by existing functiontime.localtime() andtime.gmtime(). Not changed by thisPEP.
Clock:
An instrument for measuring time. Different clocks have differentcharacteristics; for example, a clock with nanosecond<precision> may start to <drift> after a few minutes, while a lessprecise clock remained accurate for days. This PEP is primarilyconcerned with clocks which use a unit of seconds.
Counter:
A clock which increments each time a certain event occurs. Acounter is strictly monotonic, but not a monotonic clock. It canbe used to generate a unique (and ordered) timestamp, but thesetimestamps cannot be mapped to <civil time>; tick creation may wellbe bursty, with several advances in the same millisecond followedby several days without any advance.
CPU Time:
A measure of how much CPU effort has been spent on a certain task.CPU seconds are often normalized (so that a variable number canoccur in the same actual second). CPU seconds can be importantwhen profiling, but they do not map directly to user response time,nor are they directly comparable to (real time) seconds.
Drift:
The accumulated error against “true” time, as defined externally tothe system. Drift may be due to imprecision, or to a differencebetween the average rate at which clock time advances and that ofreal time.
Epoch:
The reference point of a clock. For clocks providing <civil time>,this is often midnight as the day (and year) rolled over to January1, 1970. For a <clock_monotonic> clock, the epoch may be undefined(represented as None).
Latency:
Delay. By the time a clock call returns, the <real time> hasadvanced, possibly by more than the precision of the clock.
Monotonic:
The characteristics expected of a monotonic clock in practice.Moving in at most one direction; for clocks, that direction isforward. The <clock> should also be <steady>, and should beconvertible to a unit of seconds. The tradeoffs often include lackof a defined <epoch> or mapping to <Civil Time>.
Precision:
The amount of deviation among measurements of the same physicalvalue by a single instrument. Imprecision in clocks may be caused bya fluctuation of the rate at which clock time advances relative toreal time, including clock adjustment by slewing.
Process Time:
Time elapsed since the process began. It is typically measured in<CPU time> rather than <real time>, and typically does not advancewhile the process is suspended.
Real Time:
Time in the real world. This differs from <Civil time> in that itis not <adjusted>, but they should otherwise advance in lockstep.It is not related to the “real time” of “Real Time [Operating]Systems”. It is sometimes called “wall clock time” to avoid thatambiguity; unfortunately, that introduces different ambiguities.
Resolution:
The smallest difference between two physical values that resultsin a different measurement by a given instrument.
Slew:
A slight change to a clock’s speed, usually intended to correct<drift> with respect to an external authority.
Stability:
Persistence of accuracy. A measure of expected <drift>.
Steady:
A clock with high <stability> and relatively high <accuracy> and<precision>. In practice, it is often used to indicate a<clock_monotonic> clock, but places greater emphasis on theconsistency of the duration between subsequent ticks.
Step:
An instantaneous change in the represented time. Instead ofspeeding or slowing the clock (<slew>), a single offset ispermanently added.
System Time:
Time as represented by the Operating System.
Thread Time:
Time elapsed since the thread began. It is typically measured in<CPU time> rather than <real time>, and typically does not advancewhile the thread is idle.
Wallclock:
What the clock on the wall says. This is typically used as asynonym for <real time>; unfortunately, wall time is itselfambiguous.

Hardware clocks

List of hardware clocks

  • HPET: A High Precision Event Timer (HPET) chip consists of a 64-bitup-counter (main counter) counting at least at 10 MHz and a set ofup to 256 comparators (at least 3). Each HPET can have up to 32timers. HPET can cause around 3 seconds of drift per day.
  • TSC (Time Stamp Counter): Historically, the TSC increased with everyinternal processor clock cycle, but now the rate is usually constant(even if the processor changes frequency) and usually equals themaximum processor frequency. Multiple cores have different TSCvalues. Hibernation of system will reset TSC value. The RDTSCinstruction can be used to read this counter. CPU frequency scalingfor power saving.
  • ACPI Power Management Timer: ACPI 24-bit timer with a frequency of3.5 MHz (3,579,545 Hz).
  • Cyclone: The Cyclone timer uses a 32-bit counter on IBM ExtendedX-Architecture (EXA) chipsets which include computers that use theIBM “Summit” series chipsets (ex: x440). This is available in IA32and IA64 architectures.
  • PIT (programmable interrupt timer): Intel 8253/8254 chipsets with aconfigurable frequency in range 18.2 Hz - 1.2 MHz. It uses a 16-bitcounter.
  • RTC (Real-time clock). Most RTCs use a crystal oscillator with afrequency of 32,768 Hz.

Linux clocksource

There were 4 implementations of the time in the Linux kernel: UTIME(1996), timer wheel (1997), HRT (2001) and hrtimers (2007). Thelatter is the result of the “high-res-timers” project started byGeorge Anzinger in 2001, with contributions by Thomas Gleixner andDouglas Niehaus. The hrtimers implementation was merged into Linux2.6.21, released in 2007.

hrtimers supports various clock sources. It sets a priority to eachsource to decide which one will be used. Linux supports the followingclock sources:

  • tsc
  • hpet
  • pit
  • pmtmr: ACPI Power Management Timer
  • cyclone

High-resolution timers are not supported on all hardwarearchitectures. They are at least provided on x86/x86_64, ARM andPowerPC.

clock_getres() returns 1 nanosecond forCLOCK_REALTIME andCLOCK_MONOTONIC regardless of underlying clock source. ReadRe:clock_getres() and real resolution from Thomas Gleixner (9 Feb2012) for an explanation.

The/sys/devices/system/clocksource/clocksource0 directorycontains two useful files:

  • available_clocksource: list of available clock sources
  • current_clocksource: clock source currently used. It ispossible to change the current clocksource by writing the name of aclocksource into this file.

/proc/timer_list contains the list of all hardware timers.

Read also thetime(7) manual page:“overview of time and timers”.

FreeBSD timecounter

kern.timecounter.choice lists available hardware clocks with theirpriority. The sysctl program can be used to change the timecounter.Example:

# dmesg | grep TimecounterTimecounter"i8254"frequency1193182Hzquality0Timecounter"ACPI-safe"frequency3579545Hzquality850Timecounter"HPET"frequency100000000Hzquality900Timecounter"TSC"frequency3411154800Hzquality800Timecounterstickevery10.000msec# sysctl kern.timecounter.choicekern.timecounter.choice:TSC(800)HPET(900)ACPI-safe(850)i8254(0)dummy(-1000000)# sysctl kern.timecounter.hardware="ACPI-fast"kern.timecounter.hardware:HPET->ACPI-fast

Available clocks:

  • “TSC”: Time Stamp Counter of the processor
  • “HPET”: High Precision Event Timer
  • “ACPI-fast”: ACPI Power Management timer (fast mode)
  • “ACPI-safe”: ACPI Power Management timer (safe mode)
  • “i8254”: PIT with Intel 8254 chipset

Thecommit 222222 (May2011) decreased ACPI-fast timecounter quality to 900 and increasedHPET timecounter quality to 950: “HPET on modern platforms usuallyhave better resolution and lower latency than ACPI timer”.

ReadTimecounters: Efficient and precise timekeeping in SMP kernels by Poul-Henning Kamp(2002) for the FreeBSD Project.

Performance

Reading a hardware clock has a cost. The following table comparesthe performance of different hardware clocks on Linux 3.3 with IntelCore i7-2600 at 3.40GHz (8 cores). Thebench_time.c programwas used to fill these tables.

FunctionTSCACPI PMHPET
time()2 ns2 ns2 ns
CLOCK_REALTIME_COARSE10 ns10 ns10 ns
CLOCK_MONOTONIC_COARSE12 ns13 ns12 ns
CLOCK_THREAD_CPUTIME_ID134 ns135 ns135 ns
CLOCK_PROCESS_CPUTIME_ID127 ns129 ns129 ns
clock()146 ns146 ns143 ns
gettimeofday()23 ns726 ns637 ns
CLOCK_MONOTONIC_RAW31 ns716 ns607 ns
CLOCK_REALTIME27 ns707 ns629 ns
CLOCK_MONOTONIC27 ns723 ns635 ns

FreeBSD 8.0 in kvm with hardware virtualization:

FunctionTSCACPI-SafeHPETi8254
time()191 ns188 ns189 ns188 ns
CLOCK_SECOND187 ns184 ns187 ns183 ns
CLOCK_REALTIME_FAST189 ns180 ns187 ns190 ns
CLOCK_UPTIME_FAST191 ns185 ns186 ns196 ns
CLOCK_MONOTONIC_FAST188 ns187 ns188 ns189 ns
CLOCK_THREAD_CPUTIME_ID208 ns206 ns207 ns220 ns
CLOCK_VIRTUAL280 ns279 ns283 ns296 ns
CLOCK_PROF289 ns280 ns282 ns286 ns
clock()342 ns340 ns337 ns344 ns
CLOCK_UPTIME_PRECISE197 ns10380 ns4402 ns4097 ns
CLOCK_REALTIME196 ns10376 ns4337 ns4054 ns
CLOCK_MONOTONIC_PRECISE198 ns10493 ns4413 ns3958 ns
CLOCK_UPTIME197 ns10523 ns4458 ns4058 ns
gettimeofday()202 ns10524 ns4186 ns3962 ns
CLOCK_REALTIME_PRECISE197 ns10599 ns4394 ns4060 ns
CLOCK_MONOTONIC201 ns10766 ns4498 ns3943 ns

Each function was called 100,000 times and CLOCK_MONOTONIC was used toget the time before and after. The benchmark was run 5 times, keepingthe minimum time.

NTP adjustment

NTP has different methods to adjust a clock:

  • “slewing”: change the clock frequency to be slightly faster orslower (which is done withadjtime()). Since the slew rate islimited to 0.5 millisecond per second, each second of adjustment requires anamortization interval of 2000 seconds. Thus, an adjustment of manyseconds can take hours or days to amortize.
  • “stepping”: jump by a large amount in a single discrete step (whichis done withsettimeofday())

By default, the time is slewed if the offset is less than 128 ms, butstepped otherwise.

Slewing is generally desirable (i.e. we should use CLOCK_MONOTONIC,not CLOCK_MONOTONIC_RAW) if one wishes to measure “real” time (and nota time-like object like CPU cycles). This is because the clock on theother end of the NTP connection from you is probably better at keepingtime: hopefully that thirty-five thousand dollars of Cesiumtimekeeping goodness is doing something better than your PC’s $3quartz crystal, after all.

Get more detail in thedocumentation of the NTP daemon.

Operating system time functions

Monotonic Clocks

NameC ResolutionAdjustedInclude SleepInclude Suspend
gethrtime()1 nsNoYesYes
CLOCK_HIGHRES1 nsNoYesYes
CLOCK_MONOTONIC1 nsSlewed on LinuxYesNo
CLOCK_MONOTONIC_COARSE1 nsSlewed on LinuxYesNo
CLOCK_MONOTONIC_RAW1 nsNoYesNo
CLOCK_BOOTTIME1 ns?YesYes
CLOCK_UPTIME1 nsNoYes?
mach_absolute_time()1 nsNoYesNo
QueryPerformanceCounter()-NoYes?
GetTickCount[64]()1 msNoYesYes
timeGetTime()1 msNoYes?

The “C Resolution” column is the resolution of the underlying Cstructure.

Examples of clock resolution on x86_64:

NameOperating systemOS ResolutionPython Resolution
QueryPerformanceCounterWindows Seven10 ns10 ns
CLOCK_HIGHRESSunOS 5.112 ns265 ns
CLOCK_MONOTONICLinux 3.01 ns322 ns
CLOCK_MONOTONIC_RAWLinux 3.31 ns628 ns
CLOCK_BOOTTIMELinux 3.31 ns628 ns
mach_absolute_time()Mac OS 10.61 ns3 µs
CLOCK_MONOTONICFreeBSD 8.211 ns5 µs
CLOCK_MONOTONICOpenBSD 5.010 ms5 µs
CLOCK_UPTIMEFreeBSD 8.211 ns6 µs
CLOCK_MONOTONIC_COARSELinux 3.31 ms1 ms
CLOCK_MONOTONIC_COARSELinux 3.04 ms4 ms
GetTickCount64()Windows Seven16 ms15 ms

The “OS Resolution” is the resolution announced by the operatingsystem.The “Python Resolution” is the smallest difference between two callsto the time function computed in Python using theclock_resolution.pyprogram.

mach_absolute_time

Mac OS X provides a monotonic clock: mach_absolute_time(). It isbased on absolute elapsed time since system boot. It is notadjusted and cannot be set.

mach_timebase_info() gives a fraction to convert the clock value to a number ofnanoseconds. See also theTechnical Q&A QA1398.

mach_absolute_time() stops during a sleep on a PowerPC CPU, but not onan Intel CPU:Different behaviour of mach_absolute_time() on i386/ppc.

CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW, CLOCK_BOOTTIME

CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW represent monotonic time sincesome unspecified starting point. They cannot be set. The resolutioncan be read usingclock_getres().

Documentation: refer to the manual page of your operating system.Examples:

CLOCK_MONOTONIC is available at least on the following operatingsystems:

  • DragonFly BSD, FreeBSD >= 5.0, OpenBSD, NetBSD
  • Linux
  • Solaris

The following operating systems don’t support CLOCK_MONOTONIC:

On Linux, NTP may adjust the CLOCK_MONOTONIC rate (slewed), but it cannotjump backward.

CLOCK_MONOTONIC_RAW is specific to Linux. It is similar toCLOCK_MONOTONIC, but provides access to a raw hardware-based time thatis not subject to NTP adjustments. CLOCK_MONOTONIC_RAW requires Linux2.6.28 or later.

Linux 2.6.39 and glibc 2.14 introduces a new clock: CLOCK_BOOTTIME.CLOCK_BOOTTIME is identical to CLOCK_MONOTONIC, except that it alsoincludes any time spent in suspend. Read alsoWaking systems fromsuspend (March, 2011).

CLOCK_MONOTONIC stops while the machine is suspended.

Linux provides also CLOCK_MONOTONIC_COARSE since Linux 2.6.32. It issimilar to CLOCK_MONOTONIC, less precise but faster.

clock_gettime() fails if the system does not support the specifiedclock, even if the standard C library supports it. For example,CLOCK_MONOTONIC_RAW requires a kernel version 2.6.28 or later.

Windows: QueryPerformanceCounter

High-resolution performance counter. It is monotonic.The frequency of the counter can be read using QueryPerformanceFrequency().The resolution is 1 / QueryPerformanceFrequency().

It has a much higher resolution, but has lower long term precisionthan GetTickCount() and timeGetTime() clocks. For example, it willdrift compared to the low precision clocks.

Documentation:

Hardware clocks used by QueryPerformanceCounter:

  • Windows XP: RDTSC instruction of Intel processors, the clockfrequency is the frequency of the processor (between 200 MHz and 3GHz, usually greater than 1 GHz nowadays).
  • Windows 2000: ACPI power management timer, frequency = 3,549,545 Hz.It can be forced through the “/usepmtimer” flag in boot.ini.

QueryPerformanceFrequency() should only be called once: the frequencywill not change while the system is running. It fails if theinstalled hardware does not support a high-resolution performancecounter.

QueryPerformanceCounter() cannot be adjusted:SetSystemTimeAdjustment()only adjusts the system time.

Bugs:

  • The performance counter value may unexpectedly leap forward becauseof a hardware bug, seeKB274323.
  • On VirtualBox, QueryPerformanceCounter() does not increment the highpart every time the low part overflows, seeMonotonic timers(2009).
  • VirtualBox had a bug in its HPET virtualized device:QueryPerformanceCounter() did jump forward by approx. 42 seconds (issue#8707).
  • Windows XP had a bug (seeKB896256): on a multiprocessorcomputer, QueryPerformanceCounter() returned a different value foreach processor. The bug was fixed in Windows XP SP2.
  • Issues with processor with variable frequency: the frequency ischanged depending on the workload to reduce memory consumption.
  • Chromium don’t use QueryPerformanceCounter() on Athlon X2 CPUs(model 15) because “QueryPerformanceCounter is unreliable” (seebase/time_win.cc in Chromium source code)

Windows: GetTickCount(), GetTickCount64()

GetTickCount() and GetTickCount64() are monotonic, cannot fail and arenot adjusted by SetSystemTimeAdjustment(). MSDN documentation:GetTickCount(),GetTickCount64().The resolution can be read using GetSystemTimeAdjustment().

The elapsed time retrieved by GetTickCount() or GetTickCount64()includes time the system spends in sleep or hibernation.

GetTickCount64() was added to Windows Vista and Windows Server 2008.

It is possible to improve the precision using theundocumentedNtSetTimerResolution() function.There are applications using this undocumented function, example:TimerResolution.

WaitForSingleObject() uses the same timer as GetTickCount() with thesame precision.

Windows: timeGetTime

The timeGetTime function retrieves the system time, in milliseconds.The system time is the time elapsed since Windows was started. ReadthetimeGetTime() documentation.

The return type of timeGetTime() is a 32-bit unsigned integer. AsGetTickCount(), timeGetTime() rolls over after 2^32 milliseconds (49.7days).

The elapsed time retrieved by timeGetTime() includes time the systemspends in sleep.

The default precision of the timeGetTime function can be fivemilliseconds or more, depending on the machine.

timeBeginPeriod() can be used to increase the precision oftimeGetTime() up to 1 millisecond, but it negatively affects powerconsumption. Calling timeBeginPeriod() also affects the granularityof some other timing calls, such as CreateWaitableTimer(),WaitForSingleObject() and Sleep().

Note

timeGetTime() and timeBeginPeriod() are part the Windows multimedialibrary and so require to link the program against winmm or todynamically load the library.

Solaris: CLOCK_HIGHRES

The Solaris OS has a CLOCK_HIGHRES timer that attempts to use anoptimal hardware source, and may give close to nanosecond resolution.CLOCK_HIGHRES is the nonadjustable, high-resolution clock. For timerscreated with a clockid_t value of CLOCK_HIGHRES, the system willattempt to use an optimal hardware source.

The resolution of CLOCK_HIGHRES can be read usingclock_getres().

Solaris: gethrtime

The gethrtime() function returns the current high-resolution realtime. Time is expressed as nanoseconds since some arbitrary time inthe past; it is not correlated in any way to the time of day, and thusis not subject to resetting or drifting by way of adjtime() orsettimeofday(). The hires timer is ideally suited to performancemeasurement tasks, where cheap, accurate interval timing is required.

The linearity of gethrtime() is not preserved across a suspend-resumecycle (Bug 4272663).

Read thegethrtime() manual page of Solaris 11.

On Solaris, gethrtime() is the same as clock_gettime(CLOCK_MONOTONIC).

System Time

NameC ResolutionInclude SleepInclude Suspend
CLOCK_REALTIME1 nsYesYes
CLOCK_REALTIME_COARSE1 nsYesYes
GetSystemTimeAsFileTime100 nsYesYes
gettimeofday()1 µsYesYes
ftime()1 msYesYes
time()1 secYesYes

The “C Resolution” column is the resolution of the underlying Cstructure.

Examples of clock resolution on x86_64:

NameOperating systemOS ResolutionPython Resolution
CLOCK_REALTIMESunOS 5.1110 ms238 ns
CLOCK_REALTIMELinux 3.01 ns238 ns
gettimeofday()Mac OS 10.61 µs4 µs
CLOCK_REALTIMEFreeBSD 8.211 ns6 µs
CLOCK_REALTIMEOpenBSD 5.010 ms5 µs
CLOCK_REALTIME_COARSELinux 3.31 ms1 ms
CLOCK_REALTIME_COARSELinux 3.04 ms4 ms
GetSystemTimeAsFileTime()Windows Seven16 ms1 ms
ftime()Windows Seven-1 ms

The “OS Resolution” is the resolution announced by the operatingsystem.The “Python Resolution” is the smallest difference between two callsto the time function computed in Python using theclock_resolution.pyprogram.

Windows: GetSystemTimeAsFileTime

The system time can be read using GetSystemTimeAsFileTime(), ftime() andtime(). The resolution of the system time can be read usingGetSystemTimeAdjustment().

Read theGetSystemTimeAsFileTime() documentation.

The system time can be set using SetSystemTime().

System time on UNIX

gettimeofday(), ftime(), time() and clock_gettime(CLOCK_REALTIME) returnthe system time. The resolution of CLOCK_REALTIME can be read usingclock_getres().

The system time can be set using settimeofday() orclock_settime(CLOCK_REALTIME).

Linux provides also CLOCK_REALTIME_COARSE since Linux 2.6.32. It is similarto CLOCK_REALTIME, less precise but faster.

Alexander Shishkin proposed an API for Linux to be notified when the systemclock is changed:timerfd: add TFD_NOTIFY_CLOCK_SET to watch for clock changes (4th version of the API, March 2011). TheAPI is not accepted yet, but CLOCK_BOOTTIME provides a similar feature.

Process Time

The process time cannot be set. It is not monotonic: the clocks stopwhile the process is idle.

NameC ResolutionInclude SleepInclude Suspend
GetProcessTimes()100 nsNoNo
CLOCK_PROCESS_CPUTIME_ID1 nsNoNo
getrusage(RUSAGE_SELF)1 µsNoNo
times()-NoNo
clock()-Yes on Windows, No otherwiseNo

The “C Resolution” column is the resolution of the underlying Cstructure.

Examples of clock resolution on x86_64:

NameOperating systemOS ResolutionPython Resolution
CLOCK_PROCESS_CPUTIME_IDLinux 3.31 ns1 ns
CLOCK_PROFFreeBSD 8.210 ms1 µs
getrusage(RUSAGE_SELF)FreeBSD 8.2-1 µs
getrusage(RUSAGE_SELF)SunOS 5.11-1 µs
CLOCK_PROCESS_CPUTIME_IDLinux 3.01 ns1 µs
getrusage(RUSAGE_SELF)Mac OS 10.6-5 µs
clock()Mac OS 10.61 µs5 µs
CLOCK_PROFOpenBSD 5.0-5 µs
getrusage(RUSAGE_SELF)Linux 3.0-4 ms
getrusage(RUSAGE_SELF)OpenBSD 5.0-8 ms
clock()FreeBSD 8.28 ms8 ms
clock()Linux 3.01 µs10 ms
times()Linux 3.010 ms10 ms
clock()OpenBSD 5.010 ms10 ms
times()OpenBSD 5.010 ms10 ms
times()Mac OS 10.610 ms10 ms
clock()SunOS 5.111 µs10 ms
times()SunOS 5.111 µs10 ms
GetProcessTimes()Windows Seven16 ms16 ms
clock()Windows Seven1 ms1 ms

The “OS Resolution” is the resolution announced by the operatingsystem.The “Python Resolution” is the smallest difference between two callsto the time function computed in Python using theclock_resolution.pyprogram.

Functions

  • Windows:GetProcessTimes().The resolution can be read using GetSystemTimeAdjustment().
  • clock_gettime(CLOCK_PROCESS_CPUTIME_ID): High-resolution per-processtimer from the CPU. The resolution can be read using clock_getres().
  • clock(). The resolution is 1 / CLOCKS_PER_SEC.
    • Windows: The elapsed wall-clock time since the start of theprocess (elapsed time in seconds times CLOCKS_PER_SEC). Includetime elapsed during sleep. It can fail.
    • UNIX: returns an approximation of processor time used by theprogram.
  • getrusage(RUSAGE_SELF) returns a structure of resource usage of the currenetprocess. ru_utime is user CPU time and ru_stime is the system CPU time.
  • times(): structure of process times. The resolution is 1 / ticks_per_seconds,where ticks_per_seconds is sysconf(_SC_CLK_TCK) or the HZ constant.

Python source code includes a portable library to get the process time (CPUtime):Tools/pybench/systimes.py.

See also theQueryProcessCycleTime() function(sum of the cycle time of all threads) andclock_getcpuclockid().

Thread Time

The thread time cannot be set. It is not monotonic: the clocks stopwhile the thread is idle.

NameC ResolutionInclude SleepInclude Suspend
CLOCK_THREAD_CPUTIME_ID1 nsYesEpoch changes
GetThreadTimes()100 nsNo?

The “C Resolution” column is the resolution of the underlying Cstructure.

Examples of clock resolution on x86_64:

NameOperating systemOS ResolutionPython Resolution
CLOCK_THREAD_CPUTIME_IDFreeBSD 8.21 µs1 µs
CLOCK_THREAD_CPUTIME_IDLinux 3.31 ns649 ns
GetThreadTimes()Windows Seven16 ms16 ms

The “OS Resolution” is the resolution announced by the operatingsystem.The “Python Resolution” is the smallest difference between two callsto the time function computed in Python using theclock_resolution.pyprogram.

Functions

  • Windows:GetThreadTimes().The resolution can be read using GetSystemTimeAdjustment().
  • clock_gettime(CLOCK_THREAD_CPUTIME_ID): Thread-specific CPU-timeclock. It uses a number of CPU cycles, not a number of seconds.The resolution can be read using of clock_getres().

See also theQueryThreadCycleTime() function(cycle time for the specified thread) and pthread_getcpuclockid().

Windows: QueryUnbiasedInterruptTime

Gets the current unbiased interrupt time from the biased interrupttime and the current sleep bias amount. This time is not affected bypower management sleep transitions.

The elapsed time retrieved by the QueryUnbiasedInterruptTime functionincludes only time that the system spends in the working state.QueryUnbiasedInterruptTime() is not monotonic.

QueryUnbiasedInterruptTime() was introduced in Windows 7.

See alsoQueryIdleProcessorCycleTime() function(cycle time for the idle thread of each processor)

Sleep

Suspend execution of the process for the given number of seconds.Sleep is not affected by system time updates. Sleep is paused duringsystem suspend. For example, if a process sleeps for 60 seconds andthe system is suspended for 30 seconds in the middle of the sleep, thesleep duration is 90 seconds in the real time.

Sleep can be interrupted by a signal: the function fails with EINTR.

NameC Resolution
nanosleep()1 ns
clock_nanosleep()1 ns
usleep()1 µs
delay()1 µs
sleep()1 sec

Other functions:

NameC Resolution
sigtimedwait()1 ns
pthread_cond_timedwait()1 ns
sem_timedwait()1 ns
select()1 µs
epoll()1 ms
poll()1 ms
WaitForSingleObject()1 ms

The “C Resolution” column is the resolution of the underlying Cstructure.

Functions

clock_nanosleep

clock_nanosleep(clock_id, flags, nanoseconds, remaining):Linuxmanpage of clock_nanosleep().

If flags is TIMER_ABSTIME, then request is interpreted as an absolutetime as measured by the clock, clock_id. If request is less than orequal to the current value of the clock, then clock_nanosleep()returns immediately without suspending the calling thread.

POSIX.1 specifies that changing the value of the CLOCK_REALTIME clockvia clock_settime(2) shall have no effect on a thread that is blockedon a relative clock_nanosleep().

select()

select(nfds, readfds, writefds, exceptfs, timeout).

Since Linux 2.6.28, select() uses high-resolution timers to handle thetimeout. A process has a “slack” attribute to configure the precisionof the timeout, the default slack is 50 microseconds. Before Linux2.6.28, timeouts for select() were handled by the main timingsubsystem at a jiffy-level resolution. Read alsoHigh- (but not toohigh-) resolution timeouts andTimer slack.

Other functions

  • poll(), epoll()
  • sigtimedwait(). POSIX: “If the Monotonic Clock option is supported,the CLOCK_MONOTONIC clock shall be used to measure the timeinterval specified by the timeout argument.”
  • pthread_cond_timedwait(), pthread_condattr_setclock(). “The defaultvalue of the clock attribute shall refer to the system time.”
  • sem_timedwait(): “If the Timers option is supported, the timeoutshall be based on the CLOCK_REALTIME clock. If the Timers option isnot supported, the timeout shall be based on the system time asreturned by the time() function. The precision of the timeoutshall be the precision of the clock on which it is based.”
  • WaitForSingleObject(): use the same timer than GetTickCount() withthe same precision.

System Standby

The ACPI power state “S3” is a system standby mode, also called“Suspend to RAM”. RAM remains powered.

On Windows, theWM_POWERBROADCAST message is sent to Windowsapplications to notify them of power-management events (ex: owner statushas changed).

For Mac OS X, readRegistering and unregistering for sleep and wakenotifications(Technical Q&A QA1340).

Footnotes

[2] (1,2,3,4,5)
“_time” is a hypothetical module only used for the example.The time module is implemented in C and so there is no need forsuch a module.

Links

Related Python issues:

Libraries exposing monotonic clocks:

Time:

Acceptance

The PEP was accepted on 2012-04-28 by Guido van Rossum[1]. The PEPimplementation has since been committed to the repository.

References

[1]
https://mail.python.org/pipermail/python-dev/2012-April/119094.html

Copyright

This document has been placed in the public domain.


Source:https://github.com/python/peps/blob/main/peps/pep-0418.rst

Last modified:2025-02-01 08:55:40 GMT


[8]ページ先頭

©2009-2025 Movatter.jp