mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-04 12:07:51 +00:00
[feature] Added std/monotimes
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
|
||||
- Make public `Sha1Digest` and `Sha1State` types and `newSha1State`, `update` and `finalize` procedures from `sha1` module. (#11694)
|
||||
|
||||
- Added the `std/monotimes` module which implements monotonic timestamps.
|
||||
|
||||
## Language additions
|
||||
|
||||
|
||||
@@ -185,7 +185,10 @@ Generic Operating System Services
|
||||
Module for process communication beyond ``os.execShellCmd``.
|
||||
|
||||
* `times <times.html>`_
|
||||
The ``times`` module contains basic support for working with time.
|
||||
The ``times`` module contains support for working with time.
|
||||
|
||||
* `std/monotimes <monotimes.html>`_
|
||||
The `monotimes` module implements monotonic timestamps.
|
||||
|
||||
* `dynlib <dynlib.html>`_
|
||||
This module implements the ability to access symbols from shared libraries.
|
||||
|
||||
@@ -186,6 +186,10 @@
|
||||
day has passed. The ``Duration`` type on the other hand normalizes everything
|
||||
to seconds, and will therefore say that 90000 seconds has passed, which is
|
||||
the same as 25 hours.
|
||||
|
||||
See also
|
||||
========
|
||||
* `monotimes module <monotimes.html>`_
|
||||
]##
|
||||
|
||||
import strutils, math, options
|
||||
|
||||
173
lib/std/monotimes.nim
Normal file
173
lib/std/monotimes.nim
Normal file
@@ -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
|
||||
@@ -158,6 +158,7 @@ lib/windows/winlean.nim
|
||||
lib/pure/random.nim
|
||||
lib/pure/complex.nim
|
||||
lib/pure/times.nim
|
||||
lib/std/monotimes.nim
|
||||
lib/pure/osproc.nim
|
||||
lib/pure/pegs.nim
|
||||
lib/pure/dynlib.nim
|
||||
|
||||
Reference in New Issue
Block a user