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()