diff options
author | Oscar Nihlgård <oscarnihlgard@gmail.com> | 2019-07-11 11:19:11 +0200 |
---|---|---|
committer | Oscar Nihlgård <oscarnihlgard@gmail.com> | 2019-07-12 10:15:06 +0200 |
commit | fd24a8923ebc51592d2210637304ff2c0a2b8ecd (patch) | |
tree | fa4568591f617200900452eea1990e4026cdb394 /lib/std | |
parent | b8be1ccb855f8bde82ed1721e4231119ffa48e9f (diff) | |
download | Nim-fd24a8923ebc51592d2210637304ff2c0a2b8ecd.tar.gz |
[feature] Added std/monotimes
Diffstat (limited to 'lib/std')
-rw-r--r-- | lib/std/monotimes.nim | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/lib/std/monotimes.nim b/lib/std/monotimes.nim new file mode 100644 index 000000000..d2d9717d7 --- /dev/null +++ b/lib/std/monotimes.nim @@ -0,0 +1,173 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2019 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +##[ + The ``std/monotimes`` module implements monotonic timestamps. A monotonic + timestamp represents the time that has passed since some system defined + point in time. The monotonic timestamps are guaranteed to always increase, + meaning that that the following is guaranteed to work: + + .. code-block:: nim + let a = getMonoTime() + # ... do some work + let b = getMonoTime() + assert a <= b + + This is not guaranteed for the `times.Time` type! This means that the + `MonoTime` should be used when measuring durations of time with + high precision. + + However, since `MonoTime` represents the time that has passed since some + unknown time origin, it cannot be converted to a human readable timestamp. + If this is required, the `times.Time` type should be used instead. + + The `MonoTime` type stores the timestamp in nanosecond resolution, but note + that the actual supported time resolution differs for different systems. + + See also + ======== + * `times module <times.html>`_ +]## + +import times + +type + MonoTime* = object ## Represents a monotonic timestamp. + ticks: int64 + +when defined(macosx): + type + MachTimebaseInfoData {.pure, final, importc: "mach_timebase_info_data_t", + header: "<mach/mach_time.h>".} = object + numer, denom: int32 + + proc mach_absolute_time(): int64 {.importc, header: "<mach/mach.h>".} + proc mach_timebase_info(info: var MachTimebaseInfoData) {.importc, + header: "<mach/mach_time.h>".} + + let machAbsoluteTimeFreq = block: + var freq: MachTimebaseInfoData + mach_timebase_info(freq) + freq + +when defined(js): + proc getJsTicks: float = + {.emit: """ + var isNode = typeof module !== 'undefined' && module.exports + + if (isNode) { + var process = require('process'); + var time = process.hrtime() + return time[0] + time[1] / 1000000000; + } else { + return window.performance.now() * 1000000; + } + """.} + + # Workaround for #6752. + {.push overflowChecks: off.} + proc `-`(a, b: int64): int64 = + system.`-`(a, b) + proc `+`(a, b: int64): int64 = + system.`+`(a, b) + {.pop.} + +elif defined(posix): + import posix + +elif defined(windows): + proc QueryPerformanceCounter(res: var uint64) {. + importc: "QueryPerformanceCounter", stdcall, dynlib: "kernel32".} + proc QueryPerformanceFrequency(res: var uint64) {. + importc: "QueryPerformanceFrequency", stdcall, dynlib: "kernel32".} + + let queryPerformanceCounterFreq = block: + var freq: uint64 + QueryPerformanceFrequency(freq) + 1_000_000_000'u64 div freq + +proc getMonoTime*(): MonoTime {.tags: [TimeEffect].} = + ## Get the current `MonoTime` timestamp. + ## + ## When compiled with the JS backend and executed in a browser, + ## this proc calls `window.performance.now()`, which is not supported by + ## older browsers. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Performance/now) + ## for more information. + when defined(JS): + let ticks = getJsTicks() + result = MonoTime(ticks: (ticks * 1_000_000_000).int64) + elif defined(macosx): + let ticks = mach_absolute_time() + result = MonoTime(ticks: ticks * machAbsoluteTimeFreq.numer div + machAbsoluteTimeFreq.denom) + elif defined(posix): + var ts: Timespec + discard clock_gettime(CLOCK_MONOTONIC, ts) + result = MonoTime(ticks: ts.tv_sec.int64 * 1_000_000_000 + + ts.tv_nsec.int64) + elif defined(windows): + var ticks: uint64 + QueryPerformanceCounter(ticks) + result = MonoTime(ticks: (ticks * queryPerformanceCounterFreq).int64) + +proc ticks*(t: MonoTime): int64 = + ## Returns the raw ticks value from a `MonoTime`. This value always uses + ## nanosecond time resolution. + t.ticks + +proc `$`*(t: MonoTime): string = + $t.ticks + +proc `-`*(a, b: MonoTime): Duration = + ## Returns the difference between two `MonoTime` timestamps as a `Duration`. + initDuration(nanoseconds = (a.ticks - b.ticks)) + +proc `+`*(a: MonoTime, b: Duration): MonoTime = + ## Increases `a` by `b`. + MonoTime(ticks: a.ticks + b.inNanoseconds) + +proc `-`*(a: MonoTime, b: Duration): MonoTime = + ## Reduces `a` by `b`. + MonoTime(ticks: a.ticks - b.inNanoseconds) + +proc `<`*(a, b: MonoTime): bool = + ## Returns true if `a` happened before `b`. + a.ticks < b.ticks + +proc `<=`*(a, b: MonoTime): bool = + ## Returns true if `a` happened before `b` or if they happened simultaneous. + a.ticks <= b.ticks + +proc `==`*(a, b: MonoTime): bool = + ## Returns true if `a` and `b` happened simultaneous. + a.ticks == b.ticks + +proc high*(typ: typedesc[MonoTime]): MonoTime = + ## Returns the highest representable `MonoTime`. + MonoTime(ticks: high(int64)) + +proc low*(typ: typedesc[MonoTime]): MonoTime = + ## Returns the lowest representable `MonoTime`. + MonoTime(ticks: low(int64)) + +when isMainModule: + let d = initDuration(nanoseconds = 10) + let t1 = getMonoTime() + let t2 = t1 + d + + doAssert t2 - t1 == d + doAssert t1 == t1 + doAssert t1 != t2 + doAssert t2 - d == t1 + doAssert t1 < t2 + doAssert t1 <= t2 + doAssert t1 <= t1 + doAssert not(t2 < t1) + doAssert t1 < high(MonoTime) + doAssert low(MonoTime) < t1 \ No newline at end of file |