-
Notifications
You must be signed in to change notification settings - Fork 61
test: add compressed audio socwatch test #1345
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| #!/bin/bash | ||
|
|
||
| ## | ||
| ## Case Name: test-compressed-audio | ||
| ## Preconditions: | ||
| ## - socwatch installed | ||
| ## - cplay installed | ||
| ## Description: | ||
| ## This test verifies if we enter PC10 state when playing MP3 with offload to DSP. | ||
| ## Case steps: | ||
| ## 1. Generate MP3 sound for testing. | ||
| ## 2. Start Socwatch measurement and play MP3 file. | ||
| ## 3. Analyze Socwatch results. | ||
| ## Expected results: | ||
| ## - generated MP3 is played | ||
| ## - dut stays in the PC10 state for the expected amount of time | ||
| ## | ||
|
|
||
| # 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 | ||
|
|
||
| OPT_NAME['pc10_per']='pc10_per' OPT_DESC['pc10_per']='pc10 state threshold - percentage of time that should be spent in pc10' | ||
| OPT_HAS_ARG['pc10_per']=1 OPT_VAL['pc10_per']=80 | ||
|
|
||
| : "${SOCWATCH_PATH:=$HOME/socwatch}" | ||
|
|
||
| func_opt_parse_option "$@" | ||
| setup_kernel_check_point | ||
|
|
||
| pcm_p=${OPT_VAL['p']} | ||
| channels_p=${OPT_VAL['N']} | ||
| duration=${OPT_VAL['d']} | ||
| pc10_threshold=${OPT_VAL['pc10_per']} | ||
|
|
||
| analyze_socwatch_results() | ||
| { | ||
| pc_states_file="$LOG_ROOT/pc_states.csv" | ||
| touch "$pc_states_file" | ||
| results=$(grep "Platform Monitoring Technology CPU Package C-States Residency Summary: Residency" -A 10 < "$socwatch_output".csv) | ||
| echo "$results" | tee "$pc_states_file" | ||
|
|
||
| expected_results="{\"PC10.2\":$pc10_threshold}" | ||
|
|
||
| # 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 | ||
| } | ||
|
|
||
| check_cplay_command() | ||
| { | ||
| dlogi "${play_command[@]}" | ||
| "${play_command[@]}" || die "cplay command returned error, socwatch analysis not performed" | ||
| } | ||
|
|
||
| run_test() | ||
| { | ||
| audio_filename="$HOME/Music/$channels_p-ch-$duration-s.mp3" | ||
| prepare_test_soundfile | ||
|
|
||
| socwatch_output="$LOG_ROOT/socwatch-results/socwatch_report" | ||
|
|
||
| play_command=("cplay" "-c" "0" "-d" "$pcm_p" "-I" "MP3" "${audio_filename}" "-v") | ||
| check_cplay_command | ||
|
|
||
| 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 "$?" | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,52 @@ | ||||||
| import sys | ||||||
| import json | ||||||
| import re | ||||||
|
|
||||||
| ACCEPTANCE_BUFFER = 8.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*$') | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Regexps are notoriously cryptic. What really helps in such cases is to give a few input examples in a comment.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||||||
| # Example lines we want to catch: | ||||||
| # PC0 , 81.09 , 119.51 | ||||||
| # PC2 , 18.91 , 27.87 | ||||||
| failures = 0 | ||||||
|
|
||||||
| with open(pc_states_file, encoding="utf-8") as file: | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could move the |
||||||
| for line in file: | ||||||
| m = pattern.match(line) | ||||||
| if not m: | ||||||
| continue | ||||||
|
|
||||||
| pc_state_nr = int(m.group(1)) | ||||||
| pc_state = "PC"+str(pc_state_nr) | ||||||
| value = float(m.group(2)) | ||||||
| expected_value = expected_results.get(pc_state) | ||||||
| if not expected_value: | ||||||
| continue | ||||||
| if not compare_values(value, float(expected_value)): | ||||||
| print(f"Incorrect value: {pc_state} time % was {value}, expected {expected_value}") | ||||||
| failures += 1 | ||||||
|
|
||||||
| if failures: | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Then you may not want the main script to exit the number of failures too because some values may have special meaning - but for sure this function has nothing better to return than the number of failures.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This func returns the result of the analysis - which is true or false. |
||||||
| return 1 | ||||||
| return 0 | ||||||
|
|
||||||
|
|
||||||
| # 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) | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
chmod a+x analyze-pc-states.pyI'm afraid sof-test is not going to work on Windows anytime soon!