_clock_implementations.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. # Copyright (c) "Neo4j"
  2. # Neo4j Sweden AB [https://neo4j.com]
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # https://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. import time
  16. from ctypes import (
  17. byref,
  18. c_long,
  19. c_longlong,
  20. CDLL,
  21. Structure,
  22. )
  23. from platform import uname
  24. from . import (
  25. Clock,
  26. ClockTime,
  27. )
  28. from ._arithmetic import nano_divmod
  29. __all__ = [
  30. "LibCClock",
  31. "PEP564Clock",
  32. "SafeClock",
  33. ]
  34. class SafeClock(Clock):
  35. """
  36. Clock implementation that should work for any variant of Python.
  37. This clock is guaranteed microsecond precision.
  38. """
  39. @classmethod
  40. def precision(cls):
  41. return 6
  42. @classmethod
  43. def available(cls):
  44. return True
  45. def utc_time(self):
  46. seconds, nanoseconds = nano_divmod(int(time.time() * 1000000), 1000000)
  47. return ClockTime(seconds, nanoseconds * 1000)
  48. class PEP564Clock(Clock):
  49. """
  50. Clock implementation based on the PEP564 additions to Python 3.7.
  51. This clock is guaranteed nanosecond precision.
  52. """
  53. @classmethod
  54. def precision(cls):
  55. return 9
  56. @classmethod
  57. def available(cls):
  58. return hasattr(time, "time_ns")
  59. def utc_time(self):
  60. t = time.time_ns()
  61. seconds, nanoseconds = divmod(t, 1000000000)
  62. return ClockTime(seconds, nanoseconds)
  63. class LibCClock(Clock):
  64. """
  65. Clock implementation backed by libc.
  66. Only works on platforms that provide libc.
  67. This clock is guaranteed nanosecond precision.
  68. """
  69. __libc = "libc.dylib" if uname()[0] == "Darwin" else "libc.so.6"
  70. class _TimeSpec(Structure):
  71. _fields_ = (
  72. ("seconds", c_longlong),
  73. ("nanoseconds", c_long),
  74. )
  75. @classmethod
  76. def precision(cls):
  77. return 9
  78. @classmethod
  79. def available(cls):
  80. try:
  81. _ = CDLL(cls.__libc)
  82. except OSError:
  83. return False
  84. else:
  85. return True
  86. def utc_time(self):
  87. libc = CDLL(self.__libc)
  88. ts = self._TimeSpec()
  89. status = libc.clock_gettime(0, byref(ts))
  90. if status == 0:
  91. return ClockTime(ts.seconds, ts.nanoseconds)
  92. else:
  93. raise RuntimeError(f"clock_gettime failed with status {status}")