diff --git a/case-lib/hijack.sh b/case-lib/hijack.sh index 6f14e954..3090af26 100644 --- a/case-lib/hijack.sh +++ b/case-lib/hijack.sh @@ -14,6 +14,10 @@ function func_exit_handler() func_lib_check_and_disable_pipewire + if [ "$RUN_SOCWATCH" == true ]; then + unload_socwatch + fi + # call trace if [ "$exit_status" -ne 0 ] ; then dloge "Starting ${FUNCNAME[0]}(), exit status=$exit_status, FUNCNAME stack:" diff --git a/case-lib/lib.sh b/case-lib/lib.sh index 15d122ba..b8cf7301 100644 --- a/case-lib/lib.sh +++ b/case-lib/lib.sh @@ -87,6 +87,10 @@ start_test() func_lib_enable_pipewire fi + if [ "$RUN_SOCWATCH" == true ]; then + load_socwatch + fi + if is_subtest; then return 0 fi @@ -1599,3 +1603,46 @@ analyze_mixed_sound() return 1 fi } + +# Generates s 2-channels .mp3 file for testing +# Arguments: +# 1 - output filename +# 2 - duration of the soundfile in seconds +# 3 - number of channels +generate_mp3_file() +{ + mkdir -p "$HOME/Music" + ffmpeg -f lavfi -i "sine=frequency=1000:duration=$2" -ac "$3" "$1" +} + +# Load socwatch and check if module was loaded correctly +load_socwatch() +{ + sudo bash "$SOCWATCH_PATH"/drivers/insmod-socwatch || true + lsmod | grep -q socwatch || die "Socwatch is not loaded" +} + +unload_socwatch() +{ + sudo bash "$SOCWATCH_PATH"/drivers/rmmod-socwatch +} + +# Run any command with socwatch +# Arguments: +# 1 - socwatch output report filename +# 2 - command you want to run with socwatch (with arguments) +run_with_socwatch() +{ + if [ -z "$SOCWATCH_PATH" ]; then + die "SOCWATCH_PATH not set" + fi + + local output_file="$1" + shift + + ( set -x + sudo "$SOCWATCH_PATH"/socwatch -m -f sys -f cpu -f cpu-hw -f pcie \ + -f hw-cpu-cstate -f pcd-slps0 -f tcss-state -f tcss -f pcie-lpm -n 200 \ + -r json -o "$output_file" -p "$@") || + die "socwatch returned $?" +} diff --git a/test-case/residency-time-test.sh b/test-case/residency-time-test.sh index 71f5738b..b3837052 100755 --- a/test-case/residency-time-test.sh +++ b/test-case/residency-time-test.sh @@ -137,10 +137,6 @@ load_modules() run_socwatch_tests() { - # load socwatch module, if the module is loaded, go ahead with the testing - sudo bash "$SOCWATCH_PATH"/drivers/insmod-socwatch || true - check_socwatch_module_loaded || die "socwatch module not loaded" - # Create a dir for all socwatch reports mkdir "$LOG_ROOT/socwatch-results" pc10_results_file="$LOG_ROOT/socwatch-results/pc10_results.json" @@ -159,15 +155,14 @@ run_socwatch_tests() cd "$LOG_ROOT" tar -zcvf socwatch-results.tar.gz socwatch-results/ rm -rf "$LOG_ROOT/socwatch-results/" - - # unload socwatch module - sudo bash "$SOCWATCH_PATH"/drivers/rmmod-socwatch } main() { unload_modules + load_socwatch run_socwatch_tests + unload_socwatch load_modules } diff --git a/test-case/test-compressed-audio.sh b/test-case/test-compressed-audio.sh new file mode 100644 index 00000000..f648a263 --- /dev/null +++ b/test-case/test-compressed-audio.sh @@ -0,0 +1,95 @@ +#!/bin/bash + +## +## Case Name: test-compressed-audio +## +## Preconditions: +## TODO +## +## Description: +## TODO +## +## Case step: +## TODO +## +## Expect result: +## TODO +## + +# shellcheck source=case-lib/lib.sh +source "$(dirname "${BASH_SOURCE[0]}")"/../case-lib/lib.sh + +OPT_NAME['p']='pcm_p' OPT_DESC['p']='compression device for playback. Example: 50' +OPT_HAS_ARG['p']=1 OPT_VAL['p']='' + +OPT_NAME['N']='channels_p' OPT_DESC['N']='channel number for playback.' +OPT_HAS_ARG['N']=1 OPT_VAL['N']='2' + +OPT_NAME['s']='sof-logger' OPT_DESC['s']="Open sof-logger trace the data will store at $LOG_ROOT" +OPT_HAS_ARG['s']=0 OPT_VAL['s']=1 + +OPT_NAME['d']='duration' OPT_DESC['d']='duration time for playing the test sound' +OPT_HAS_ARG['d']=1 OPT_VAL['d']=10 + +: "${SOCWATCH_PATH:=$HOME/socwatch}" +SOCWATCH_VERSION=$(sudo "$SOCWATCH_PATH"/socwatch --version | grep Version) + +func_opt_parse_option "$@" +setup_kernel_check_point + +pcm_p=${OPT_VAL['p']} +channels_p=${OPT_VAL['N']} +duration=${OPT_VAL['d']} + +analyze_socwatch_results() +{ + pc_states_file="$LOG_ROOT/pc_states.csv" + touch "$pc_states_file" + results=$(cat "$socwatch_output".csv | grep "Platform Monitoring Technology CPU Package C-States Residency Summary: Residency" -A 10) + echo "$results" | tee "$pc_states_file" + + expected_results='{"PC0":12.00, "PC2":88, "PC6.1":0, "PC6.2":11, "PC10.1":2, "PC10.2":72, "PC10.3":0}' + + # Analyze if the % of the time spent in given PC state was as expected + if python3 "$SCRIPT_HOME"/tools/analyze-pc-states.py "$pc_states_file" "$expected_results"; then + dlogi "All Package Residency (%) values were as expected" + else + die "Some Package Residency (%) values different from expected!" + fi +} + +# Checks for soundfile needed for test, generates missing ones +prepare_test_soundfile() +{ + if [ ! -f "$audio_filename" ]; then + dlogi "Generating audio file for the test..." + generate_mp3_file "$audio_filename" "$duration" "$channels_p" + fi +} + +run_test() +{ + audio_filename="$HOME/Music/$channels_p-ch-$duration-s.mp3" + prepare_test_soundfile + + socwatch_output="$LOG_ROOT/socwatch-results/socwatch_report" + + # cplay -c 0 -d "$pcm_p" -I MP3 "$audio_filename" -v + + play_command=("cplay" "-c" "0" "-d" "$pcm_p" "-I" "MP3" "${audio_filename}" "-v") + run_with_socwatch "$socwatch_output" "${play_command[@]}" + + analyze_socwatch_results +} + +main() +{ + export RUN_SOCWATCH=true + start_test + logger_disabled || func_lib_start_log_collect + run_test +} + +{ + main "$@"; exit "$?" +} diff --git a/tools/analyze-pc-states.py b/tools/analyze-pc-states.py new file mode 100644 index 00000000..6b12dc3c --- /dev/null +++ b/tools/analyze-pc-states.py @@ -0,0 +1,46 @@ +import csv +import sys +import json +import re + +ACCEPTANCE_BUFFER = 2.0 + + +def compare_values(real, expected): + if abs(real-expected) <= ACCEPTANCE_BUFFER: + return True + return False + + +def analyze_pc_states(pc_states_file, expected_results): + pattern = re.compile(r'^PC(\d+)\s*,\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\s*$') + failures = 0 + + with open(pc_states_file) as file: + for line in file: + m = pattern.match(line) + if m: + pc_state_nr = int(m.group(1)) + pc_state = "PC"+str(pc_state_nr) + value = float(m.group(2)) + expected_value = float(expected_results.get(pc_state)) + if not expected_value: + continue + if not compare_values(value, expected_value): + print(f"Incorrect value: {pc_state} time % was {value}, expected {expected_value}") + failures += 1 + + return 0 if failures == 0 else 1 + + +# This script analyzes if the % of the time spent in given PC state was as expected +if __name__ == "__main__": + if len(sys.argv) != 3: + print("Incorrect number of args!") + sys.exit(1) + + pc_states_results_file = sys.argv[1] + pc_states_thresholds = json.loads(sys.argv[2]) + + result = analyze_pc_states(pc_states_results_file, pc_states_thresholds) + sys.exit(result)