monotimes.nim 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2019 Nim contributors
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ##[
  10. The `std/monotimes` module implements monotonic timestamps. A monotonic
  11. timestamp represents the time that has passed since some system defined
  12. point in time. The monotonic timestamps are guaranteed not to decrease,
  13. meaning that that the following is guaranteed to work:
  14. ]##
  15. runnableExamples:
  16. let a = getMonoTime()
  17. let b = getMonoTime()
  18. assert a <= b
  19. ##[
  20. This is not guaranteed for the `times.Time` type! This means that the
  21. `MonoTime` should be used when measuring durations of time with
  22. high precision.
  23. However, since `MonoTime` represents the time that has passed since some
  24. unknown time origin, it cannot be converted to a human readable timestamp.
  25. If this is required, the `times.Time` type should be used instead.
  26. The `MonoTime` type stores the timestamp in nanosecond resolution, but note
  27. that the actual supported time resolution differs for different systems.
  28. See also
  29. ========
  30. * `times module <times.html>`_
  31. ]##
  32. import std/times
  33. type
  34. MonoTime* = object ## Represents a monotonic timestamp.
  35. ticks: int64
  36. when defined(macosx):
  37. type
  38. MachTimebaseInfoData {.pure, final, importc: "mach_timebase_info_data_t",
  39. header: "<mach/mach_time.h>".} = object
  40. numer, denom: int32
  41. proc mach_absolute_time(): int64 {.importc, header: "<mach/mach.h>".}
  42. proc mach_timebase_info(info: var MachTimebaseInfoData) {.importc,
  43. header: "<mach/mach_time.h>".}
  44. when defined(js):
  45. proc getJsTicks: float =
  46. ## Returns ticks in the unit seconds.
  47. when defined(nodejs):
  48. {.emit: """
  49. let process = require('process');
  50. let time = process.hrtime();
  51. `result` = time[0] + time[1] / 1000000000;
  52. """.}
  53. else:
  54. proc jsNow(): float {.importjs: "window.performance.now()".}
  55. result = jsNow() / 1000
  56. # Workaround for #6752.
  57. {.push overflowChecks: off.}
  58. proc `-`(a, b: int64): int64 =
  59. system.`-`(a, b)
  60. proc `+`(a, b: int64): int64 =
  61. system.`+`(a, b)
  62. {.pop.}
  63. elif defined(posix) and not defined(osx):
  64. import std/posix
  65. when defined(zephyr):
  66. proc k_uptime_ticks(): int64 {.importc: "k_uptime_ticks", header: "<kernel.h>".}
  67. proc k_ticks_to_ns_floor64(ticks: int64): int64 {.importc: "k_ticks_to_ns_floor64", header: "<kernel.h>".}
  68. elif defined(windows):
  69. proc QueryPerformanceCounter(res: var uint64) {.
  70. importc: "QueryPerformanceCounter", stdcall, dynlib: "kernel32".}
  71. proc QueryPerformanceFrequency(res: var uint64) {.
  72. importc: "QueryPerformanceFrequency", stdcall, dynlib: "kernel32".}
  73. proc getMonoTime*(): MonoTime {.tags: [TimeEffect].} =
  74. ## Returns the current `MonoTime` timestamp.
  75. ##
  76. ## When compiled with the JS backend and executed in a browser,
  77. ## this proc calls `window.performance.now()`.
  78. ## See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Performance/now)
  79. ## for more information.
  80. when defined(js):
  81. let ticks = getJsTicks()
  82. result = MonoTime(ticks: (ticks * 1_000_000_000).int64)
  83. elif defined(macosx):
  84. let ticks = mach_absolute_time()
  85. var machAbsoluteTimeFreq: MachTimebaseInfoData
  86. mach_timebase_info(machAbsoluteTimeFreq)
  87. result = MonoTime(ticks: ticks * machAbsoluteTimeFreq.numer div
  88. machAbsoluteTimeFreq.denom)
  89. elif defined(zephyr):
  90. let ticks = k_ticks_to_ns_floor64(k_uptime_ticks())
  91. result = MonoTime(ticks: ticks)
  92. elif defined(posix):
  93. var ts: Timespec
  94. discard clock_gettime(CLOCK_MONOTONIC, ts)
  95. result = MonoTime(ticks: ts.tv_sec.int64 * 1_000_000_000 +
  96. ts.tv_nsec.int64)
  97. elif defined(windows):
  98. var ticks: uint64
  99. QueryPerformanceCounter(ticks)
  100. var freq: uint64
  101. QueryPerformanceFrequency(freq)
  102. let queryPerformanceCounterFreq = 1_000_000_000'u64 div freq
  103. result = MonoTime(ticks: (ticks * queryPerformanceCounterFreq).int64)
  104. proc ticks*(t: MonoTime): int64 =
  105. ## Returns the raw ticks value from a `MonoTime`. This value always uses
  106. ## nanosecond time resolution.
  107. t.ticks
  108. proc `$`*(t: MonoTime): string =
  109. $t.ticks
  110. proc `-`*(a, b: MonoTime): Duration =
  111. ## Returns the difference between two `MonoTime` timestamps as a `Duration`.
  112. initDuration(nanoseconds = (a.ticks - b.ticks))
  113. proc `+`*(a: MonoTime, b: Duration): MonoTime =
  114. ## Increases `a` by `b`.
  115. MonoTime(ticks: a.ticks + b.inNanoseconds)
  116. proc `-`*(a: MonoTime, b: Duration): MonoTime =
  117. ## Reduces `a` by `b`.
  118. MonoTime(ticks: a.ticks - b.inNanoseconds)
  119. proc `<`*(a, b: MonoTime): bool =
  120. ## Returns true if `a` happened before `b`.
  121. a.ticks < b.ticks
  122. proc `<=`*(a, b: MonoTime): bool =
  123. ## Returns true if `a` happened before `b` or if they happened simultaneous.
  124. a.ticks <= b.ticks
  125. proc `==`*(a, b: MonoTime): bool =
  126. ## Returns true if `a` and `b` happened simultaneous.
  127. a.ticks == b.ticks
  128. proc high*(typ: typedesc[MonoTime]): MonoTime =
  129. ## Returns the highest representable `MonoTime`.
  130. MonoTime(ticks: high(int64))
  131. proc low*(typ: typedesc[MonoTime]): MonoTime =
  132. ## Returns the lowest representable `MonoTime`.
  133. MonoTime(ticks: low(int64))