|
|
@ -1,6 +1,8 @@ |
|
|
|
"""A package for processing and analysis of non-hierarchical gate-level VLSI designs. |
|
|
|
"""A package for processing and analysis of non-hierarchical gate-level VLSI designs. |
|
|
|
|
|
|
|
|
|
|
|
It contains fundamental building blocks for research software in the fields of VLSI test, diagnosis and reliability. |
|
|
|
The kyupy package itself contains a logger and other simple utility functions. |
|
|
|
|
|
|
|
In addition, it defines a ``numba`` and a ``cuda`` module that point to the actual modules |
|
|
|
|
|
|
|
if they are available and point to mocks if numba is not installed. |
|
|
|
""" |
|
|
|
""" |
|
|
|
|
|
|
|
|
|
|
|
import time |
|
|
|
import time |
|
|
@ -14,10 +16,12 @@ _pop_count_lut = np.asarray([bin(x).count('1') for x in range(256)]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def popcount(a): |
|
|
|
def popcount(a): |
|
|
|
|
|
|
|
"""Returns the number of 1-bits in a given packed numpy array.""" |
|
|
|
return np.sum(_pop_count_lut[a]) |
|
|
|
return np.sum(_pop_count_lut[a]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def readtext(file): |
|
|
|
def readtext(file): |
|
|
|
|
|
|
|
"""Reads and returns the text in a given file. Transparently decompresses \\*.gz files.""" |
|
|
|
if hasattr(file, 'read'): |
|
|
|
if hasattr(file, 'read'): |
|
|
|
return file.read() |
|
|
|
return file.read() |
|
|
|
if str(file).endswith('.gz'): |
|
|
|
if str(file).endswith('.gz'): |
|
|
@ -29,6 +33,7 @@ def readtext(file): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def hr_sci(value): |
|
|
|
def hr_sci(value): |
|
|
|
|
|
|
|
"""Formats a value in a human-readible scientific notation.""" |
|
|
|
multiplier = 0 |
|
|
|
multiplier = 0 |
|
|
|
while abs(value) >= 1000: |
|
|
|
while abs(value) >= 1000: |
|
|
|
value /= 1000 |
|
|
|
value /= 1000 |
|
|
@ -40,6 +45,7 @@ def hr_sci(value): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def hr_bytes(nbytes): |
|
|
|
def hr_bytes(nbytes): |
|
|
|
|
|
|
|
"""Formats a given number of bytes for human readability.""" |
|
|
|
multiplier = 0 |
|
|
|
multiplier = 0 |
|
|
|
while abs(nbytes) >= 1000: |
|
|
|
while abs(nbytes) >= 1000: |
|
|
|
nbytes /= 1024 |
|
|
|
nbytes /= 1024 |
|
|
@ -48,6 +54,7 @@ def hr_bytes(nbytes): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def hr_time(seconds): |
|
|
|
def hr_time(seconds): |
|
|
|
|
|
|
|
"""Formats a given time interval for human readability.""" |
|
|
|
s = '' |
|
|
|
s = '' |
|
|
|
if seconds >= 86400: |
|
|
|
if seconds >= 86400: |
|
|
|
d = seconds // 86400 |
|
|
|
d = seconds // 86400 |
|
|
@ -68,9 +75,15 @@ def hr_time(seconds): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Log: |
|
|
|
class Log: |
|
|
|
|
|
|
|
"""A very simple logger that formats the messages with the number of seconds since |
|
|
|
|
|
|
|
program start. |
|
|
|
|
|
|
|
""" |
|
|
|
def __init__(self): |
|
|
|
def __init__(self): |
|
|
|
self.start = time.perf_counter() |
|
|
|
self.start = time.perf_counter() |
|
|
|
self.logfile = None |
|
|
|
self.logfile = None |
|
|
|
|
|
|
|
"""When set to a file handle, log messages are written to it instead to standard output. |
|
|
|
|
|
|
|
After each write, ``flush()`` is called as well. |
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
|
|
def log(self, level, message): |
|
|
|
def log(self, level, message): |
|
|
|
t = time.perf_counter() - self.start |
|
|
|
t = time.perf_counter() - self.start |
|
|
@ -80,13 +93,21 @@ class Log: |
|
|
|
self.logfile.write(f'{t:011.3f} {level} {message}\n') |
|
|
|
self.logfile.write(f'{t:011.3f} {level} {message}\n') |
|
|
|
self.logfile.flush() |
|
|
|
self.logfile.flush() |
|
|
|
|
|
|
|
|
|
|
|
def info(self, message): self.log('-', message) |
|
|
|
def info(self, message): |
|
|
|
|
|
|
|
"""Log an informational message.""" |
|
|
|
|
|
|
|
self.log('-', message) |
|
|
|
|
|
|
|
|
|
|
|
def warn(self, message): self.log('W', message) |
|
|
|
def warn(self, message): |
|
|
|
|
|
|
|
"""Log a warning message.""" |
|
|
|
|
|
|
|
self.log('W', message) |
|
|
|
|
|
|
|
|
|
|
|
def error(self, message): self.log('E', message) |
|
|
|
def error(self, message): |
|
|
|
|
|
|
|
"""Log an error message.""" |
|
|
|
|
|
|
|
self.log('E', message) |
|
|
|
|
|
|
|
|
|
|
|
def range(self, *args): |
|
|
|
def range(self, *args): |
|
|
|
|
|
|
|
"""A generator that operates just like the ``range()`` built-in, and also occasionally logs the progress |
|
|
|
|
|
|
|
and compute time estimates.""" |
|
|
|
elems = len(range(*args)) |
|
|
|
elems = len(range(*args)) |
|
|
|
start_time = time.perf_counter() |
|
|
|
start_time = time.perf_counter() |
|
|
|
lastlog_time = start_time |
|
|
|
lastlog_time = start_time |
|
|
@ -105,6 +126,7 @@ class Log: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log = Log() |
|
|
|
log = Log() |
|
|
|
|
|
|
|
"""The standard logger instance.""" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# |
|
|
|
# |
|
|
|