summary refs log tree commit diff stats
path: root/lib/std/monotimes.nim
blob: 5c67a5d4c4bd0e63b6446fafe7ac4c16df03d7bd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
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 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 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))
7 preadv2 378 pwritev2 379 pkey_mprotect 380 pkey_alloc 381 pkey_free 382 statx 383 arch_prctl 384 io_pgetevents 385 rseq 386 semget 393 semctl 394 shmget 395 shmctl 396 shmat 397 shmdt 398 msgget 399 msgsnd 400 msgrcv 401 msgctl 402 clock_gettime64 403 clock_settime64 404 clock_adjtime64 405 clock_getres_time64 406 clock_nanosleep_time64 407 timer_gettime64 408 timer_settime64 409 timerfd_gettime64 410 timerfd_settime64 411 utimensat_time64 412 pselect6_time64 413 ppoll_time64 414 io_pgetevents_time64 416 recvmmsg_time64 417 mq_timedsend_time64 418 mq_timedreceive_time64 419 semtimedop_time64 420 rt_sigtimedwait_time64 421 futex_time64 422 sched_rr_get_interval_time64 423 pidfd_send_signal 424 io_uring_setup 425 io_uring_enter 426 io_uring_register 427 open_tree 428 move_mount 429 fsopen 430 fsconfig 431 fsmount 432 fspick 433 pidfd_open 434 clone3 435 close_range 436 openat2 437 pidfd_getfd 438 faccessat2 439 process_madvise 440 epoll_pwait2 441 mount_setattr 442 quotactl_fd 443 landlock_create_ruleset 444 landlock_add_rule 445 landlock_restrict_self 446 memfd_secret 447 process_mrelease 448