|
|
|
@ -6,6 +6,7 @@ if they are available and otherwise point to mocks.
@@ -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):
@@ -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:
@@ -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:
@@ -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. |
|
|
|
|