| # Trace Based Model (TBM) |
| |
| ## What is TBM? |
| |
| TBM is a performance simulator, designed to get performance measurements very |
| early in the design cycle of processors/accelerators. It provides a way for |
| testing the impact of new design ideas, before any detailed implementation. In |
| order to do hardware-software codesign, it is necessary to have a highly |
| configurable, easily extended performance simulator that gives detailed, |
| actionable feedback to hardware engineers about the bottlenecks of different |
| microarchitectural options; that can give detailed, actionable feedback to |
| software engineers about the performance of the inner loops of their code; and |
| that can be used to evaluate a range of different design microarchitectural |
| decisions. Having a configurable, and extensible, performance simulator enables |
| the software and hardware engineers to have the conversations that are critical |
| to hardware-software codesign and replaces guesswork and hunches with data. |
| |
| TBMs approach is to use an existing functional simulator to generate a |
| functional trace and to build a “trace based model” (TBM) that models the |
| control/scheduling logic of the microarchitecture but does not need to calculate |
| the result of each instruction. The overall usage of a TBM: a functional |
| simulator simulates execution of a program and generates a functional trace; TBM |
| processes the functional trace using a microarchitectural model and produces |
| information about the performance of the program on the microarchitecture being |
| modeled. TBM is intended to be small and simple. Since it is only concerned with |
| implementing the control/scheduling logic, it is possible to achieve high levels |
| of code reuse and make it highly configurable. |
| |
| ## Project structure |
| |
| ### Prerequisite: |
| |
| To run TBM you will need Python3 and the packages listed in `requirements.txt`. |
| You can install the packages with pip: `pip install -r requirements.txt`. |
| |
| You will also need the flatbuffers compiler `flatc`. On Debian based distros you |
| can get it with apt: `sudo apt install flatbuffers-compiler` |
| |
| The make scripts expect the following environment variables and directory |
| structure: |
| |
| * `ROOTDIR` should be set to the root directory of the shodan source tree. |
| * `OUT` should be set to the directory where build artifacts should be created |
| (e.g. `$ROOTDIR/out`). |
| * To use spike (RISC-V simulator), the spike executable should be in |
| `$OUT/host/spike/bin/spike`. |
| * To update the RISC-V pipe-maps, the |
| [riscv-opcodes](https://github.com/riscv/riscv-opcodes) repo (commit |
| `6c34f60fe290613b7ba1d280b29a41179c399e69`) should be checked out at |
| `$ROOTDIR/toolchain/riscv-opcodes`. |
| |
| ### Executables: |
| |
| - `tbm/gentrace-spike.py` - reads a Spike trace and reformat it. |
| - `tbm/gentrace-renode.py` - reads a Renode trace and reformat it. |
| - `tbm/import-riscv-opcodes.py` - create and update pipe-maps. |
| - `tbm/merge-counters.py` - merges results from multiple runs of TBM. |
| - `tbm/tbm.py` - runs a trace in TBM; the main tool here. |
| |
| ### 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. |
| |
| - `tbm/buffered_queue.py` - defines `Queue`, FIFO queue model. |
| - `tbm/counter.py` - performance counters. |
| - `tbm/cpu.py` - defines CPU, a cpu model (includes instances of `FetchUnit`, `SchedUnit`, |
| `ExecUnit`, and `MemorySystem`). |
| - `tbm/disassembler.py` - bits we need to elaborate Spike traces. |
| - `tbm/exec_unit.py` - defines `ExecUnit`, an execution unit model (includes instances of |
| `ScalarPipe`, `VectorPipe`, `scoreboard.Preemptive` and `scoreboard.VecPreemptive`). |
| - `tbm/fetch_unit.py` - defines `FetchUnit`. |
| - `tbm/functional_trace.py` - reads a trace (as generated by `gentrace-*.py`). |
| - `tbm/instruction.py` - defines `Instruction`, a data class representing a single |
| instruction instance in the trace. |
| - `tbm/interfaces.py` - defines the internal API. This will be more important when we |
| add different models (i.e. implementations) for the various units. |
| - `tbm/memory_system.py` - defines `MemorySystem`, a main memory and cache hierarchy model. |
| - `tbm/scalar_pipe.py` - defines `ScalarPipe`, a scalar functional unit model. |
| - `tbm/sched_unit.py` - defines `SchedUnit`, an issue queue model. |
| - `tbm/scoreboard.py` - defines `Preemptive` and `VecPreemptive`, scoreboard models. |
| - `tbm/tbm_options.py` - command line parsing for `tbm.py`. |
| - `tbm/utilities.py` - general purpose constructs. |
| - `tbm/vector_pipe.py` - defines `VectorPipe`, a vector functional unit model. |
| |
| ### TBM configuration files: |
| |
| - `config/instruction.fbs` - FlatBuffer schema for the Instruction data class (used for |
| saving elaborated traces). The `FBInstruction.Instruction` module is generated |
| from this file. |
| - `config/rvv-simple.yaml` - a uArch configuration example. |
| - `config/uarch.schema.json` - JSON schema for uArch configuration files. |
| - `pipe_maps/riscv/*.json` - pipe-maps, mapping RISC-V opcodes to functional units. |
| |
| ### Build files: |
| |
| - `Makefile` - builds things that are needed for tbm to run. |
| - `common.mk` |
| <!--- BEGIN-INTERNAL --> |
| - `integration-tests.mk` - runs tbm on some ML models. |
| - `riscv_tests.mk` `riscv_tests_isa.mk` - run tbm on tests from `$OUT/springbok/riscv-tests`. |
| - `rvv_tests.mk` - runs tbm on tests from `$OUT/springbok/rvv_for_tbm/tests`. |
| <!--- END-INTERNAL --> |
| - `tbm.mk` - rules for running tbm. |
| |
| |
| ## How to use the make files |
| |
| ### Building TBM: |
| |
| Before running any of the TBM tools you must run `make all`. |
| |
| To update the RISC-V pipe-maps in `pipe_maps/riscv` run `make riscv_pipe_maps`. |
| This will import missing opcodes from `$ROOTDIR/toolchain/riscv-opcodes`, and |
| will remove spurious ones. New opcodes are mapped to "UNKNOWN". You can also |
| update individual RISC-V pipe-maps like this: `make pipe_maps/riscv/rv32a.json`. |
| |
| To run a linter on all the Python files in `tbm/` run `make lint`. |
| |
| To type-check all the Python scripts run `make type-check`. After running the |
| type checker you can merge inferred types back to the `.py` files by running |
| `make merge-pyi` to merge into all `.py` files, or `make merge-pyi-MOD` to |
| merge into `tbm/MOD.py`. |
| |
| <!--- BEGIN-INTERNAL --> |
| ### Running tests from shodan |
| |
| - `make -f integration-tests.mk integration_tests` - most of these tests are |
| actually not very good for integration testing as they take far too long to |
| complete. |
| - `make -f riscv_tests.mk riscv_tests_isa` - run some of the tests from `$ROOTDIR/out/springbok/riscv-tests/isa`. |
| - `make -f riscv_tests.mk riscv_tests_benchmarks` - run the tests from `$ROOTDIR/out/springbok/riscv-tests/benchmarks`. |
| - `make -f riscv_tests.mk riscv_tests` - run the two previous targets. |
| - `make -f riscv_tests.mk benchmarks` - runs the above benchmarks and generates |
| the file `benchmarks.md` with all the results. |
| - `make -f rvv_tests.mk rvv_tests` - run the tests from `$ROOTDIR/out/springbok/rvv_for_tbm/tests/`. |
| <!--- END-INTERNAL --> |