codon/stdlib/time.codon

269 lines
6.1 KiB
Python
Raw Normal View History

# Copyright (C) 2022-2024 Exaloop Inc. <https://exaloop.io>
2022-01-24 18:22:49 +08:00
def time() -> float:
2021-09-28 02:02:44 +08:00
return _C.seq_time() / 1e9
2022-01-24 18:22:49 +08:00
def time_ns() -> int:
return _C.seq_time()
2022-01-24 18:22:49 +08:00
def monotonic() -> float:
return _C.seq_time_monotonic() / 1e9
2022-01-24 18:22:49 +08:00
def monotonic_ns() -> int:
return _C.seq_time_monotonic()
2022-01-24 18:22:49 +08:00
def perf_counter() -> float:
return _C.seq_time_highres() / 1e9
2022-01-24 18:22:49 +08:00
def perf_counter_ns() -> int:
return _C.seq_time_highres()
2022-02-16 23:51:16 +08:00
def sleep(secs: float):
if secs < 0:
raise ValueError("sleep length must be non-negative")
_C.seq_sleep(secs)
2021-09-28 02:02:44 +08:00
class TimeInterval:
"""
Utility class for timing Seq code
"""
2022-01-24 18:22:49 +08:00
2021-09-28 02:02:44 +08:00
start: int
msg: str
2022-02-16 23:51:16 +08:00
def __init__(self):
2021-09-28 02:02:44 +08:00
self.start = _C.seq_time()
2022-01-24 18:22:49 +08:00
self.msg = ""
2021-09-28 02:02:44 +08:00
2022-02-16 23:51:16 +08:00
def __enter__(self):
2021-09-28 02:02:44 +08:00
self.start = _C.seq_time()
2022-02-16 23:51:16 +08:00
def __exit__(self):
2024-07-31 07:35:27 +08:00
from sys import stderr
2021-09-28 02:02:44 +08:00
print(self.report(self.msg), file=stderr)
2022-01-24 18:22:49 +08:00
def report(self, msg="", memory=False) -> str:
2021-09-28 02:02:44 +08:00
msg = f"{'Block' if not self.msg else self.msg} took {self.elapsed()}s"
# if memory:
2022-01-24 18:22:49 +08:00
# msg = f'{msg} ({_C.memory()} MB)'
2021-09-28 02:02:44 +08:00
return msg
2022-01-24 18:22:49 +08:00
def elapsed(self) -> float:
2021-09-28 02:02:44 +08:00
return float(_C.seq_time() - self.start) / 1e9
2022-02-16 23:51:16 +08:00
def tick(self, msg, memory=False):
2021-09-28 02:02:44 +08:00
ret = self.report(msg)
self.start = _C.seq_time()
2022-01-24 18:22:49 +08:00
def timing(msg: str = "") -> TimeInterval:
2021-09-28 02:02:44 +08:00
"""
Example usage:
.. code-block:: python
2021-09-28 02:02:44 +08:00
from time import timing
with timing('foo function'):
foo() # prints runtime of foo
"""
return TimeInterval(0, msg)
@tuple
class struct_time:
_year: i16
_yday: i16
_sec: i8
_min: i8
_hour: i8
_mday: i8
_mon: i8
_wday: i8
_isdst: i8
# (sunday=0) --> (monday=0)
2022-01-24 18:22:49 +08:00
def _wday_adjust_monday_start(wday: int) -> int:
x = wday - 1
if x < 0:
x = 6
return x
# (monday=0) --> (sunday=0)
2022-01-24 18:22:49 +08:00
def _wday_adjust_sunday_start(wday: int) -> int:
x = wday + 1
if x > 6:
x = 0
return x
2022-01-24 18:22:49 +08:00
def __new__(
2024-04-22 05:05:06 +08:00
year: int = 0,
mon: int = 0,
mday: int = 0,
hour: int = 0,
min: int = 0,
sec: int = 0,
wday: int = 0,
yday: int = 0,
isdst: int = 0,
2022-01-24 18:22:49 +08:00
) -> struct_time:
return struct_time(
i16(year - 1900),
i16(yday - 1),
i8(sec),
i8(min),
i8(hour),
i8(mday),
i8(mon - 1),
i8(struct_time._wday_adjust_sunday_start(wday)),
i8(isdst),
)
@property
2022-01-24 18:22:49 +08:00
def tm_year(self) -> int:
return int(self._year) + 1900
@property
2022-01-24 18:22:49 +08:00
def tm_yday(self) -> int:
return int(self._yday) + 1
@property
2022-01-24 18:22:49 +08:00
def tm_sec(self) -> int:
return int(self._sec)
@property
2022-01-24 18:22:49 +08:00
def tm_min(self) -> int:
return int(self._min)
@property
2022-01-24 18:22:49 +08:00
def tm_hour(self) -> int:
return int(self._hour)
@property
2022-01-24 18:22:49 +08:00
def tm_mday(self) -> int:
return int(self._mday)
@property
2022-01-24 18:22:49 +08:00
def tm_mon(self) -> int:
return int(self._mon) + 1
@property
2022-01-24 18:22:49 +08:00
def tm_wday(self) -> int:
return struct_time._wday_adjust_monday_start(int(self._wday))
@property
2022-01-24 18:22:49 +08:00
def tm_isdst(self) -> int:
return int(self._isdst)
2022-01-24 18:22:49 +08:00
def localtime(secs: int = -1) -> struct_time:
tm = struct_time()
worked = _C.seq_localtime(secs, __ptr__(tm).as_byte())
if not worked:
raise OSError("localtime failed")
return tm
2022-01-24 18:22:49 +08:00
def gmtime(secs: int = -1) -> struct_time:
tm = struct_time()
worked = _C.seq_gmtime(secs, __ptr__(tm).as_byte())
if not worked:
raise OSError("localtime failed")
return tm
2022-01-24 18:22:49 +08:00
def mktime(t) -> int:
if isinstance(t, struct_time):
return _C.seq_mktime(__ptr__(t).as_byte())
else:
tm = struct_time(*t)
return _C.seq_mktime(__ptr__(tm).as_byte())
# pytime.h funcs
_ROUND_HALF_EVEN = 0
_ROUND_CEILING = 1
_ROUND_FLOOR = 2
_ROUND_UP = 3
_MIN = 0x8000000000000000
2022-01-24 18:22:49 +08:00
_MAX = 0x7FFFFFFFFFFFFFFF
2022-02-16 23:51:16 +08:00
def _overflow():
raise OverflowError("timestamp too large")
2022-01-24 18:22:49 +08:00
def _add(t1: int, t2: int) -> int:
if t2 > 0 and t1 > _MAX - t2:
return _MAX
elif t2 < 0 and t1 < _MIN - t2:
return _MIN
else:
return t1 + t2
2022-01-24 18:22:49 +08:00
def _mul_check_overflow(a: int, b: int) -> bool:
if b != 0:
# assert b > 0
return (a < _MIN // b) or (_MAX // b < a)
else:
return False
2022-01-24 18:22:49 +08:00
def _mul(t: int, k: int) -> int:
# assert k >= 0
2022-01-24 18:22:49 +08:00
if _mul_check_overflow(t, k):
return _MAX if t >= 0 else _MIN
else:
return t * k
2022-01-24 18:22:49 +08:00
def _muldiv(ticks: int, mul: int, div: int) -> int:
intpart = ticks / div
ticks %= div
remaining = _mul(ticks, mul) // div
return _add(_mul(intpart, mul), remaining)
2022-01-24 18:22:49 +08:00
def _round_half_even(x: float) -> float:
from math import fabs
2022-01-24 18:22:49 +08:00
rounded = x.__round__()
if fabs(x - rounded) == 0.5:
rounded = 2.0 * (x / 2.0).__round__()
return rounded
2022-01-24 18:22:49 +08:00
def _round(x: float, mode: int) -> float:
d = x
if mode == _ROUND_HALF_EVEN:
d = _round_half_even(d)
elif mode == _ROUND_CEILING:
d = d.__ceil__()
elif mode == _ROUND_FLOOR:
d = d.__floor__()
elif mode == _ROUND_UP:
d = d.__ceil__() if d >= 0 else d.__floor__()
return d
2022-01-24 18:22:49 +08:00
def _double_to_denominator(d: float, idenominator: int, mode: int) -> Tuple[int, int]:
from math import modf
2022-01-24 18:22:49 +08:00
denominator = float(idenominator)
floatpart, intpart = modf(d)
floatpart *= denominator
floatpart = _round(floatpart, mode)
if floatpart >= denominator:
floatpart -= denominator
intpart += 1.0
elif floatpart < 0.0:
floatpart += denominator
intpart -= 1.0
# assert 0.0 <= floatpart < denominator
if intpart < _MIN or intpart > _MAX:
_overflow()
sec = int(intpart)
numerator = int(floatpart)
# assert 0 <= numerator < idenominator
return sec, numerator
2022-01-24 18:22:49 +08:00
def _time_to_timespec(t: float, mode: int) -> Tuple[int, int]:
return _double_to_denominator(t, 1000000000, mode)
2022-01-24 18:22:49 +08:00
def _time_to_timeval(t: float, mode: int) -> Tuple[int, int]:
return _double_to_denominator(t, 1000000, mode)