-
Notifications
You must be signed in to change notification settings - Fork 46
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tools: Add a new script for firmware boot stress testing
This requires the kernel changes that expose the debugfs entries for executing the different DSP ops and reading the current DSP firmware and power states. The script takes the firmware name and the path as inputs along with the number of iterations of firmware boot. It takes care of putting the DSP in the D3 state and unloading any existing firmware before starting firmware boot. Signed-off-by: Ranjani Sridharan <[email protected]>
- Loading branch information
Showing
1 changed file
with
118 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
#!/usr/bin/env python3 | ||
|
||
"""Module to stress test firmware boot""" | ||
|
||
import argparse | ||
import logging | ||
import sys | ||
import time | ||
|
||
# define command line arguments | ||
def parse_cmdline(): | ||
"""Function to parse the command line arguments""" | ||
parser = argparse.ArgumentParser(add_help=True, formatter_class=argparse.RawTextHelpFormatter, | ||
description='A script for stress testing firmware boot') | ||
parser.add_argument('-i', '--iter', type=int, default=100, | ||
help="number of firmware boot iterations") | ||
parser.add_argument('-f', '--firmware', type=str, required=True, help='firmware filename') | ||
parser.add_argument('-p', '--fw_path', type=str, required=True, | ||
help='path to the firmware file relative to /lib/firmware') | ||
return vars(parser.parse_args()) | ||
|
||
def main(): | ||
"""Main function for stress testing""" | ||
logging.basicConfig(level=logging.INFO, format='%(message)s') | ||
cmd_args = parse_cmdline() | ||
|
||
# Get firmware file path | ||
fw_path = cmd_args['fw_path'] | ||
|
||
# Get firmware file name | ||
fw_filename = cmd_args['firmware'] | ||
|
||
num_iter = cmd_args['iter'] | ||
output = f"""============================================================================== | ||
Starting boot stress test with: | ||
Firmware filename: {fw_filename} | ||
Path to firmware file: {fw_path} | ||
Number of Iterations: {num_iter} | ||
==============================================================================""" | ||
logging.info(output) | ||
|
||
# set path to the depbugfs entries | ||
debugfs_path = '/sys/kernel/debug/sof/dsp_ops' | ||
|
||
# set the firmware filename & path | ||
with open(debugfs_path + '/fw_filename', 'w', encoding="utf8") as dbgf: | ||
dbgf.write(fw_filename + "\n") | ||
with open(debugfs_path + '/fw_path', 'w', encoding="utf8") as dbgf: | ||
dbgf.write(fw_path + "\n") | ||
|
||
total_boot_time_ms = 0 | ||
min_boot_time_ms = sys.maxsize | ||
max_boot_time_ms = 0 | ||
|
||
for i in range(num_iter): | ||
# put the DSP in D3 | ||
debugfs_entry = debugfs_path + '/dsp_power_state' | ||
with open(debugfs_entry, 'w', encoding="utf8") as dbgf: | ||
dbgf.write("D3\n") | ||
|
||
# check if the DSP is in D3 | ||
with open(debugfs_entry, 'r', encoding="utf8") as dbgf: | ||
power_state = dbgf.read(1024) | ||
if not power_state == 'D3': | ||
sys.exit("Failed booting firmware. DSP is not in D3") | ||
|
||
# unload current firmware | ||
debugfs_entry = debugfs_path + '/unload_fw' | ||
with open(debugfs_entry, 'w', encoding="utf8") as dbgf: | ||
dbgf.write("1\n") | ||
|
||
# get current fw_state and continue to boot only if the current state is 'PREPARE' | ||
debugfs_entry = debugfs_path + '/fw_state' | ||
with open(debugfs_entry, 'r', encoding="utf8") as dbgf: | ||
fw_state = dbgf.read(1024) | ||
fw_state = fw_state.rstrip() | ||
if not fw_state == 'PREPARE': | ||
sys.exit("Cannot boot firmware boot from current state {fw_state}") | ||
|
||
# load and boot firmware | ||
debugfs_entry = debugfs_path + '/boot_fw' | ||
start = time.time() | ||
with open(debugfs_entry, 'w', encoding="utf8") as dbgf: | ||
dbgf.write("1\n") | ||
end = time.time() | ||
|
||
# calculate boot time | ||
boot_time_ms = round((end - start) * 1000, 3) | ||
total_boot_time_ms += boot_time_ms | ||
if boot_time_ms < min_boot_time_ms: | ||
min_boot_time_ms = boot_time_ms | ||
if boot_time_ms > max_boot_time_ms: | ||
max_boot_time_ms = boot_time_ms | ||
|
||
# get current fw_state to make sure the state is COMPLETE | ||
debugfs_entry = debugfs_path + '/fw_state' | ||
with open(debugfs_entry, 'r', encoding="utf8") as dbgf: | ||
fw_state = dbgf.read(1024) | ||
fw_state = fw_state.rstrip() | ||
if not fw_state == 'COMPLETE': | ||
sys.exit(f"Firmware boot failed at iteration {i}") | ||
|
||
logging.info(f"Firmware boot iteration {i} completed in {boot_time_ms} ms") | ||
|
||
# print firmware boot stats | ||
avg_boot_time_ms = total_boot_time_ms / num_iter | ||
output = f"""============================================================================== | ||
Finished boot stress test with: | ||
Firmware filename: {fw_filename} | ||
Path to firmware file: {fw_path} | ||
Average firmware boot time after {num_iter} iterations: {avg_boot_time_ms} ms | ||
Maximum firmware boot time {max_boot_time_ms} ms | ||
Minimum firmware boot time {min_boot_time_ms} ms | ||
==============================================================================""" | ||
logging.info(output) | ||
|
||
if __name__=="__main__": | ||
main() |