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()