utils: general purpose utilities Also includes a new README.md explaining the code structure to come. Change-Id: I2725308c3f0dc2cbd88f5f8481555154223e4e97
diff --git a/README.md b/README.md new file mode 100644 index 0000000..2a6aad0 --- /dev/null +++ b/README.md
@@ -0,0 +1,47 @@ +# Trace Based Model (TBM) + +## Code structure + +### Executables: + +- gentrace-spike.py - reads a Spike trace and reformat it. We expect to support + other functional simulators, each of those will have its own gentrace-*.py + file. +- tbm.py - runs a trace in TBM; the main tool here. +- merge-counters.py - merges results from multiple runs of TBM. + +### Python modules: + +**NOTE:** currently TBM includes a single model for each of the building block +units. The intention is that other models will be added in the future to cover +uArchs that are not supported by the current models. interfaces.py defines (what +we expect to be) the API of the building blocks. + +- counter.py - performance counters. +- cpu.py - defines CPU, a cpu model (includes instances of FetchUnit, SchedUnit, + ExecUnit, and MemorySystem). +- disassembler.py - bits we need to elaborate Spike traces. +- exec_unit.py - defines ExecUnit, an execution unit model (includes instances of + ScalarPipe, VectorPipe, scoreboard.Preemptive and scoreboard.VecPreemptive). +- fetch_unit.py - defines FetchUnit. +- instruction.fbs - FlatBuffer schema for the Instruction data class (used for + saving elaborated traces). The FBInstruction.Instruction module is generated + from this file. +- instruction.py - defines Instruction, a data class representing a single + instruction instance in the trace. +- interfaces.py - defines the internal API. This will be more important when we + add different models (i.e. implementations) for the various units. +- memory_system.py - defines MemorySystem, a main memory and cache hierarchy model. +- queue.py - defines Queue, FIFO queue model. +- scalar_pipe.py - defines ScalarPipe, a scalar functional unit model. +- sched_unit.py - defines SchedUnit, an issue queue model. +- scoreboard.py - defines Preemptive and VecPreemptive, scoreboard models. +- tbm_options.py - command line parsing for tbm.py. +- trace.py - reads a trace (as generated by gentrace-*.py). +- utilities.py - general purpose constructs. +- vector_pipe.py - defines VectorPipe, a vector functional unit model. + +### Other files: + +- config/uarch.schema.json - JSON schema for uArch configuration files. +- config/default_arch.yaml - a uArch configuration example.
diff --git a/utilities.py b/utilities.py new file mode 100644 index 0000000..4fdbff3 --- /dev/null +++ b/utilities.py
@@ -0,0 +1,77 @@ +"""Collection of general purpose utilities.""" + +import enum +import itertools +import logging +import sys +import threading +import time +from typing import Any, Callable, Iterable, Sequence + + +def logging_config(level: int) -> None: + """Configure the root logger to track events starting from `level`. + + If tracked, WARNING events (and above) go to stderr, other events go to + stdout. + """ + # Log messages below WARNING go to stdout. + stdout_h = logging.StreamHandler(sys.stdout) + stdout_h.setLevel(logging.DEBUG) + stdout_h.addFilter(lambda record: record.levelno < logging.WARNING) + + # Log messages that are WARNING and above go to stderr. + stderr_h = logging.StreamHandler(sys.stderr) + stderr_h.setLevel(logging.WARNING) + + formatter = logging.Formatter("[%(asctime)s] %(message)s", + datefmt="%H:%M:%S'") + stdout_h.setFormatter(formatter) + stderr_h.setFormatter(formatter) + + logging.basicConfig(handlers=[stdout_h, stderr_h], + level=level) + + +class FileFormat(enum.Enum): + FLATBUFFERS = enum.auto() + JSON = enum.auto() + + +def flatten(xss: Iterable[Iterable[Any]]) -> Sequence[Any]: + return list(itertools.chain.from_iterable(xss)) + + +class CallEvery(): + """Call some function every few seconds. + + `with CallEvery(s, f) as c: ...` calls `f()` every `s` seconds, while inside + the with block. + """ + + def __init__(self, period, f: Callable[[], None]): + self.period = period + self.f = f + self.running = False + self.timer = None + self.t = None + + def __enter__(self) -> None: + self.running = True + self.t = time.time() + self.period + self.timer = threading.Timer(max(self.t - time.time(), 0), self._run) + self.timer.start() + + def __exit__(self, exc_type, exc_value, traceback) -> bool: + self.running = False + if self.timer: + self.timer.cancel() + return False + + def _run(self): + if self.running: + self.f() + self.t += self.period + self.timer = threading.Timer(max(self.t - time.time(), 0), + self._run) + self.timer.start()