Skip to content

Commit 94af63b

Browse files
committed
autotuner: add unit tests for parse_flow_variables and parse_tunable_variables
Signed-off-by: rohithsiddi <rohithsiddi7@gmail.com>
1 parent 8977154 commit 94af63b

2 files changed

Lines changed: 156 additions & 0 deletions

File tree

flow/test/test_autotuner.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ cd ../
1313
./tools/AutoTuner/installer.sh
1414
. ./tools/AutoTuner/setup.sh
1515

16+
echo "Running Autotuner utility tests"
17+
python3 -m unittest tools.AutoTuner.test.test_utils
18+
1619
echo "Running Autotuner smoke tune test"
1720
python3 -m unittest tools.AutoTuner.test.smoke_test_tune.${PLATFORM_WITHOUT_DASHES}TuneSmokeTest.test_tune
1821

tools/AutoTuner/test/test_utils.py

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
#############################################################################
2+
##
3+
## BSD 3-Clause License
4+
##
5+
## Copyright (c) 2026, Precision Innovations Inc.
6+
## All rights reserved.
7+
##
8+
## Redistribution and use in source and binary forms, with or without
9+
## modification, are permitted provided that the following conditions are met:
10+
##
11+
## * Redistributions of source code must retain the above copyright notice, this
12+
## list of conditions and the following disclaimer.
13+
##
14+
## * Redistributions in binary form must reproduce the above copyright notice,
15+
## this list of conditions and the following disclaimer in the documentation
16+
## and/or other materials provided with the distribution.
17+
##
18+
## * Neither the name of the copyright holder nor the names of its
19+
## contributors may be used to endorse or promote products derived from
20+
## this software without specific prior written permission.
21+
##
22+
## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23+
## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24+
## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25+
## ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
26+
## LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27+
## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28+
## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29+
## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30+
## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31+
## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32+
## POSSIBILITY OF SUCH DAMAGE.
33+
##
34+
###############################################################################
35+
36+
import os
37+
import sys
38+
import tempfile
39+
import unittest
40+
from io import StringIO
41+
from types import SimpleNamespace
42+
from unittest.mock import mock_open, patch
43+
44+
cur_dir = os.path.dirname(os.path.abspath(__file__))
45+
src_dir = os.path.join(cur_dir, "../src")
46+
sys.path.insert(0, src_dir)
47+
48+
from autotuner import utils
49+
50+
51+
class ParseFlowVariablesTest(unittest.TestCase):
52+
def setUp(self):
53+
self.tmp_dir = tempfile.TemporaryDirectory()
54+
self.flow_dir = os.path.join(self.tmp_dir.name, "flow")
55+
self.scripts_dir = os.path.join(self.flow_dir, "scripts")
56+
os.makedirs(self.scripts_dir)
57+
58+
def tearDown(self):
59+
self.tmp_dir.cleanup()
60+
61+
def _write_file(self, path, contents):
62+
with open(path, "w") as file:
63+
file.write(contents)
64+
65+
def test_parse_flow_variables_from_scripts_and_vars_tcl(self):
66+
self._write_file(
67+
os.path.join(self.scripts_dir, "floorplan.tcl"),
68+
"""
69+
set util $::env(core_utilization)
70+
set margin $env(CORE_MARGIN)
71+
""",
72+
)
73+
self._write_file(
74+
os.path.join(self.scripts_dir, "route.tcl"),
75+
"""
76+
if {$::env(FASTROUTE_TCL) != ""} {
77+
puts $::env(FASTROUTE_TCL)
78+
}
79+
""",
80+
)
81+
self._write_file(
82+
os.path.join(self.flow_dir, "vars.tcl"),
83+
"""
84+
set ::env(PLACE_DENSITY) 0.7
85+
""",
86+
)
87+
88+
with patch.object(
89+
utils.subprocess,
90+
"run",
91+
return_value=SimpleNamespace(returncode=0),
92+
) as run:
93+
variables = utils.parse_flow_variables(self.tmp_dir.name, "sky130hd")
94+
95+
run.assert_called_once_with(
96+
["make", "-C", self.flow_dir, "vars", "PLATFORM=sky130hd"],
97+
capture_output=True,
98+
)
99+
self.assertEqual(
100+
variables,
101+
{
102+
"CORE_UTILIZATION",
103+
"CORE_MARGIN",
104+
"FASTROUTE_TCL",
105+
"PLACE_DENSITY",
106+
},
107+
)
108+
109+
def test_parse_flow_variables_exits_when_make_fails(self):
110+
with patch.object(
111+
utils.subprocess,
112+
"run",
113+
return_value=SimpleNamespace(returncode=2),
114+
):
115+
with patch("sys.stdout", new=StringIO()) as stdout:
116+
with self.assertRaises(SystemExit):
117+
utils.parse_flow_variables(self.tmp_dir.name, "sky130hd")
118+
119+
self.assertIn("[ERROR TUN-0018]", stdout.getvalue())
120+
121+
def test_parse_flow_variables_exits_when_vars_tcl_is_missing(self):
122+
with patch.object(
123+
utils.subprocess,
124+
"run",
125+
return_value=SimpleNamespace(returncode=0),
126+
):
127+
with patch("sys.stdout", new=StringIO()) as stdout:
128+
with self.assertRaises(SystemExit):
129+
utils.parse_flow_variables(self.tmp_dir.name, "sky130hd")
130+
131+
self.assertIn("[ERROR TUN-0019]", stdout.getvalue())
132+
133+
134+
class ParseTunableVariablesTest(unittest.TestCase):
135+
def test_parse_tunable_variables_returns_only_tunable_keys(self):
136+
variables_yaml = {
137+
"CORE_UTILIZATION": {"tunable": 1},
138+
"PLACE_DENSITY": {"tunable": 1},
139+
"GENERATE_ARTIFACTS_ON_FAILURE": {"default": 0},
140+
"DETAILED_METRICS": {"tunable": 0},
141+
}
142+
143+
with patch("builtins.open", mock_open(read_data="unused")) as open_mock:
144+
with patch.object(utils.yaml, "safe_load", return_value=variables_yaml):
145+
variables = utils.parse_tunable_variables()
146+
147+
open_mock.assert_called_once()
148+
self.assertEqual(variables, {"CORE_UTILIZATION", "PLACE_DENSITY"})
149+
self.assertIsInstance(variables, set)
150+
151+
152+
if __name__ == "__main__":
153+
unittest.main()

0 commit comments

Comments
 (0)