PageRenderTime 47ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/rpython/rlib/rtime.py

https://bitbucket.org/pypy/pypy/
Python | 236 lines | 194 code | 30 blank | 12 comment | 42 complexity | c994ccf63954d851f3558771c25a0c70 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. """
  2. RPython implementations of time.time(), time.clock(), time.select().
  3. """
  4. import sys
  5. import math
  6. import time as pytime
  7. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  8. from rpython.rtyper.tool import rffi_platform
  9. from rpython.rtyper.lltypesystem import rffi, lltype
  10. from rpython.rlib.objectmodel import register_replacement_for
  11. from rpython.rlib.rarithmetic import intmask, UINT_MAX
  12. from rpython.rlib import rposix
  13. _WIN32 = sys.platform.startswith('win')
  14. if _WIN32:
  15. TIME_H = 'time.h'
  16. FTIME = '_ftime64'
  17. STRUCT_TIMEB = 'struct __timeb64'
  18. includes = ['winsock2.h', 'windows.h',
  19. TIME_H, 'sys/types.h', 'sys/timeb.h']
  20. need_rusage = False
  21. else:
  22. TIME_H = 'sys/time.h'
  23. FTIME = 'ftime'
  24. STRUCT_TIMEB = 'struct timeb'
  25. includes = [TIME_H, 'time.h', 'errno.h', 'sys/select.h',
  26. 'sys/types.h', 'unistd.h',
  27. 'sys/time.h', 'sys/resource.h']
  28. if not sys.platform.startswith("openbsd"):
  29. includes.append('sys/timeb.h')
  30. need_rusage = True
  31. eci = ExternalCompilationInfo(includes=includes)
  32. class CConfig:
  33. _compilation_info_ = eci
  34. TIMEVAL = rffi_platform.Struct('struct timeval', [('tv_sec', rffi.INT),
  35. ('tv_usec', rffi.INT)])
  36. HAVE_GETTIMEOFDAY = rffi_platform.Has('gettimeofday')
  37. HAVE_FTIME = rffi_platform.Has(FTIME)
  38. if need_rusage:
  39. RUSAGE = rffi_platform.Struct('struct rusage', [('ru_utime', TIMEVAL),
  40. ('ru_stime', TIMEVAL)])
  41. if sys.platform.startswith('freebsd') or sys.platform.startswith('netbsd'):
  42. libraries = ['compat']
  43. elif sys.platform == 'linux2':
  44. libraries = ['rt']
  45. else:
  46. libraries = []
  47. class CConfigForFTime:
  48. _compilation_info_ = ExternalCompilationInfo(
  49. includes=[TIME_H, 'sys/timeb.h'],
  50. libraries=libraries
  51. )
  52. TIMEB = rffi_platform.Struct(STRUCT_TIMEB, [('time', rffi.INT),
  53. ('millitm', rffi.INT)])
  54. class CConfigForClockGetTime:
  55. _compilation_info_ = ExternalCompilationInfo(
  56. includes=['time.h'],
  57. libraries=libraries
  58. )
  59. TIMESPEC = rffi_platform.Struct('struct timespec', [('tv_sec', rffi.LONG),
  60. ('tv_nsec', rffi.LONG)])
  61. constant_names = ['RUSAGE_SELF', 'EINTR', 'CLOCK_PROCESS_CPUTIME_ID']
  62. for const in constant_names:
  63. setattr(CConfig, const, rffi_platform.DefinedConstantInteger(const))
  64. defs_names = ['GETTIMEOFDAY_NO_TZ']
  65. for const in defs_names:
  66. setattr(CConfig, const, rffi_platform.Defined(const))
  67. def decode_timeval(t):
  68. return (float(rffi.getintfield(t, 'c_tv_sec')) +
  69. float(rffi.getintfield(t, 'c_tv_usec')) * 0.000001)
  70. def external(name, args, result, compilation_info=eci, **kwds):
  71. return rffi.llexternal(name, args, result,
  72. compilation_info=compilation_info, **kwds)
  73. def replace_time_function(name):
  74. func = getattr(pytime, name, None)
  75. if func is None:
  76. return lambda f: f
  77. return register_replacement_for(
  78. func,
  79. sandboxed_name='ll_time.ll_time_%s' % name)
  80. config = rffi_platform.configure(CConfig)
  81. globals().update(config)
  82. # Note: time.time() is used by the framework GC during collect(),
  83. # which means that we have to be very careful about not allocating
  84. # GC memory here. This is the reason for the _nowrapper=True.
  85. if HAVE_GETTIMEOFDAY:
  86. if GETTIMEOFDAY_NO_TZ:
  87. c_gettimeofday = external('gettimeofday',
  88. [lltype.Ptr(TIMEVAL)], rffi.INT,
  89. _nowrapper=True, releasegil=False)
  90. else:
  91. c_gettimeofday = external('gettimeofday',
  92. [lltype.Ptr(TIMEVAL), rffi.VOIDP], rffi.INT,
  93. _nowrapper=True, releasegil=False)
  94. if HAVE_FTIME:
  95. globals().update(rffi_platform.configure(CConfigForFTime))
  96. c_ftime = external(FTIME, [lltype.Ptr(TIMEB)],
  97. lltype.Void,
  98. _nowrapper=True, releasegil=False)
  99. c_time = external('time', [rffi.VOIDP], rffi.TIME_T,
  100. _nowrapper=True, releasegil=False)
  101. @replace_time_function('time')
  102. def time():
  103. void = lltype.nullptr(rffi.VOIDP.TO)
  104. result = -1.0
  105. if HAVE_GETTIMEOFDAY:
  106. with lltype.scoped_alloc(TIMEVAL) as t:
  107. errcode = -1
  108. if GETTIMEOFDAY_NO_TZ:
  109. errcode = c_gettimeofday(t)
  110. else:
  111. errcode = c_gettimeofday(t, void)
  112. if rffi.cast(rffi.LONG, errcode) == 0:
  113. result = decode_timeval(t)
  114. if result != -1:
  115. return result
  116. else: # assume using ftime(3)
  117. with lltype.scoped_alloc(TIMEB) as t:
  118. c_ftime(t)
  119. result = (float(intmask(t.c_time)) +
  120. float(intmask(t.c_millitm)) * 0.001)
  121. return result
  122. return float(c_time(void))
  123. # _______________________________________________________________
  124. # time.clock()
  125. if _WIN32:
  126. # hacking to avoid LARGE_INTEGER which is a union...
  127. QueryPerformanceCounter = external(
  128. 'QueryPerformanceCounter', [rffi.CArrayPtr(lltype.SignedLongLong)],
  129. lltype.Void, releasegil=False)
  130. QueryPerformanceFrequency = external(
  131. 'QueryPerformanceFrequency', [rffi.CArrayPtr(lltype.SignedLongLong)],
  132. rffi.INT, releasegil=False)
  133. class State(object):
  134. divisor = 0.0
  135. counter_start = 0
  136. state = State()
  137. elif CLOCK_PROCESS_CPUTIME_ID is not None:
  138. # Linux and other POSIX systems with clock_gettime()
  139. globals().update(rffi_platform.configure(CConfigForClockGetTime))
  140. TIMESPEC = TIMESPEC
  141. CLOCK_PROCESS_CPUTIME_ID = CLOCK_PROCESS_CPUTIME_ID
  142. eci_with_lrt = eci.merge(ExternalCompilationInfo(libraries=['rt']))
  143. c_clock_gettime = external('clock_gettime',
  144. [lltype.Signed, lltype.Ptr(TIMESPEC)],
  145. rffi.INT, releasegil=False,
  146. compilation_info=eci_with_lrt)
  147. if need_rusage:
  148. RUSAGE = RUSAGE
  149. RUSAGE_SELF = RUSAGE_SELF or 0
  150. c_getrusage = external('getrusage',
  151. [rffi.INT, lltype.Ptr(RUSAGE)],
  152. rffi.INT,
  153. releasegil=False)
  154. def win_perf_counter():
  155. with lltype.scoped_alloc(rffi.CArray(rffi.lltype.SignedLongLong), 1) as a:
  156. if state.divisor == 0.0:
  157. QueryPerformanceCounter(a)
  158. state.counter_start = a[0]
  159. QueryPerformanceFrequency(a)
  160. state.divisor = float(a[0])
  161. QueryPerformanceCounter(a)
  162. diff = a[0] - state.counter_start
  163. return float(diff) / state.divisor
  164. @replace_time_function('clock')
  165. def clock():
  166. if _WIN32:
  167. return win_perf_counter()
  168. elif CLOCK_PROCESS_CPUTIME_ID is not None:
  169. with lltype.scoped_alloc(TIMESPEC) as a:
  170. c_clock_gettime(CLOCK_PROCESS_CPUTIME_ID, a)
  171. result = (float(rffi.getintfield(a, 'c_tv_sec')) +
  172. float(rffi.getintfield(a, 'c_tv_nsec')) * 0.000000001)
  173. return result
  174. else:
  175. with lltype.scoped_alloc(RUSAGE) as a:
  176. c_getrusage(RUSAGE_SELF, a)
  177. result = (decode_timeval(a.c_ru_utime) +
  178. decode_timeval(a.c_ru_stime))
  179. return result
  180. # _______________________________________________________________
  181. # time.sleep()
  182. if _WIN32:
  183. Sleep = external('Sleep', [rffi.ULONG], lltype.Void)
  184. else:
  185. c_select = external('select', [rffi.INT, rffi.VOIDP,
  186. rffi.VOIDP, rffi.VOIDP,
  187. lltype.Ptr(TIMEVAL)], rffi.INT,
  188. save_err=rffi.RFFI_SAVE_ERRNO)
  189. @replace_time_function('sleep')
  190. def sleep(secs):
  191. if _WIN32:
  192. millisecs = secs * 1000.0
  193. while millisecs > UINT_MAX:
  194. Sleep(UINT_MAX)
  195. millisecs -= UINT_MAX
  196. Sleep(rffi.cast(rffi.ULONG, int(millisecs)))
  197. else:
  198. void = lltype.nullptr(rffi.VOIDP.TO)
  199. with lltype.scoped_alloc(TIMEVAL) as t:
  200. frac = math.fmod(secs, 1.0)
  201. rffi.setintfield(t, 'c_tv_sec', int(secs))
  202. rffi.setintfield(t, 'c_tv_usec', int(frac*1000000.0))
  203. if rffi.cast(rffi.LONG, c_select(0, void, void, void, t)) != 0:
  204. errno = rposix.get_saved_errno()
  205. if errno != EINTR:
  206. raise OSError(errno, "Select failed")