1""" 2from: https://bitbucket.org/haypo/misc/src/tip/python/pep418.py 3 4Implementation of the PEP 418 in pure Python using ctypes. 5 6Functions: 7 8 - clock() 9 - get_clock_info(name) 10 - monotonic(): not always available 11 - perf_frequency() 12 - process_time() 13 - sleep() 14 - time() 15 16Constants: 17 18 - has_monotonic (bool): True if time.monotonic() is available 19""" 20# flake8: noqa 21# TODO: gethrtime() for Solaris/OpenIndiana 22# TODO: call GetSystemTimeAdjustment() to get the resolution 23# TODO: other FIXME 24 25import os 26import sys 27import time as python_time 28 29has_mach_absolute_time = False 30has_clock_gettime = False 31has_gettimeofday = False 32has_ftime = False 33has_delay = False 34has_libc_time = False 35has_libc_clock = False 36has_libc_sleep = False 37has_GetTickCount64 = False 38CLOCK_REALTIME = None 39CLOCK_MONOTONIC = None 40CLOCK_PROCESS_CPUTIME_ID = None 41CLOCK_HIGHRES = None 42CLOCK_PROF = None 43try: 44 import ctypes 45 import ctypes.util 46 from ctypes import POINTER 47 from ctypes import byref 48except ImportError as err: 49 pass 50else: 51 def ctypes_oserror(): 52 errno = ctypes.get_errno() 53 message = os.strerror(errno) 54 return OSError(errno, message) 55 56 time_t = ctypes.c_long 57 58 if os.name == "nt": 59 from ctypes import windll 60 from ctypes.wintypes import BOOL 61 from ctypes.wintypes import DWORD 62 from ctypes.wintypes import FILETIME 63 from ctypes.wintypes import HANDLE 64 LARGEINTEGER = ctypes.c_int64 65 LARGEINTEGER_p = POINTER(LARGEINTEGER) 66 FILETIME_p = POINTER(FILETIME) 67 ULONGLONG = ctypes.c_uint64 68 69 def ctypes_winerror(): 70 errno = ctypes.get_errno() 71 message = os.strerror(errno) 72 return WindowsError(errno, message) 73 74 _QueryPerformanceFrequency = windll.kernel32.QueryPerformanceFrequency 75 _QueryPerformanceFrequency.restype = BOOL 76 _QueryPerformanceFrequency.argtypes = (LARGEINTEGER_p,) 77 def QueryPerformanceFrequency(): 78 frequency = LARGEINTEGER() 79 ok = _QueryPerformanceFrequency(byref(frequency)) 80 if not ok: 81 raise ctypes_winerror() 82 return int(frequency.value) 83 84 _QueryPerformanceCounter = windll.kernel32.QueryPerformanceCounter 85 _QueryPerformanceCounter.restype = BOOL 86 _QueryPerformanceCounter.argtypes = (LARGEINTEGER_p,) 87 def QueryPerformanceCounter(): 88 frequency = LARGEINTEGER() 89 ok = _QueryPerformanceCounter(byref(frequency)) 90 if not ok: 91 raise ctypes_winerror() 92 return int(frequency.value) 93 94 GetTickCount = windll.kernel32.GetTickCount 95 GetTickCount.restype = DWORD 96 GetTickCount.argtypes = () 97 98 if hasattr(windll.kernel32, 'GetTickCount64'): 99 GetTickCount64 = windll.kernel32.GetTickCount64 100 GetTickCount64.restype = ULONGLONG 101 GetTickCount64.argtypes = () 102 has_GetTickCount64 = True 103 104 GetCurrentProcess = windll.kernel32.GetCurrentProcess 105 GetCurrentProcess.argtypes = () 106 GetCurrentProcess.restype = HANDLE 107 108 _GetProcessTimes = windll.kernel32.GetProcessTimes 109 _GetProcessTimes.argtypes = (HANDLE, FILETIME_p, FILETIME_p, FILETIME_p, FILETIME_p) 110 _GetProcessTimes.restype = BOOL 111 112 def filetime2py(obj): 113 return (obj.dwHighDateTime << 32) + obj.dwLowDateTime 114 115 def GetProcessTimes(handle): 116 creation_time = FILETIME() 117 exit_time = FILETIME() 118 kernel_time = FILETIME() 119 user_time = FILETIME() 120 ok = _GetProcessTimes(handle, 121 byref(creation_time), byref(exit_time), 122 byref(kernel_time), byref(user_time)) 123 if not ok: 124 raise ctypes_winerror() 125 return (filetime2py(creation_time), filetime2py(exit_time), 126 filetime2py(kernel_time), filetime2py(user_time)) 127 128 _GetSystemTimeAsFileTime = windll.kernel32.GetSystemTimeAsFileTime 129 _GetSystemTimeAsFileTime.argtypes = (FILETIME_p,) 130 _GetSystemTimeAsFileTime.restype = None 131 132 def GetSystemTimeAsFileTime(): 133 system_time = FILETIME() 134 _GetSystemTimeAsFileTime(byref(system_time)) 135 return filetime2py(system_time) 136 137 libc_name = ctypes.util.find_library('c') 138 if libc_name: 139 libc = ctypes.CDLL(libc_name, use_errno=True) 140 clock_t = ctypes.c_ulong 141 142 if sys.platform == 'darwin': 143 mach_absolute_time = libc.mach_absolute_time 144 mach_absolute_time.argtypes = () 145 mach_absolute_time.restype = ctypes.c_uint64 146 has_mach_absolute_time = True 147 148 class mach_timebase_info_data_t(ctypes.Structure): 149 _fields_ = ( 150 ('numer', ctypes.c_uint32), 151 ('denom', ctypes.c_uint32), 152 ) 153 mach_timebase_info_data_p = POINTER(mach_timebase_info_data_t) 154 155 _mach_timebase_info = libc.mach_timebase_info 156 _mach_timebase_info.argtypes = (mach_timebase_info_data_p,) 157 _mach_timebase_info.restype = ctypes.c_int 158 def mach_timebase_info(): 159 timebase = mach_timebase_info_data_t() 160 _mach_timebase_info(byref(timebase)) 161 return (timebase.numer, timebase.denom) 162 163 _libc_clock = libc.clock 164 _libc_clock.argtypes = () 165 _libc_clock.restype = clock_t 166 has_libc_clock = True 167 168 if hasattr(libc, 'sleep'): 169 _libc_sleep = libc.sleep 170 _libc_sleep.argtypes = (ctypes.c_uint,) 171 _libc_sleep.restype = ctypes.c_uint 172 has_libc_sleep = True 173 174 if hasattr(libc, 'gettimeofday'): 175 class timeval(ctypes.Structure): 176 _fields_ = ( 177 ('tv_sec', time_t), 178 ('tv_usec', ctypes.c_long), 179 ) 180 timeval_p = POINTER(timeval) 181 timezone_p = ctypes.c_void_p 182 183 _gettimeofday = libc.gettimeofday 184 # FIXME: some platforms only expect one argument 185 _gettimeofday.argtypes = (timeval_p, timezone_p) 186 _gettimeofday.restype = ctypes.c_int 187 def gettimeofday(): 188 tv = timeval() 189 err = _gettimeofday(byref(tv), None) 190 if err: 191 raise ctypes_oserror() 192 return tv 193 has_gettimeofday = True 194 195 time_t_p = POINTER(time_t) 196 if hasattr(libc, 'time'): 197 _libc__time = libc.time 198 _libc__time.argtypes = (time_t_p,) 199 _libc__time.restype = time_t 200 def _libc_time(): 201 return _libc__time(None) 202 has_libc_time = True 203 204 if sys.platform.startswith(("freebsd", "openbsd")): 205 librt_name = libc_name 206 else: 207 librt_name = ctypes.util.find_library('rt') 208 if librt_name: 209 librt = ctypes.CDLL(librt_name, use_errno=True) 210 if hasattr(librt, 'clock_gettime'): 211 clockid_t = ctypes.c_int 212 class timespec(ctypes.Structure): 213 _fields_ = ( 214 ('tv_sec', time_t), 215 ('tv_nsec', ctypes.c_long), 216 ) 217 timespec_p = POINTER(timespec) 218 219 _clock_gettime = librt.clock_gettime 220 _clock_gettime.argtypes = (clockid_t, timespec_p) 221 _clock_gettime.restype = ctypes.c_int 222 def clock_gettime(clk_id): 223 ts = timespec() 224 err = _clock_gettime(clk_id, byref(ts)) 225 if err: 226 raise ctypes_oserror() 227 return ts.tv_sec + ts.tv_nsec * 1e-9 228 has_clock_gettime = True 229 230 _clock_settime = librt.clock_settime 231 _clock_settime.argtypes = (clockid_t, timespec_p) 232 _clock_settime.restype = ctypes.c_int 233 def clock_settime(clk_id, value): 234 ts = timespec() 235 ts.tv_sec = int(value) 236 ts.tv_nsec = int(float(abs(value)) % 1.0 * 1e9) 237 err = _clock_settime(clk_id, byref(ts)) 238 if err: 239 raise ctypes_oserror() 240 return ts.tv_sec + ts.tv_nsec * 1e-9 241 242 _clock_getres = librt.clock_getres 243 _clock_getres.argtypes = (clockid_t, timespec_p) 244 _clock_getres.restype = ctypes.c_int 245 def clock_getres(clk_id): 246 ts = timespec() 247 err = _clock_getres(clk_id, byref(ts)) 248 if err: 249 raise ctypes_oserror() 250 return ts.tv_sec + ts.tv_nsec * 1e-9 251 252 if sys.platform.startswith("linux"): 253 CLOCK_REALTIME = 0 254 CLOCK_MONOTONIC = 1 255 CLOCK_PROCESS_CPUTIME_ID = 2 256 elif sys.platform.startswith("freebsd"): 257 CLOCK_REALTIME = 0 258 CLOCK_PROF = 2 259 CLOCK_MONOTONIC = 4 260 elif sys.platform.startswith("openbsd"): 261 CLOCK_REALTIME = 0 262 CLOCK_MONOTONIC = 3 263 elif sys.platform.startswith("sunos"): 264 CLOCK_REALTIME = 3 265 CLOCK_HIGHRES = 4 266 # clock_gettime(CLOCK_PROCESS_CPUTIME_ID) fails with errno 22 267 # on OpenSolaris 268 # CLOCK_PROCESS_CPUTIME_ID = 5 269 270def _clock_gettime_info(use_info, clk_id): 271 value = clock_gettime(clk_id) 272 if use_info: 273 name = { 274 CLOCK_MONOTONIC: 'CLOCK_MONOTONIC', 275 CLOCK_PROF: 'CLOCK_PROF', 276 CLOCK_HIGHRES: 'CLOCK_HIGHRES', 277 CLOCK_PROCESS_CPUTIME_ID: 'CLOCK_PROCESS_CPUTIME_ID', 278 CLOCK_REALTIME: 'CLOCK_REALTIME', 279 }[clk_id] 280 try: 281 resolution = clock_getres(clk_id) 282 except OSError: 283 resolution = 1e-9 284 info = { 285 'implementation': 'clock_gettime(%s)' % name, 286 'resolution': resolution, 287 } 288 if clk_id in (CLOCK_MONOTONIC, CLOCK_PROF, CLOCK_HIGHRES, CLOCK_PROCESS_CPUTIME_ID): 289 info['monotonic'] = True 290 info['adjustable'] = False 291 elif clk_id in (CLOCK_REALTIME,): 292 info['monotonic'] = False 293 info['adjustable'] = True 294 else: 295 info = None 296 return (value, info) 297 298has_monotonic = False 299if os.name == 'nt': 300 # GetTickCount64() requires Windows Vista, Server 2008 or later 301 if has_GetTickCount64: 302 def _monotonic(use_info): 303 value = GetTickCount64() * 1e-3 304 if use_info: 305 info = { 306 'implementation': "GetTickCount64()", 307 "monotonic": True, 308 "resolution": 1e-3, 309 "adjustable": False, 310 } 311 # FIXME: call GetSystemTimeAdjustment() to get the resolution 312 else: 313 info = None 314 return (value, info) 315 has_monotonic = True 316 else: 317 def _monotonic(use_info): 318 ticks = GetTickCount() 319 if ticks < _monotonic.last: 320 # Integer overflow detected 321 _monotonic.delta += 2**32 322 _monotonic.last = ticks 323 value = (ticks + _monotonic.delta) * 1e-3 324 325 if use_info: 326 info = { 327 'implementation': "GetTickCount()", 328 "monotonic": True, 329 "resolution": 1e-3, 330 "adjustable": False, 331 } 332 # FIXME: call GetSystemTimeAdjustment() to get the resolution 333 else: 334 info = None 335 return (value, info) 336 _monotonic.last = 0 337 _monotonic.delta = 0 338 has_monotonic = True 339 340elif has_mach_absolute_time: 341 def _monotonic(use_info): 342 if _monotonic.factor is None: 343 timebase = mach_timebase_info() 344 _monotonic.factor = timebase[0] / timebase[1] * 1e-9 345 value = mach_absolute_time() * _monotonic.factor 346 if use_info: 347 info = { 348 'implementation': "mach_absolute_time()", 349 'resolution': _monotonic.factor, 350 'monotonic': True, 351 'adjustable': False, 352 } 353 else: 354 info = None 355 return (value, info) 356 _monotonic.factor = None 357 has_monotonic = True 358 359elif has_clock_gettime and CLOCK_HIGHRES is not None: 360 def _monotonic(use_info): 361 return _clock_gettime_info(use_info, CLOCK_HIGHRES) 362 has_monotonic = True 363 364elif has_clock_gettime and CLOCK_MONOTONIC is not None: 365 def _monotonic(use_info): 366 return _clock_gettime_info(use_info, CLOCK_MONOTONIC) 367 has_monotonic = True 368 369if has_monotonic: 370 def monotonic(): 371 return _monotonic(False)[0] 372 373 374def _perf_counter(use_info): 375 info = None 376 if _perf_counter.use_performance_counter: 377 if _perf_counter.performance_frequency is None: 378 value, info = _win_perf_counter(use_info) 379 if value is not None: 380 return (value, info) 381 if _perf_counter.use_monotonic: 382 # The monotonic clock is preferred over the system time 383 try: 384 return _monotonic(use_info) 385 except (OSError, WindowsError): 386 _perf_counter.use_monotonic = False 387 return _time(use_info) 388_perf_counter.use_performance_counter = (os.name == 'nt') 389if _perf_counter.use_performance_counter: 390 _perf_counter.performance_frequency = None 391_perf_counter.use_monotonic = has_monotonic 392 393def perf_counter(): 394 return _perf_counter(False)[0] 395 396 397if os.name == 'nt': 398 def _process_time(use_info): 399 handle = GetCurrentProcess() 400 process_times = GetProcessTimes(handle) 401 value = (process_times[2] + process_times[3]) * 1e-7 402 if use_info: 403 info = { 404 "implementation": "GetProcessTimes()", 405 "resolution": 1e-7, 406 "monotonic": True, 407 "adjustable": False, 408 # FIXME: call GetSystemTimeAdjustment() to get the resolution 409 } 410 else: 411 info = None 412 return (value, info) 413else: 414 import os 415 try: 416 import resource 417 except ImportError: 418 has_resource = False 419 else: 420 has_resource = True 421 422 def _process_time(use_info): 423 info = None 424 if _process_time.clock_id is not None: 425 try: 426 return _clock_gettime_info(use_info, _process_time.clock_id) 427 except OSError: 428 _process_time.clock_id = None 429 if _process_time.use_getrusage: 430 try: 431 usage = resource.getrusage(resource.RUSAGE_SELF) 432 value = usage[0] + usage[1] 433 except OSError: 434 _process_time.use_getrusage = False 435 else: 436 if use_info: 437 info = { 438 "implementation": "getrusage(RUSAGE_SELF)", 439 "resolution": 1e-6, 440 "monotonic": True, 441 "adjustable": False, 442 } 443 return (value, info) 444 if _process_time.use_times: 445 try: 446 times = os.times() 447 value = times[0] + times[1] 448 except OSError: 449 _process_time.use_getrusage = False 450 else: 451 if use_info: 452 try: 453 ticks_per_second = os.sysconf("SC_CLK_TCK") 454 except ValueError: 455 ticks_per_second = 60 # FIXME: get HZ constant 456 info = { 457 "implementation": "times()", 458 "resolution": 1.0 / ticks_per_second, 459 "monotonic": True, 460 "adjustable": False, 461 } 462 return (value, info) 463 return _libc_clock_info(use_info) 464 if has_clock_gettime and CLOCK_PROCESS_CPUTIME_ID is not None: 465 _process_time.clock_id = CLOCK_PROCESS_CPUTIME_ID 466 elif has_clock_gettime and CLOCK_PROF is not None: 467 _process_time.clock_id = CLOCK_PROF 468 else: 469 _process_time.clock_id = None 470 _process_time.use_getrusage = has_resource 471 # On OS/2, only the 5th field of os.times() is set, others are zeros 472 _process_time.use_times = (hasattr(os, 'times') and os.name != 'os2') 473 474def process_time(): 475 return _process_time(False)[0] 476 477 478if os.name == "nt": 479 def _time(use_info): 480 value = GetSystemTimeAsFileTime() * 1e-7 481 if use_info: 482 info = { 483 'implementation': 'GetSystemTimeAsFileTime', 484 'resolution': 1e-7, 485 'monotonic': False, 486 # FIXME: call GetSystemTimeAdjustment() to get the resolution 487 # and adjustable 488 } 489 else: 490 info = None 491 return (value, info) 492else: 493 def _time(use_info): 494 info = None 495 if has_clock_gettime and CLOCK_REALTIME is not None: 496 try: 497 return _clock_gettime_info(use_info, CLOCK_REALTIME) 498 except OSError: 499 # CLOCK_REALTIME is not supported (unlikely) 500 pass 501 if has_gettimeofday: 502 try: 503 tv = gettimeofday() 504 except OSError: 505 # gettimeofday() should not fail 506 pass 507 else: 508 if use_info: 509 info = { 510 'monotonic': False, 511 "implementation": "gettimeofday()", 512 "resolution": 1e-6, 513 'monotonic': False, 514 'adjustable': True, 515 } 516 value = tv.tv_sec + tv.tv_usec * 1e-6 517 return (value, info) 518 # FIXME: implement ftime() 519 if has_ftime: 520 if use_info: 521 info = { 522 "implementation": "ftime()", 523 "resolution": 1e-3, 524 'monotonic': False, 525 'adjustable': True, 526 } 527 value = ftime() 528 elif has_libc_time: 529 if use_info: 530 info = { 531 "implementation": "time()", 532 "resolution": 1.0, 533 'monotonic': False, 534 'adjustable': True, 535 } 536 value = float(_libc_time()) 537 else: 538 if use_info: 539 info = { 540 "implementation": "time.time()", 541 'monotonic': False, 542 'adjustable': True, 543 } 544 if os.name == "nt": 545 # On Windows, time.time() uses ftime() 546 info["resolution"] = 1e-3 547 else: 548 # guess that time.time() uses gettimeofday() 549 info["resolution"] = 1e-6 550 value = python_time.time() 551 return (value, info) 552 553def time(): 554 return _time(False)[0] 555 556 557try: 558 import select 559except ImportError: 560 has_select = False 561else: 562 # FIXME: On Windows, select.select([], [], [], seconds) fails with 563 # select.error(10093) 564 has_select = (hasattr(select, "select") and os.name != "nt") 565 566if has_select: 567 def _sleep(seconds): 568 return select.select([], [], [], seconds) 569 570elif has_delay: 571 def _sleep(seconds): 572 milliseconds = int(seconds * 1000) 573 # FIXME 574 delay(milliseconds) 575 576#elif os.name == "nt": 577# def _sleep(seconds): 578# milliseconds = int(seconds * 1000) 579# # FIXME: use ctypes 580# win32api.ResetEvent(hInterruptEvent); 581# win32api.WaitForSingleObject(sleep.sigint_event, milliseconds) 582# 583# sleep.sigint_event = win32api.CreateEvent(NULL, TRUE, FALSE, FALSE) 584# # SetEvent(sleep.sigint_event) will be called by the signal handler of SIGINT 585 586elif os.name == "os2": 587 def _sleep(seconds): 588 milliseconds = int(seconds * 1000) 589 # FIXME 590 DosSleep(milliseconds) 591 592elif has_libc_sleep: 593 def _sleep(seconds): 594 seconds = int(seconds) 595 _libc_sleep(seconds) 596 597else: 598 def _sleep(seconds): 599 python_time.sleep(seconds) 600 601def sleep(seconds): 602 if seconds < 0: 603 raise ValueError("sleep length must be non-negative") 604 _sleep(seconds) 605 606def _libc_clock_info(use_info): 607 if use_info: 608 info = { 609 'implementation': 'clock()', 610 'resolution': 1.0, 611 # FIXME: 'resolution': 1.0 / CLOCKS_PER_SEC, 612 'monotonic': True, 613 'adjustable': False, 614 } 615 if os.name != "nt": 616 info['monotonic'] = True 617 else: 618 info = None 619 if has_libc_clock: 620 value = _libc_clock() 621 if use_info: 622 info['implementation'] = 'clock()' 623 else: 624 value = python_time.clock() 625 if use_info: 626 info['implementation'] = 'time.clock()' 627 return (value, info) 628 629def _win_perf_counter(use_info): 630 if _win_perf_counter.perf_frequency is None: 631 try: 632 _win_perf_counter.perf_frequency = float(QueryPerformanceFrequency()) 633 except WindowsError: 634 # QueryPerformanceFrequency() fails if the installed 635 # hardware does not support a high-resolution performance 636 # counter 637 return (None, None) 638 639 value = QueryPerformanceCounter() / _win_perf_counter.perf_frequency 640 if use_info: 641 info = { 642 'implementation': 'QueryPerformanceCounter', 643 'resolution': 1.0 / _win_perf_counter.perf_frequency, 644 'monotonic': True, 645 'adjustable': False, 646 } 647 else: 648 info = None 649 return (value, info) 650_win_perf_counter.perf_frequency = None 651 652if os.name == 'nt': 653 def _clock(use_info): 654 info = None 655 if _clock.use_performance_counter: 656 value, info = _win_perf_counter(use_info) 657 if value is not None: 658 return (value, info) 659 return _libc_clock_info(use_info) 660 _clock.use_performance_counter = True 661else: 662 def _clock(use_info): 663 return _libc_clock_info(use_info) 664 665def clock(): 666 return _clock(False)[0] 667 668 669class clock_info(object): 670 def __init__(self, implementation, monotonic, adjustable, resolution): 671 self.implementation = implementation 672 self.monotonic = monotonic 673 self.adjustable = adjustable 674 self.resolution = resolution 675 676 def __repr__(self): 677 return ( 678 'clockinfo(adjustable=%s, implementation=%r, monotonic=%s, resolution=%s' 679 % (self.adjustable, self.implementation, self.monotonic, self.resolution)) 680 681def get_clock_info(name): 682 if name == 'clock': 683 info = _clock(True)[1] 684 elif name == 'perf_counter': 685 info = _perf_counter(True)[1] 686 elif name == 'process_time': 687 info = _process_time(True)[1] 688 elif name == 'time': 689 info = _time(True)[1] 690 elif has_monotonic and name == 'monotonic': 691 info = _monotonic(True)[1] 692 else: 693 raise ValueError("unknown clock: %s" % name) 694 return clock_info(**info) 695 696if __name__ == "__main__": 697 import threading 698 import unittest 699 from errno import EPERM 700 701 class TestPEP418(unittest.TestCase): 702 if not hasattr(unittest.TestCase, 'assertIsInstance'): 703 # Python < 2.7 or Python < 3.2 704 def assertIsInstance(self, obj, klass): 705 self.assertTrue(isinstance(obj, klass)) 706 def assertGreater(self, a, b): 707 self.assertTrue(a > b) 708 def assertLess(self, a, b): 709 self.assertTrue(a < b) 710 def assertLessEqual(self, a, b): 711 self.assertTrue(a <= b) 712 def assertAlmostEqual(self, first, second, delta): 713 self.assertTrue(abs(first - second) <= delta) 714 715 def test_clock(self): 716 clock() 717 718 info = get_clock_info('clock') 719 self.assertEqual(info.monotonic, True) 720 self.assertEqual(info.adjustable, False) 721 722 def test_get_clock_info(self): 723 clocks = ['clock', 'perf_counter', 'process_time', 'time'] 724 if has_monotonic: 725 clocks.append('monotonic') 726 727 for name in clocks: 728 info = get_clock_info(name) 729 self.assertIsInstance(info.implementation, str) 730 self.assertNotEqual(info.implementation, '') 731 self.assertIsInstance(info.monotonic, bool) 732 self.assertIsInstance(info.resolution, float) 733 # 0 < resolution <= 1.0 734 self.assertGreater(info.resolution, 0) 735 self.assertLessEqual(info.resolution, 1) 736 self.assertIsInstance(info.adjustable, bool) 737 738 self.assertRaises(ValueError, get_clock_info, 'xxx') 739 740 if not has_monotonic: 741 print("Skip test_monotonic: need time.monotonic") 742 else: 743 def test_monotonic(self): 744 t1 = monotonic() 745 python_time.sleep(0.1) 746 t2 = monotonic() 747 dt = t2 - t1 748 self.assertGreater(t2, t1) 749 self.assertAlmostEqual(dt, 0.1, delta=0.2) 750 751 info = get_clock_info('monotonic') 752 self.assertEqual(info.monotonic, True) 753 self.assertEqual(info.adjustable, False) 754 755 if not has_monotonic or not has_clock_gettime: 756 if not has_monotonic: 757 print('Skip test_monotonic_settime: need time.monotonic') 758 elif not has_clock_gettime: 759 print('Skip test_monotonic_settime: need time.clock_settime') 760 else: 761 def test_monotonic_settime(self): 762 t1 = monotonic() 763 realtime = clock_gettime(CLOCK_REALTIME) 764 # jump backward with an offset of 1 hour 765 try: 766 clock_settime(CLOCK_REALTIME, realtime - 3600) 767 except OSError as err: 768 if err.errno == EPERM: 769 if hasattr(unittest, 'SkipTest'): 770 raise unittest.SkipTest(str(err)) 771 else: 772 print("Skip test_monotonic_settime: %s" % err) 773 return 774 else: 775 raise 776 t2 = monotonic() 777 clock_settime(CLOCK_REALTIME, realtime) 778 # monotonic must not be affected by system clock updates 779 self.assertGreaterEqual(t2, t1) 780 781 def test_perf_counter(self): 782 perf_counter() 783 784 def test_process_time(self): 785 start = process_time() 786 python_time.sleep(0.1) 787 stop = process_time() 788 self.assertLess(stop - start, 0.01) 789 790 info = get_clock_info('process_time') 791 self.assertEqual(info.monotonic, True) 792 self.assertEqual(info.adjustable, False) 793 794 795 def test_process_time_threads(self): 796 class BusyThread(threading.Thread): 797 def run(self): 798 while not self.stop: 799 pass 800 801 thread = BusyThread() 802 thread.stop = False 803 t1 = process_time() 804 thread.start() 805 sleep(0.2) 806 t2 = process_time() 807 thread.stop = True 808 thread.join() 809 self.assertGreater(t2 - t1, 0.1) 810 811 def test_sleep(self): 812 self.assertRaises(ValueError, sleep, -2) 813 self.assertRaises(ValueError, sleep, -1) 814 sleep(1.2) 815 816 def test_time(self): 817 value = time() 818 self.assertIsInstance(value, float) 819 820 info = get_clock_info('time') 821 self.assertEqual(info.monotonic, False) 822 self.assertEqual(info.adjustable, True) 823 824 825 if True: 826 from pprint import pprint 827 828 print("clock: %s" % clock()) 829 if has_monotonic: 830 print("monotonic: %s" % monotonic()) 831 else: 832 print("monotonic: <not available>") 833 print("perf_counter: %s" % perf_counter()) 834 print("process_time: %s" % process_time()) 835 print("time: %s" % time()) 836 837 clocks = ['clock', 'perf_counter', 'process_time', 'time'] 838 if has_monotonic: 839 clocks.append('monotonic') 840 pprint(dict((name, get_clock_info(name)) for name in clocks)) 841 842 unittest.main() 843