Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Store simulation result file, return sim state from run #270

Merged
merged 30 commits into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a8e6f77
Add statement to dump simulation state to file
chetanyagoyal Nov 9, 2023
33956c5
Create prePEX_sim_result
chetanyagoyal Nov 9, 2023
33bff42
Update test_simulation.py
chetanyagoyal Nov 9, 2023
f7a5a8b
Update test_simulation.py
chetanyagoyal Nov 9, 2023
683c198
Update test_simulation.py
chetanyagoyal Nov 9, 2023
5786c54
Update test_simulation.py
chetanyagoyal Nov 9, 2023
211fec8
return sim_state dict instead of num_configs
chetanyagoyal Nov 9, 2023
539609c
fix return variables and dump sim state
chetanyagoyal Nov 9, 2023
21abaaf
return dictionary of simulation state instead of null
chetanyagoyal Nov 9, 2023
afe5a03
Update test_simulation.py to account for changes to return types
chetanyagoyal Nov 9, 2023
4e69c4b
Merge branch 'idea-fasoc:main' into main
chetanyagoyal Nov 9, 2023
09d7d49
Merge branch 'idea-fasoc:main' into main
chetanyagoyal Nov 11, 2023
368cb35
Change return type from int to dict
chetanyagoyal Nov 11, 2023
f2209fe
Update simulation_run.py
chetanyagoyal Nov 11, 2023
4959c07
Remove whitespace
chetanyagoyal Nov 11, 2023
6c4812e
Merge branch 'idea-fasoc:main' into main
chetanyagoyal Nov 15, 2023
36dfb27
commit latest changes to make sims work
chetanyagoyal Nov 15, 2023
32244e4
update ngspice version check statement
chetanyagoyal Nov 15, 2023
6ee4229
revise function to include ngspice version here
chetanyagoyal Nov 15, 2023
da4ad4e
Update parse_rpt.py
chetanyagoyal Nov 15, 2023
2b573cd
fix errors
chetanyagoyal Nov 15, 2023
604967d
Format file
chetanyagoyal Nov 15, 2023
7449c31
Fix indent errors in file
chetanyagoyal Nov 15, 2023
ac0f657
Merge branch 'idea-fasoc:main' into main
chetanyagoyal Nov 30, 2023
b869fe2
Separate ngspice version and result file check
chetanyagoyal Nov 30, 2023
f3abf5e
Merge branch 'idea-fasoc:main' into main
chetanyagoyal Dec 5, 2023
35dc71d
change dir structure, make new job for temp-sense sims
chetanyagoyal Dec 5, 2023
1116b6b
add new comparison function for sim results
chetanyagoyal Dec 5, 2023
548f577
Merge branch 'idea-fasoc:main' into main
chetanyagoyal Dec 6, 2023
0a8fcad
revert change to ngspice clone command
chetanyagoyal Dec 8, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Temp Frequency Power Error
-20.0 129.13698399282515 0.0001395741 0.0
0.0 812.2374949945864 0.000216328 -1.2889568113520866
20.0 3726.282213709738 0.000308484 -1.905159990787503
40.0 13548.077588756503 0.0004135831 -2.0993284842505844
60.0 40753.5328218765 0.0005294722 -1.884757884614622
80.0 104972.69292852504 0.0006544346 -1.288956811352108
100.0 238491.19025467758 0.0007871842 -0.3737931886616934
53 changes: 50 additions & 3 deletions .github/scripts/parse_rpt.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,12 @@
import json
import os
import re, subprocess
import warnings

sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from common.get_ngspice_version import check_ngspice_version
from common.check_gen_files import check_gen_files
from common.check_sim_results import compare_files

sys.stdout.flush()

Expand All @@ -45,6 +49,8 @@
elif len(sys.argv) > 1:
if sys.argv[1] == 'sky130hvl_ldo':
_generator_is['sky130hvl_ldo'] = 1
elif sys.argv[1] == 'sky130hd_temp_full':
_generator_is['sky130hd_temp'] = 1
else:
_generator_is['sky130XX_cryo'] = 1

Expand Down Expand Up @@ -102,11 +108,52 @@

## Result File Check
if _generator_is['sky130hvl_ldo']:
json_filename = "spec.json"
json_filename = "spec.json"
else:
json_filename = "test.json"
json_filename = "test.json"

if check_gen_files(json_filename, _generator_is, cryo_library):
print("Flow check is clean!")
print("Flow check is clean!")
else:
print("Flow check failed!")

if len(sys.argv) > 1 and sys.argv[1] == "sky130hd_temp_full":
sim_state_filename = "work/sim_state_file.txt"
result_filename = "work/prePEX_sim_result"
template_filename = "../../../.github/scripts/expected_sim_outputs/temp-sense-gen/prePEX_sim_result"
max_allowable_error = 0.5

### Generated result file check against stored template
ngspice_version_flag = check_ngspice_version()
file_comp_flag = compare_files(template_filename, result_filename, max_allowable_error)

if ngspice_version_flag == 1 and file_comp_flag == 0:
raise ValueError("Ngspice version matches but sim results do not...sims failed!")
elif ngspice_version_flag == 0 and file_comp_flag == 0:
warnings.warn("The ngspice version does not match, "
"simulation results might not match! "
"Please contact a maintainer of the repo!", DeprecationWarning)
elif ngspice_version_flag == 0 and file_comp_flag == 1:
warnings.warn("The ngspice version does not match!", DeprecationWarning)

### Number of failed simulations returned from simulation state check
sim_state = json.load(open("work/sim_state_file.txt"))
if sim_state["failed_sims"] != 0:
raise ValueError("Simulations failed: Non zero failed simulations!")

### Generated file check
for folder_num in range(1, sim_state["completed_sims"] + 1):
dir_path = r'simulations/run/'
pex_path = os.listdir(dir_path)

file_name = "simulations/run/" + str(pex_path[0]) + "/" + str(folder_num) + "/"
param_file = file_name + "parameters.txt"
log_file = file_name + "sim_" + str(folder_num) + ".log"
spice_file = file_name + "sim_" + str(folder_num) + ".sp"

if os.path.exists(log_file) and os.path.exists(log_file) and os.path.exists(spice_file):
pass
else:
raise ValueError("Simulations failed: required number of run folders do not exist!")

print("Simulations are clean!")
23 changes: 22 additions & 1 deletion .github/workflows/tempSense_sky130hd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
- name: Checkout repo
uses: actions/checkout@v2

- name: Test sky130hd Temp sensor
- name: Test sky130hd temperature sensor
env:
IMAGE_NAME: msaligane/openfasoc:stable
run: |
Expand All @@ -44,3 +44,24 @@ jobs:
" && exit_code=$? | tee -a file.log
if [ $? -ne 0 ]; then exit 1; fi
if grep "\[ERROR\]" file.log; then exit 1; else exit 0; fi

- name: Test sky130hd temperature sensor simulations
env:
IMAGE_NAME: msaligane/openfasoc:stable
run: |
cd $GITHUB_WORKSPACE
touch sim_file.log
docker run --rm \
-v $PWD:$PWD\
-w $PWD\
$IMAGE_NAME\
bash -c "\
cp ./.github/scripts/parse_rpt.py ./openfasoc/generators/temp-sense-gen/. &&\
pip3 install -r requirements.txt &&\
cd ./openfasoc/generators/temp-sense-gen &&\
make clean &&\
make sky130hd_temp_full &&\
python3 parse_rpt.py sky130hd_temp_full
" && exit_code=$? | tee -a file.log
if [ $? -ne 0 ]; then exit 1; fi
if grep "\[ERROR\]" file.log; then exit 1; else exit 0; fi
2 changes: 1 addition & 1 deletion dependencies.sh
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ source ~/.bashrc
if cat /etc/os-release | grep "ubuntu" >> /dev/null
then
apt install bison flex libx11-dev libx11-6 libxaw7-dev libreadline6-dev autoconf libtool automake -y
git clone http://git.code.sf.net/p/ngspice/ngspice
git clone https://git.code.sf.net/p/ngspice/ngspice
currentver="$(lsb_release -rs)"
requiredver="22.04"
if [ $currentver == $requiredver ]
Expand Down
3 changes: 3 additions & 0 deletions openfasoc/generators/common/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,8 @@
1. `check_gen_files(parameters: json_filename, is_tempsense)`: Used to check if the various files that should be generated by the flow are present in their required directories.
- `common.check_gen_extensions`
1. Stores the extensions of the files generated by the flow.
- `common.check_sim_results`
1. `compare_files(parameters: template_filename, result_filename, max_allowable error) -> int` Checks if the generated frequency, power and error result file values are within the maximum
allowable error from those in the template file. Returns 1 for successful check, else returns 0
See individual function documentation for more information on a particular function.
"""
39 changes: 39 additions & 0 deletions openfasoc/generators/common/check_sim_results.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
def compare_files(template_file, result_file, max_allowable_error) -> int:
"""Checks if the generated simulation result file matches with
the stored template file.

Args:
- 'template_file' (string): The stored template file
- 'result_file' (string): The result file generated by the simulations
- 'max_allowable_error' (float): The maximum allowable difference (percent error) in
the values in both files

Returns:
- 'int': Returns 1 if the differences in readings (if any) is less than the 'max_allowable_error
else returns 0
"""
with open(template_file, 'r') as template, open(result_file, 'r') as result:
next(template)
next(result)

for template_line, result_line in zip(template, result):
template_data = [float(val) for val in template_line.split()]
result_data = [float(val) for val in result_line.split()]

if template_data[1] != 0.0:
freq_diff = (abs(template_data[1] - result_data[1]) / template_data[1]) * 100
else:
freq_diff = (abs(template_data[1] - result_data[1])) * 100
if template_data[2] != 0.0:
power_diff = (abs(template_data[2] - result_data[2]) / template_data[2]) * 100
else:
power_diff = (abs(template_data[2] - result_data[2])) * 100
if template_data[3] != 0.0:
error_diff = (abs(template_data[3] - result_data[3]) / template_data[3]) * 100
else:
error_diff = (abs(template_data[3] - result_data[3])) * 100

if freq_diff <= max_allowable_error and power_diff <= max_allowable_error and error_diff <= max_allowable_error:
return 1
else:
return 0
20 changes: 20 additions & 0 deletions openfasoc/generators/common/get_ngspice_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import subprocess
import re

def check_ngspice_version() -> int:
last_known_version = "41+"
result = subprocess.run(["ngspice", "--version"], capture_output=True, text=True)

if result.returncode == 0:
data = result.stdout.strip()
match = re.search(r'ngspice-(\S+)', data)

if match:
ngspice_version = match.group(1)
return ngspice_version == last_known_version
else:
print("Error parsing ngspice version.")
else:
print("Error getting ngspice version:", result.stderr)

return 0
8 changes: 4 additions & 4 deletions openfasoc/generators/common/simulation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def run_simulations(
sim_tool: str = "ngspice",
num_concurrent_sims: int = 4,
netlist_path: str = "netlist.sp"
) -> int:
) -> dict:
"""Runs SPICE simulations.

Generates configurations of all combinations of the given `parameters` and simulates each case. The testbench SPICE file, configuration parameters, and the output for each run are generated in the `simulation_dir/runs_dir` directory.
Expand Down Expand Up @@ -73,7 +73,7 @@ def run_simulations(
- `num_concurrent_sims` (int = 4): The maximum number of concurrent simulations.
- `netlist_path` (str = "netlist.sp"): Path to the SPICE netlist of the design to be simulated.

Returns (int): The number of simulations run.
Returns : A dictionary containing the number of ongoing (ideally 0), completed and failed simulations.
"""

runs_dir_path = path.join(simulation_dir, runs_dir)
Expand All @@ -94,11 +94,11 @@ def run_simulations(
print(f"Number of configurations: {config_number}")
print(f"Number of concurrent simulations: {num_concurrent_sims}")

_run_simulations(
sim_state = _run_simulations(
num_configs=config_number,
num_concurrent_sims=num_concurrent_sims,
sim_tool=sim_tool,
runs_dir_path=runs_dir_path
)

return config_number
return sim_state
5 changes: 4 additions & 1 deletion openfasoc/generators/common/simulation/simulation_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ def _run_simulations(
- `num_concurrent_sims` (int): The maximum number of concurrent simulations.
- `sim_tool` (str): Path to the directory in which the simulation runs will be generated.
- `runs_dir_path` (str): Path to the directory in which the simulation runs will be generated.

Returns: `simulation_state`, the number of ongoing, completed and failed sims.
"""

simulation_state = {
Expand Down Expand Up @@ -68,6 +70,7 @@ def thread_on_exit(exit_status: int, state=simulation_state):
time.sleep(1)

_print_progress(num_configs, simulation_state['completed_sims'], simulation_state['failed_sims'], start_time, end='\n')
return simulation_state

def _run_config(
sim_tool: str,
Expand Down Expand Up @@ -148,4 +151,4 @@ def _threaded_run(
except:
return on_exit(1)

on_exit(0)
on_exit(0)
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ vVSS VSS 0 dc

c0 lc_out 0 1f

.if (temp_var <= 20)
.TRAN 1u 'sim_end'
.else
.TRAN 10n 'sim_end'
.endif

.meas tran period TRIG v(lc_out) td=10p val=1.0 rise=2
+ TARG v(lc_out) td=10p val=1.0 rise=3
Expand Down
12 changes: 8 additions & 4 deletions openfasoc/generators/temp-sense-gen/tools/simulation.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import os
import os, json
import re
import shutil
import sys
Expand Down Expand Up @@ -57,7 +57,7 @@ def generate_runs(

update_netlist(srcNetlist, dstNetlist, jsonConfig["simMode"])

num_simulations = run_simulations(
sim_state = run_simulations(
parameters={
'temp': {'start': tempStart, 'end': tempStop, 'step': tempStep},
'model_file': model_file,
Expand All @@ -75,7 +75,7 @@ def generate_runs(

# Calculating simulation results and error
with open(os.path.join(runDirPath, 'sim_output'), 'w') as sim_output_file:
for i in range(num_simulations):
for i in range(sim_state["completed_sims"]):
log_file_path = os.path.join(runDirPath, f"{i + 1}", f"sim_{i + 1}.log")
sim_results = get_sim_results(open(log_file_path, "r").read())

Expand All @@ -86,6 +86,10 @@ def generate_runs(
error_data = calculate_sim_error(sim_output_lines=sim_output_file.readlines())
all_result_file.write("\n".join(error_data))

# dump final simulation state to log file called sim_state_file
with open(spiceDir + "/sim_state_file.txt", 'w') as sim_state_file:
json.dump(sim_state, sim_state_file)
chetanyagoyal marked this conversation as resolved.
Show resolved Hide resolved

return runDirPath

def matchNetlistCell(cell_instantiation):
Expand Down Expand Up @@ -169,4 +173,4 @@ def update_netlist(srcNetlist, dstNetlist, simMode):
"""
netlist = netlist.replace(toplevel_pinout.split(" ", 2)[2], standardized_pinout)
with open(dstNetlist, "w") as wf:
wf.write(netlist)
wf.write(netlist)
6 changes: 3 additions & 3 deletions tests/common_api/test_simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def run_before_and_after_tests():
rmtree(RUNS_DIR)

def test_simulations():
num_runs = run_simulations(
sim_state = run_simulations(
parameters=PARAMS,
platform = "",
simulation_dir = TEST_SIMULATION_DIR,
Expand All @@ -69,7 +69,7 @@ def test_simulations():
)

# Check if the correct number of configurations are generated
assert num_runs == EXPECTED_NUM_CONFIGS, "The number of runs does not match the expected number."
assert sim_state["completed_sims"] == EXPECTED_NUM_CONFIGS, "The number of runs does not match the expected number."
assert len(os.listdir(RUNS_DIR)) == EXPECTED_NUM_CONFIGS, "The number of generated configurations does not match the expected number."


Expand Down Expand Up @@ -99,4 +99,4 @@ def test_simulations():
irms_value = get_value(log_file_text, 'irms')

assert vrms_value != "NOT_FOUND", f"`vrms` value not found in the simulation output for config #{i}"
assert irms_value != "NOT_FOUND", f"`irms` value not found in the simulation output for config #{i}"
assert irms_value != "NOT_FOUND", f"`irms` value not found in the simulation output for config #{i}"
Loading