diff options
Diffstat (limited to 'lib/std/monotimes.nim')
-rw-r--r-- | lib/std/monotimes.nim | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/lib/std/monotimes.nim b/lib/std/monotimes.nim new file mode 100644 index 000000000..bf6dc776b --- /dev/null +++ b/lib/std/monotimes.nim @@ -0,0 +1,160 @@ +# +# +# 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 not to decrease, +meaning that that the following is guaranteed to work: +]## + +runnableExamples: + let a = getMonoTime() + 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 std/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>".} + +when defined(js): + proc getJsTicks: float = + ## Returns ticks in the unit seconds. + when defined(nodejs): + {.emit: """ + let process = require('process'); + let time = process.hrtime(); + `result` = time[0] + time[1] / 1000000000; + """.} + else: + proc jsNow(): float {.importjs: "window.performance.now()".} + result = jsNow() / 1000 + + # 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) and not defined(osx): + import std/posix + +when defined(zephyr): + proc k_uptime_ticks(): int64 {.importc: "k_uptime_ticks", header: "<kernel.h>".} + proc k_ticks_to_ns_floor64(ticks: int64): int64 {.importc: "k_ticks_to_ns_floor64", header: "<kernel.h>".} + +elif defined(windows): + proc QueryPerformanceCounter(res: var uint64) {. + importc: "QueryPerformanceCounter", stdcall, dynlib: "kernel32".} + proc QueryPerformanceFrequency(res: var uint64) {. + importc: "QueryPerformanceFrequency", stdcall, dynlib: "kernel32".} + +proc getMonoTime*(): MonoTime {.tags: [TimeEffect].} = + ## Returns the current `MonoTime` timestamp. + ## + ## When compiled with the JS backend and executed in a browser, + ## this proc calls `window.performance.now()`. + ## 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() + var machAbsoluteTimeFreq: MachTimebaseInfoData + mach_timebase_info(machAbsoluteTimeFreq) + result = MonoTime(ticks: ticks * machAbsoluteTimeFreq.numer div + machAbsoluteTimeFreq.denom) + elif defined(zephyr): + let ticks = k_ticks_to_ns_floor64(k_uptime_ticks()) + result = MonoTime(ticks: ticks) + 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) + + var freq: uint64 + QueryPerformanceFrequency(freq) + let queryPerformanceCounterFreq = 1_000_000_000'u64 div freq + 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)) |