Skip to content

Commit 87054e9

Browse files
abejgonzalezSriram Sridhar
authored andcommitted
Config finder make target (#1328)
* Add config-finder make target * Add recursive functionality * Add config finder to CI * Workaround bash argument limit failures
1 parent 538ac6a commit 87054e9

File tree

4 files changed

+110
-1
lines changed

4 files changed

+110
-1
lines changed

.github/workflows/chipyard-full-flow.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,19 @@ jobs:
8181
export MAKEFLAGS="-j32"
8282
./build-setup.sh -f
8383
84+
run-cfg-finder:
85+
name: run-cfg-finder
86+
needs: [setup-repo]
87+
runs-on: ferry
88+
steps:
89+
- name: Run config finder
90+
run: |
91+
cd ${{ env.REMOTE_WORK_DIR }}
92+
eval "$(conda shell.bash hook)"
93+
source env.sh
94+
cd sims/verilator
95+
make find-config-fragments
96+
8497
run-tutorial:
8598
name: run-tutorial
8699
needs: [setup-repo]

common.mk

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ HELP_COMMANDS += \
4848
" run-tests = run all assembly and benchmark tests" \
4949
" launch-sbt = start sbt terminal" \
5050
" {shutdown,start}-sbt-server = shutdown or start sbt server if using ENABLE_SBT_THIN_CLIENT" \
51+
" find-config-fragments = list all config. fragments and their locations (recursive up to CONFIG_FRAG_LEVELS=$(CONFIG_FRAG_LEVELS))"
5152

5253
#########################################################################################
5354
# include additional subproject make fragments
@@ -388,8 +389,21 @@ start-sbt-server: check-thin-client
388389
cd $(base_dir) && $(SBT) "exit"
389390

390391
#########################################################################################
391-
# print help text
392+
# print help text (and other help)
392393
#########################################################################################
394+
# helper to add newlines (avoid bash argument too long)
395+
define \n
396+
397+
398+
endef
399+
400+
CONFIG_FRAG_LEVELS ?= 3
401+
.PHONY: find-config-fragments
402+
find-config-fragments: $(SCALA_SOURCES)
403+
rm -rf /tmp/scala_files.f
404+
@$(foreach file,$(SCALA_SOURCES),echo $(file) >> /tmp/scala_files.f${\n})
405+
$(base_dir)/scripts/config-finder.py -l $(CONFIG_FRAG_LEVELS) /tmp/scala_files.f
406+
393407
.PHONY: help
394408
help:
395409
@for line in $(HELP_LINES); do echo "$$line"; done

docs/Customization/Keys-Traits-Configs.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,9 @@ We can use this config fragment when composing our configs.
7575

7676
.. note::
7777
Readers who want more information on the configuration system may be interested in reading :ref:`cdes`.
78+
79+
Chipyard Config Fragments
80+
-------------------------
81+
82+
For discoverability, users can run ``make find-config-fragments`` to see a list of config. fragments
83+
(config. fragments that match "class NAME extends CONFIG\n" on a single line and a subset of their children) and their file path in a fully initialized Chipyard repository.

scripts/config-finder.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#!/usr/bin/env python3
2+
3+
import argparse
4+
import subprocess
5+
from collections import defaultdict
6+
import re
7+
from copy import deepcopy
8+
import os
9+
10+
cy_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
11+
12+
# from https://gist.github.com/angstwad/bf22d1822c38a92ec0a9
13+
def deep_merge(a: dict, b: dict) -> dict:
14+
"""Merge two dicts and return a singular dict"""
15+
result = deepcopy(a)
16+
for bk, bv in b.items():
17+
av = result.get(bk)
18+
if isinstance(av, dict) and isinstance(bv, dict):
19+
result[bk] = deep_merge(av, bv)
20+
else:
21+
result[bk] = deepcopy(bv)
22+
return result
23+
24+
if __name__ == "__main__":
25+
parser = argparse.ArgumentParser(description='Pretty print all configs given a filelist of scala files')
26+
parser.add_argument('FILE', type=str, help='Filelist of scala files to search within')
27+
parser.add_argument('-l', '--levels', default=0, type=int, help='Number of levels to recursively look for configs')
28+
args = parser.parse_args()
29+
30+
files = []
31+
with open(args.FILE, 'r') as f:
32+
files = f.read().splitlines()
33+
34+
cmd = ['grep', '-o', r"class \+.* \+extends \+Config"] + files
35+
r = subprocess.run(cmd, check=True, capture_output=True)
36+
37+
base_file_path_dict = defaultdict(list)
38+
for l in r.stdout.decode("UTF-8").splitlines():
39+
match = re.match(r"^(.*):class +([a-zA-Z_$][a-zA-Z\d_$]*).* +extends", l)
40+
if match:
41+
base_file_path_dict[match.group(1)].append(match.group(2))
42+
43+
levels = []
44+
for level in range(args.levels):
45+
if level == 0:
46+
# use the base
47+
dict_to_use = base_file_path_dict
48+
else:
49+
# use the level-1 dict
50+
assert len(levels) > 0
51+
dict_to_use = levels[-1]
52+
53+
file_path_dict = defaultdict(list)
54+
55+
for configs in dict_to_use.values():
56+
for config in configs:
57+
cmd = ['grep', '-o', r"class \+.* \+extends \+" + f"{config}"] + files
58+
r = subprocess.run(cmd, capture_output=True)
59+
60+
for l in r.stdout.decode("UTF-8").splitlines():
61+
match = re.match(r"^(.*):class +([a-zA-Z_$][a-zA-Z\d_$]*).* +extends", l)
62+
if match:
63+
file_path_dict[match.group(1)].append(match.group(2))
64+
65+
levels.append(file_path_dict)
66+
67+
final_dict = base_file_path_dict
68+
for dct in levels:
69+
final_dict = deep_merge(final_dict, dct)
70+
71+
print(f"Finding all one-line config. fragments (up to {args.levels} levels)\n")
72+
for k, v in final_dict.items():
73+
print(f"{k.replace(cy_path, 'chipyard')}:")
74+
for e in v:
75+
print(f" {e}")
76+
print("")

0 commit comments

Comments
 (0)