From 9036809f656cf97d84ad5ac87bbbb91bb943019b Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 24 Apr 2024 09:16:18 -0700 Subject: [PATCH] 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 --- tools/sof-fw-boot-test.py | 132 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100755 tools/sof-fw-boot-test.py diff --git a/tools/sof-fw-boot-test.py b/tools/sof-fw-boot-test.py new file mode 100755 index 00000000..1c62dd78 --- /dev/null +++ b/tools/sof-fw-boot-test.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python3 + +import argparse +import os +import subprocess +import sys +import time +from pathlib import Path + +# define command line arguments +def parse_cmdline(): + 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(): + cmd_args = parse_cmdline() + + # Get firmware file path + fw_path = cmd_args["fw_path"] + full_fw_path = '/lib/firmware/' + fw_path + if not os.path.exists(full_fw_path): + print(f"Firmware path {fw_path} does not exist") + sys.exit(1) + + # Get firmware file name + fw_filename = cmd_args["firmware"] + + # check if the firmware binary exists + fw_fullname = '/lib/firmware/' + fw_path + '/' + fw_filename + if not os.path.isfile(fw_fullname): + print(f"Firmware file {fw_filename} does not exist") + sys.exit(1) + + 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} +==============================================================================""" + print(output) + + # set path to the depbugfs entries + debugfs_path = '/sys/kernel/debug/sof/dsp_ops' + if not os.path.exists(debugfs_path): + print(f"Debugfs path {debugfs_path} does not exist!") + sys.exit(1) + + # set the firmware filename & path + os.system('echo %s > %s/fw_filename' %(fw_filename, debugfs_path)) + os.system('echo %s > %s/fw_path' %(fw_path, debugfs_path)) + 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 with a timeout of 1 second + debugfs_entry = debugfs_path + '/dsp_power_state' + cmd = 'echo D3 > ' + debugfs_entry + subprocess.run(cmd, shell=True, check=True, timeout=1) + + file_path = Path(debugfs_entry) + with file_path.open('r') as file: + power_state = file.read(1024) + # check if the DSP is in D3 + if not power_state == 'D3': + print("Failed booting firmware. DSP is not in D3") + sys.exit(1) + + # unload current firmware + debugfs_entry = debugfs_path + '/unload_fw' + file_path = Path(debugfs_entry) + with file_path.open('w') as file: + file.write('1') + + # get current fw_state and continue to boot only if the current state is 'PREPARE' + debugfs_entry = debugfs_path + '/fw_state' + file_path = Path(debugfs_entry) + with file_path.open('r') as file: + fw_state = file.read(1024) + fw_state = fw_state.rstrip() + if not fw_state == 'PREPARE': + print(f"Cannot boot firmware boot from current state {fw_state}") + sys.exit(1) + + # load and boot firmware. Set a 2s timeout for firmware boot + debugfs_entry = debugfs_path + '/boot_fw' + cmd = 'echo 1 > ' + debugfs_entry + start = time.time() + proc = subprocess.run(cmd, shell=True, check=True, timeout=2, capture_output=True, text=True) + 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' + file_path = Path(debugfs_entry) + with file_path.open('r') as file: + fw_state = file.read(1024) + fw_state = fw_state.rstrip() + if not fw_state == 'COMPLETE': + print(f"Invalid firmware boot status: {fw_state}") + sys.exit(1) + + print(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 +==============================================================================""" + print(output) + +if __name__=="__main__": + main()