Skip to content

Commit 7b30541

Browse files
authored
Add CVA6 performance model (#2880)
1 parent 4a1bffa commit 7b30541

File tree

5 files changed

+1402
-0
lines changed

5 files changed

+1402
-0
lines changed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ CVA6 is a 6-stage, single-issue, in-order CPU which implements the 64-bit RISC-V
44

55
It has a configurable size, separate TLBs, a hardware PTW and branch-prediction (branch target buffer and branch history table). The primary design goal was on reducing critical path length.
66

7+
A performance model of CVA6 is available in the `perf-model/` folder of this repository.
8+
It can be used to investigate performance-related micro-architecture changes.
9+
710
<img src="docs/03_cva6_design/_static/ariane_overview.drawio.png"/>
811

912

perf-model/README.md

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# CVA6 cycle-accurate performance model
2+
3+
This repository contains a cycle-accurate performance model of CVA6 control-path.
4+
5+
It was developed to explore microarchitecture changes in CVA6 before implementing them.
6+
7+
To cite this model, please head to the end of this document.
8+
9+
10+
## Getting started
11+
12+
### Adapt RVFI trace generation
13+
14+
The regular expression expects the cycle number to be in the RVFI trace.
15+
The value is not used by the model but it is used to compare the model and CVA6.
16+
17+
To emit cycle number in RVFI trace, modify `corev_apu/tb/rvfi_tracer.sv` in CVA6 repository as below.
18+
19+
```diff
20+
- $fwrite(f, "core 0: 0x%h (0x%h) DASM(%h)\n",
21+
- pc64, rvfi_i[i].insn, rvfi_i[i].insn);
22+
+ $fwrite(f, "core 0: 0x%h (0x%h) @%d DASM(%h)\n",
23+
+ pc64, rvfi_i[i].insn, cycles, rvfi_i[i].insn);
24+
```
25+
26+
27+
### Generate an RVFI trace
28+
29+
To generate an RVFI trace, follow the instructions in the CVA6 repository to run a simulation.
30+
The RVFI trace will be in `verif/sim/out_<date>/<simulator>/<test-name>.log`.
31+
32+
33+
### Running the model
34+
35+
```bash
36+
python3 model.py verif/sim/out_<date>/<simulator>/<test-name>.log
37+
```
38+
39+
40+
### Exploring design space
41+
42+
In `model.py`, the `main` function runs the model with arguments which override default values.
43+
Generic parameters are available in `Model.__init__`.
44+
You can add new parameters to explore here.
45+
46+
To perform exploration, run the model in a loop, like `issue_commit_graph` does.
47+
The `display_scores` function is meant to print a 3D plot if you have `matplotlib`.
48+
`issue_commit_graph` prints the scores so that you can store it and display the figure without re-running the model.
49+
50+
51+
## Files
52+
53+
| Name | Description |
54+
| :--- | :--- |
55+
| `cycle_diff.py` | Calculates duration of each instruction in an RVFI trace |
56+
| `isa.py` | Module to create Python objects from RISC-V instructions |
57+
| `model.py` | The CVA6 performance model |
58+
59+
60+
## Citing
61+
62+
```bibtex
63+
@inproceedings{cf24,
64+
author = {Allart, C\^{o}me and Coulon, Jean-Roch and Sintzoff, Andr\'{e} and Potin, Olivier and Rigaud, Jean-Baptiste},
65+
title = {Using a Performance Model to Implement a Superscalar CVA6},
66+
year = {2024},
67+
isbn = {9798400704925},
68+
publisher = {Association for Computing Machinery},
69+
url = {https://doi.org/10.1145/3637543.3652871},
70+
doi = {10.1145/3637543.3652871},
71+
abstract = {A performance model of CVA6 RISC-V processor is built to evaluate performance-related modifications before implementing them in RTL. Its accuracy is 99.2\% on CoreMark. This model is used to evaluate a superscalar feature for CVA6. During design phase, the model helped detecting and fixing performance bugs. The superscalar feature resulted in a CVA6 performance improvement of 40\% on CoreMark.},
72+
booktitle = {Proceedings of the 21st ACM International Conference on Computing Frontiers: Workshops and Special Sessions},
73+
pages = {43–46},
74+
numpages = {4},
75+
keywords = {CVA6, Cycle-Based Model, Multi-Issue, Performance, RISC-V, Superscalar},
76+
location = {Ischia, Italy},
77+
series = {CF '24 Companion}
78+
}
79+
```

perf-model/cycle_diff.py

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Copyright 2024 Thales Silicon Security
2+
#
3+
# Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
6+
# You may obtain a copy of the License at https://solderpad.org/licenses/
7+
#
8+
# Original Author: Côme ALLART - Thales
9+
10+
import re
11+
import sys
12+
13+
re_csrr_minstret = re.compile(r"^csrr\s+\w+,\s*minstret$")
14+
re_full = re.compile(
15+
r"([a-z]+)\s+0:\s*0x00000000([0-9a-f]+)\s*\(([0-9a-fx]+)\)\s*(\S*)@\s*([0-9]+)\s*(.*)"
16+
)
17+
18+
class Trace:
19+
def __init__(self, addr, cycle, mnemo, flags):
20+
self.addr = addr
21+
self.cycle = cycle
22+
self.mnemo = mnemo
23+
self.flags = flags
24+
self.delta = None
25+
26+
def report(self):
27+
"""True if the instruction is a loading instruction"""
28+
return f"+{self.delta} {self.flags} 0x{self.addr}: {self.mnemo}"
29+
30+
def print_data(name, value):
31+
"Prints 'name = data' with alignment of the '='"
32+
spaces = ' ' * (24 - len(name))
33+
print(f"{name}{spaces} = {value}")
34+
35+
def read_traces(input_file):
36+
"Collect stage traces from file"
37+
l = []
38+
def filter_add(trace):
39+
if not hasattr(filter_add, "accepting"):
40+
filter_add.accepting = False
41+
if re_csrr_minstret.search(trace.mnemo):
42+
filter_add.accepting = not filter_add.accepting
43+
return
44+
if filter_add.accepting:
45+
l.append(trace)
46+
with open(input_file, "r", encoding="utf8") as f:
47+
for line in [l.strip() for l in f]:
48+
found = re_full.search(line)
49+
if found:
50+
addr = found.group(2)
51+
flags = found.group(4)
52+
cycle = int(found.group(5))
53+
mnemo = found.group(6)
54+
filter_add(Trace(addr, cycle, mnemo, flags))
55+
#l.append(Trace(addr, cycle, mnemo, flags))
56+
return l
57+
58+
def write_traces(outfile, traces):
59+
"Write all instructions to output file"
60+
print("output file:", outfile)
61+
with open(outfile, "w", encoding="utf8") as f:
62+
for trace in traces:
63+
f.write(trace.report() + "\n")
64+
65+
def main(input_file: str):
66+
"Main function"
67+
traces = read_traces(input_file)
68+
cycle = traces[0].cycle
69+
cycle_number = traces[-1].cycle - cycle + 1
70+
for trace in traces:
71+
trace.delta = trace.cycle - cycle
72+
cycle = trace.cycle
73+
print_data("cycle number", cycle_number)
74+
print_data("Coremark/MHz", 1000000 / cycle_number)
75+
print_data("instruction number", len(traces))
76+
print_data("IPC", len(traces) / cycle_number)
77+
write_traces("traceout.log", traces)
78+
79+
if __name__ == "__main__":
80+
main(sys.argv[1])

0 commit comments

Comments
 (0)