Skip to content

Commit ee8ac93

Browse files
committed
Add profiler script
1 parent 6d0e0ef commit ee8ac93

File tree

2 files changed

+164
-0
lines changed

2 files changed

+164
-0
lines changed

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,23 @@ _Example Instructions Histogram_
255255
_Example Registers Histogram_
256256
![Registers Hisrogram Example](docs/histogram-reg.png)
257257

258+
## RISC-V Basic Block Usage Statistics
259+
260+
To install [lolviz](https://github.com/parrt/lolviz)
261+
```shell
262+
$ pip install lolviz
263+
```
264+
For macOS users, installing might be required:
265+
```shell
266+
$ brew install graphviz
267+
```
268+
First, user need to crate the directory `prof` and build profiling data through executing `rv32emu`
269+
270+
```shell
271+
$ ./build/rv32emu -p ./build/[test_program].elf
272+
$ ./tools/rv_profiler [--start-address|--stop-address|--graph-ir] [test_program]
273+
```
274+
258275
## Contributing
259276

260277
See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines.

tools/rv_profiler

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
#!/usr/bin/env python3
2+
import sys
3+
import argparse
4+
import math
5+
from lolviz import *
6+
7+
class Block:
8+
def __init__(self, PC, IR_list, branch_taken=None, branch_untaken=None):
9+
self.PC = PC;
10+
self.IR_list = IR_list
11+
self.branch_taken = branch_taken
12+
self.branch_untaken = branch_untaken
13+
14+
def printTable(table):
15+
col_widths = getLongestWordLength(table)
16+
if len(table):
17+
if len(table[0]) == 9:
18+
print("PC_start".rjust(col_widths[0]), end=' ')
19+
print("PC_end".rjust(col_widths[0]), end=' ')
20+
print("frequency".rjust(col_widths[0]), end=' ')
21+
print("hot".rjust(col_widths[0]), end=' ')
22+
print("loop".rjust(col_widths[0]), end=' ')
23+
print("untaken".rjust(col_widths[0]), end=' ')
24+
print("taken".rjust(col_widths[0]), end=' ')
25+
print("".rjust(5), end=' ')
26+
print("IR_list", end=' ')
27+
print()
28+
for i in range(len(table)):
29+
print(table[i]["PC_start"].rjust(col_widths[i]), end=' ')
30+
print(table[i]["PC_end"].rjust(col_widths[i]), end=' ')
31+
print(table[i]["frequency"].rjust(col_widths[i]), end=' ')
32+
print(table[i]["hot"].rjust(col_widths[i]), end=' ')
33+
print(table[i]["loop"].rjust(col_widths[i]), end=' ')
34+
print(table[i]["untaken"].rjust(col_widths[i]), end=' ')
35+
print(table[i]["taken"].rjust(col_widths[i]), end=' ')
36+
print("".rjust(5), end=' ')
37+
print(table[i]["IR_list"], end=' ')
38+
print()
39+
else:
40+
print("PC_start".rjust(col_widths[0]), end=' ')
41+
print("PC_end".rjust(col_widths[0]), end=' ')
42+
print("untaken".rjust(col_widths[0]), end=' ')
43+
print("taken".rjust(col_widths[0]), end=' ')
44+
print("".rjust(5), end=' ')
45+
print("IR_list", end=' ')
46+
print()
47+
for i in range(len(table)):
48+
print(table[i]["PC_start"].rjust(col_widths[i]), end=' ')
49+
print(table[i]["PC_end"].rjust(col_widths[i]), end=' ')
50+
print(table[i]["untaken"].rjust(col_widths[i]), end=' ')
51+
print(table[i]["taken"].rjust(col_widths[i]), end=' ')
52+
print("".rjust(5), end=' ')
53+
print(table[i]["IR_list"], end=' ')
54+
print()
55+
56+
57+
def getLongestWordLength(table):
58+
return[max([len(item) for item in line]) for line in table]
59+
60+
profile_dict = {}
61+
block_dict = {}
62+
pc_set = set()
63+
def print_graph_IR(pc):
64+
if (pc in pc_set):
65+
return None;
66+
pc_set.add(pc);
67+
data = profile_dict[pc]
68+
print(data["PC_start"], data["IR_list"])
69+
block = Block(data["PC_start"], data["IR_list"])
70+
block_dict[pc] = block
71+
untaken = None
72+
taken = None
73+
if data["untaken"] != "NULL":
74+
if (data["untaken"] in pc_set):
75+
untaken = block_dict[data["untaken"]]
76+
else:
77+
untaken = print_graph_IR(data["untaken"])
78+
if data["taken"] != "NULL":
79+
if (data["taken"] in pc_set):
80+
taken = block_dict[data["taken"]]
81+
else:
82+
taken = print_graph_IR(data["taken"])
83+
block.branch_untaken = untaken
84+
block.branch_taken = taken
85+
return block
86+
87+
parser = argparse.ArgumentParser()
88+
parser.add_argument('filename', type=str,
89+
help='an integer for the accumulator')
90+
parser.add_argument('--start-address', type=str,
91+
help='start address for profiling data')
92+
parser.add_argument('--stop-address', type=str,
93+
help='stop address for profiling data')
94+
parser.add_argument('--graph-ir', type=str,
95+
help='visualize graph IR')
96+
args = parser.parse_args()
97+
98+
f = open(f'prof/{args.filename}.prof', 'r')
99+
fileds = f.readline()
100+
raw_datas = f.read().split("\n")
101+
profile_datas = []
102+
for data in raw_datas:
103+
tmp = data.split("|")
104+
if len(tmp) == 9:
105+
d = {
106+
"PC_start": tmp[0].strip(),
107+
"PC_end": tmp[1].strip(),
108+
"frequency": tmp[2].strip(),
109+
"hot": tmp[3].strip(),
110+
"backward": tmp[4].strip(),
111+
"loop": tmp[5].strip(),
112+
"untaken": tmp[6].strip(),
113+
"taken": tmp[7].strip(),
114+
"IR_list": tmp[8].strip(),
115+
}
116+
profile_datas.append(d)
117+
profile_dict[d["PC_start"]] = d;
118+
elif len(tmp) == 5:
119+
d = {
120+
"PC_start": tmp[0].strip(),
121+
"PC_end": tmp[1].strip(),
122+
"untaken": tmp[2].strip(),
123+
"taken": tmp[3].strip(),
124+
"IR_list": tmp[4].strip(),
125+
}
126+
profile_datas.append(d)
127+
profile_dict[d["PC_start"]] = d;
128+
129+
if args.start_address or args.stop_address:
130+
print_data = []
131+
start_address = 0
132+
stop_address = math.inf
133+
if args.start_address:
134+
start_address = int(args.start_address, 16)
135+
if args.stop_address:
136+
stop_address = int(args.stop_address, 16)
137+
for data in profile_datas:
138+
pc_start = int(data["PC_start"], 16)
139+
pc_end = int(data["PC_end"], 16)
140+
if pc_start >= start_address and pc_end <= stop_address:
141+
print_data.append(data)
142+
printTable(print_data)
143+
144+
if args.graph_ir:
145+
block = print_graph_IR(args.graph_ir)
146+
g = objviz(block)
147+
g.view() # render and show graphviz.files.Source object

0 commit comments

Comments
 (0)