diff --git a/tools/sof-fw-boot-test.py b/tools/sof-fw-boot-test.py new file mode 100755 index 00000000..9a5bd1f5 --- /dev/null +++ b/tools/sof-fw-boot-test.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python3 + +"""Module to stress test firmware boot""" + +import argparse +import logging +import sys +import time + +logging.basicConfig(level=logging.INFO, format="%(message)s") + +# set path to the depbugfs entries +debugfs_path = "/sys/kernel/debug/sof/dsp_ops" + +# 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 boot_fw(): + """Power down the DSP and boot firmware using previously set firmware path and filename""" + # 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 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 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() + + # get current fw_state + 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() + + # calculate boot time + boot_time_ms = round((end - start) * 1000, 3) + + return boot_time_ms, fw_state + + +def main(): + """Main function for stress testing""" + 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 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): + boot_time_ms, fw_state = boot_fw() + # check if fw_state is COMPLETE + if fw_state != "COMPLETE": + sys.exit(f"Firmware boot failed at iteration {i}") + + total_boot_time_ms += boot_time_ms + min_boot_time_ms = min(min_boot_time_ms, boot_time_ms) + max_boot_time_ms = max(max_boot_time_ms, boot_time_ms) + + 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"""============================================================================== + Average firmware boot time {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()