diff --git a/src/kyupy/__init__.py b/src/kyupy/__init__.py index fd6ab26..897e832 100644 --- a/src/kyupy/__init__.py +++ b/src/kyupy/__init__.py @@ -6,6 +6,7 @@ if they are available and otherwise point to mocks. """ import time +import sys from collections import defaultdict import importlib.util import gzip @@ -76,21 +77,27 @@ def hr_time(seconds): class Timer: - def __init__(self): self.s = 0 - def __enter__(self): self.start_time = time.perf_counter() + def __init__(self, s=0): self.s = s + def __enter__(self): self.start_time = time.perf_counter(); return self def __exit__(self, *args): self.s += time.perf_counter() - self.start_time @property def ms(self): return self.s*1e3 @property def us(self): return self.s*1e6 - def __repr__(self): return f'{self.s:.3f}s' if self.s >= 1 else f'{self.ms:.3f}ms' + def __repr__(self): return f'{self.s:.3f}' + def __add__(self, t): + return Timer(self.s + t.s) class Timers: - def __init__(self): self.timers = defaultdict(Timer) + def __init__(self, t={}): self.timers = defaultdict(Timer) | t def __getitem__(self, name): return self.timers[name] def __getattr__(self, name): return self.timers[name] - def __repr__(self): return ''.join([f'{k}={v} ' for k, v in self.timers.items()]) + def __repr__(self): return '{' + ', '.join([f'{k}: {v}' for k, v in self.timers.items()]) + '}' + def __add__(self, t): + tmr = Timers(self.timers) + for k, v in t.timers.items(): tmr.timers[k] += v + return tmr class Log: @@ -100,25 +107,36 @@ class Log: def __init__(self): self.start = time.perf_counter() - self.logfile = None + self.logfile = sys.stdout """When set to a file handle, log messages are written to it instead to standard output. After each write, ``flush()`` is called as well. """ + self.indent = 0 def __getstate__(self): return {'elapsed': time.perf_counter() - self.start} def __setstate__(self, state): - self.logfile = None + self.logfile = sys.stdout + self.indent = 0 self.start = time.perf_counter() - state['elapsed'] + def write(self, s, indent=0): + self.logfile.write(' '*indent + s + '\n') + self.logfile.flush() + + def li(self, item): self.write('- ' + str(item).replace('\n', '\n'+' '*(self.indent+1)), self.indent) + def lib(self): self.write('-', self.indent); self.indent += 1 + def lin(self): self.write('-', self.indent-1) + def di(self, key, value): self.write(str(key) + ': ' + str(value).replace('\n', '\n'+' '*(self.indent+1)), self.indent) + def dib(self, key): self.write(str(key) + ':', self.indent); self.indent += 1 + def din(self, key): self.write(str(key) + ':', self.indent-1) + def ie(self, n=1): self.indent -= n + def log(self, level, message): t = time.perf_counter() - self.start - if self.logfile is None: - print(f'{t:011.3f} {level} {message}') - else: - self.logfile.write(f'{t:011.3f} {level} {message}\n') - self.logfile.flush() + self.logfile.write(f'# {t:011.3f} {level} {message}\n') + self.logfile.flush() def info(self, message): """Log an informational message.""" @@ -227,11 +245,11 @@ if importlib.util.find_spec('numba') is not None: try: list(numba.cuda.gpus) from numba import cuda + from numba.core import config + config.CUDA_LOW_OCCUPANCY_WARNINGS = False except CudaSupportError: log.warn('Cuda unavailable. Falling back to pure Python.') cuda = MockCuda() - from numba.core import config - config.CUDA_LOW_OCCUPANCY_WARNINGS = False else: numba = MockNumba() """If Numba is available on the system, it is the actual ``numba`` package.