Skip to content

Commit aa8e581

Browse files
committed
test: add compressed audio with DSP offload test
Signed-off-by: Emilia Kurdybelska <emiliax.kurdybelska@intel.com>
1 parent da3d9af commit aa8e581

5 files changed

Lines changed: 263 additions & 7 deletions

File tree

case-lib/hijack.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ function func_exit_handler()
1414

1515
func_lib_check_and_disable_pipewire
1616

17+
if [ "$RUN_SOCWATCH" == true ]; then
18+
unload_socwatch
19+
fi
20+
1721
# call trace
1822
if [ "$exit_status" -ne 0 ] ; then
1923
dloge "Starting ${FUNCNAME[0]}(), exit status=$exit_status, FUNCNAME stack:"

case-lib/lib.sh

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ start_test()
8787
func_lib_enable_pipewire
8888
fi
8989

90+
if [ "$RUN_SOCWATCH" == true ]; then
91+
load_socwatch
92+
fi
93+
9094
if is_subtest; then
9195
return 0
9296
fi
@@ -1599,3 +1603,42 @@ analyze_mixed_sound()
15991603
return 1
16001604
fi
16011605
}
1606+
1607+
# Generates 20s .mp3 file for testing
1608+
# Arguments: 1 - output filename
1609+
generate_mp3_file()
1610+
{
1611+
ffmpeg -f lavfi -i "sine=frequency=1000:duration=20" "$1"
1612+
}
1613+
1614+
# Load socwatch and check if module was loaded correctly
1615+
load_socwatch()
1616+
{
1617+
sudo bash "$SOCWATCH_PATH"/drivers/insmod-socwatch || true
1618+
lsmod | grep -q socwatch || die "Socwatch is not loaded"
1619+
}
1620+
1621+
unload_socwatch()
1622+
{
1623+
sudo bash "$SOCWATCH_PATH"/drivers/rmmod-socwatch
1624+
}
1625+
1626+
# Run any command with socwatch
1627+
# Arguments:
1628+
# 1 - socwatch output report filename
1629+
# 2 - command you want to run with socwatch (with arguments)
1630+
run_with_socwatch()
1631+
{
1632+
if [ -z "$SOCWATCH_PATH" ]; then
1633+
die "SOCWATCH_PATH not set"
1634+
fi
1635+
1636+
local output_file="$1"
1637+
shift
1638+
1639+
( set -x
1640+
sudo "$SOCWATCH_PATH"/socwatch -m -f sys -f cpu -f cpu-hw -f pcie \
1641+
-f hw-cpu-cstate -f pcd-slps0 -f tcss-state -f tcss -f pcie-lpm -n 200 \
1642+
-r json -o "$output_file" -p "$@") ||
1643+
die "socwatch returned $?"
1644+
}

test-case/residency-time-test.sh

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,6 @@ load_modules()
137137

138138
run_socwatch_tests()
139139
{
140-
# load socwatch module, if the module is loaded, go ahead with the testing
141-
sudo bash "$SOCWATCH_PATH"/drivers/insmod-socwatch || true
142-
check_socwatch_module_loaded || die "socwatch module not loaded"
143-
144140
# Create a dir for all socwatch reports
145141
mkdir "$LOG_ROOT/socwatch-results"
146142
pc10_results_file="$LOG_ROOT/socwatch-results/pc10_results.json"
@@ -159,15 +155,14 @@ run_socwatch_tests()
159155
cd "$LOG_ROOT"
160156
tar -zcvf socwatch-results.tar.gz socwatch-results/
161157
rm -rf "$LOG_ROOT/socwatch-results/"
162-
163-
# unload socwatch module
164-
sudo bash "$SOCWATCH_PATH"/drivers/rmmod-socwatch
165158
}
166159

167160
main()
168161
{
169162
unload_modules
163+
load_socwatch
170164
run_socwatch_tests
165+
unload_socwatch
171166
load_modules
172167
}
173168

test-case/test-cplay.sh

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
#!/bin/bash
2+
3+
##
4+
## Case Name: check alsabat
5+
##
6+
## Preconditions:
7+
## This test case requires physical loopback between playback and capture.
8+
## playback <=====> capture
9+
## nocodec : no need to use hw loopback cable, It support DSP loopback by quirk
10+
##
11+
## Description:
12+
## Run two alsabat instances concurrently, one on each specified PCM: playback
13+
## and capture.
14+
##
15+
## Warning: as of January 2024, "man alsabat" is incomplete and
16+
## documents only the "single instance" mode where a single alsabat
17+
## process performs both playback and capture.
18+
##
19+
## Case step:
20+
## 1. Specify the pcm IDs for playback and catpure
21+
## 3. run alsabat test
22+
##
23+
## Expect result:
24+
## The return value of alsabat is 0
25+
##
26+
27+
# remove the existing alsabat wav files
28+
rm -f /tmp/bat.wav.*
29+
30+
# shellcheck source=case-lib/lib.sh
31+
source "$(dirname "${BASH_SOURCE[0]}")"/../case-lib/lib.sh
32+
33+
OPT_NAME['p']='pcm_p' OPT_DESC['p']='pcm for playback. Example: hw:0,0'
34+
OPT_HAS_ARG['p']=1 OPT_VAL['p']=''
35+
36+
OPT_NAME['C']='channel_c' OPT_DESC['C']='channel number for capture.'
37+
OPT_HAS_ARG['C']=1 OPT_VAL['C']='1'
38+
39+
OPT_NAME['N']='channel_p' OPT_DESC['N']='channel number for playback.'
40+
OPT_HAS_ARG['N']=1 OPT_VAL['N']='2'
41+
42+
OPT_NAME['r']='rate' OPT_DESC['r']='sample rate'
43+
OPT_HAS_ARG['r']=1 OPT_VAL['r']=48000
44+
45+
OPT_NAME['c']='pcm_c' OPT_DESC['c']='pcm for capture. Example: hw:1,0'
46+
OPT_HAS_ARG['c']=1 OPT_VAL['c']=''
47+
48+
OPT_NAME['f']='format' OPT_DESC['f']='target format'
49+
OPT_HAS_ARG['f']=1 OPT_VAL['f']="S16_LE"
50+
51+
OPT_NAME['F']='frequency' OPT_DESC['F']='target frequency'
52+
OPT_HAS_ARG['F']=1 OPT_VAL['F']=821
53+
54+
OPT_NAME['k']='sigmak' OPT_DESC['k']='sigma k value'
55+
OPT_HAS_ARG['k']=1 OPT_VAL['k']=2.1
56+
57+
OPT_NAME['n']='frames' OPT_DESC['n']='test frames'
58+
OPT_HAS_ARG['n']=1 OPT_VAL['n']=240000
59+
60+
OPT_NAME['s']='sof-logger' OPT_DESC['s']="Open sof-logger trace the data will store at $LOG_ROOT"
61+
OPT_HAS_ARG['s']=0 OPT_VAL['s']=1
62+
63+
OPT_NAME['d']='duration' OPT_DESC['d']='duration time for socwatch to collect the data'
64+
OPT_HAS_ARG['d']=1 OPT_VAL['d']=10
65+
66+
: "${SOCWATCH_PATH:=$HOME/socwatch}"
67+
SOCWATCH_VERSION=$(sudo "$SOCWATCH_PATH"/socwatch --version | grep Version)
68+
69+
func_opt_parse_option "$@"
70+
setup_kernel_check_point
71+
72+
pcm_p=${OPT_VAL['p']}
73+
pcm_c=${OPT_VAL['c']}
74+
rate=${OPT_VAL['r']}
75+
channel_c=${OPT_VAL['C']}
76+
channel_p=${OPT_VAL['N']}
77+
format=${OPT_VAL['f']}
78+
frequency=${OPT_VAL['F']}
79+
sigmak=${OPT_VAL['k']}
80+
frames=${OPT_VAL['n']}
81+
duration=${OPT_VAL['d']}
82+
83+
analyze_socwatch_results()
84+
{
85+
pc_states_file="$LOG_ROOT/pc_states.csv"
86+
touch "$pc_states_file"
87+
results=$(cat "$socwatch_output".csv | grep "Platform Monitoring Technology CPU Package C-States Residency Summary: Residency" -A 10)
88+
echo "$results" | tee "$pc_states_file"
89+
90+
expected_results='{"PC0":12.00, "PC2":88, "PC6.1":0, "PC6.2":11, "PC10.1":2, "PC10.2":72, "PC10.3":0}'
91+
92+
# Analyze if the % of the time spent in given PC state was as expected
93+
if python3 "$SCRIPT_HOME"/tools/analyze-pc-states.py "$pc_states_file" "$expected_results"; then
94+
dlogi "All Package Residency (%) values were as expected"
95+
else
96+
die "Some Package Residency (%) values different from expected!"
97+
fi
98+
}
99+
100+
check_for_PC10_state()
101+
{
102+
pc10_count=$(awk '/Package C-State Summary: Entry Counts/{f=1; next} f && /PC10/{print $3; exit}' "$socwatch_output".csv)
103+
if [ -z "$pc10_count" ]; then
104+
die "PC10 State not achieved"
105+
fi
106+
dlogi "Entered into PC10 State $pc10_count times"
107+
108+
pc10_per=$(awk '/Package C-State Summary: Residency/{f=1; next} f && /PC10/{print $3; exit}' "$socwatch_output".csv)
109+
pc10_time=$(awk '/Package C-State Summary: Residency/{f=1; next} f && /PC10/{print $5; exit}' "$socwatch_output".csv)
110+
dlogi "Spent $pc10_time ms ($pc10_per %) in PC10 State"
111+
112+
json_str=$( jq -n \
113+
--arg id "$i" \
114+
--arg cnt "$pc10_count" \
115+
--arg time "$pc10_time" \
116+
--arg per "$pc10_per" \
117+
'{$id: {pc10_entires_count: $cnt, time_ms: $time, time_percentage: $per}}' )
118+
119+
results=$(jq --slurp 'add' <(echo "$results") <(echo "$json_str"))
120+
}
121+
122+
check_the_pcms()
123+
{
124+
aplay "-Dplug${pcm_p}" -d 1 /dev/zero -q || die "Failed to play on PCM: ${pcm_p}"
125+
arecord "-Dplug${pcm_c}" -d 1 /dev/null -q || die "Failed to capture on PCM: ${pcm_c}"
126+
}
127+
128+
# Checks for soundfile needed for test, generates missing ones
129+
prepare_test_soundfile()
130+
{
131+
mkdir -p "$HOME/Music"
132+
if [ ! -f "$audio_filename" ]; then
133+
generate_mp3_file "$audio_filename"
134+
fi
135+
}
136+
137+
run_test()
138+
{
139+
check_the_pcms
140+
# audio_filename="$HOME/Music/test.mp3"
141+
# prepare_test_soundfile
142+
143+
socwatch_output="$LOG_ROOT/socwatch-results/socwatch_report"
144+
145+
# play_command="cplay -D${pcm_p} -d ${duration} ${audio_filename}"
146+
play_command=(aplay -Dplug${pcm_p} -d ${duration} /dev/zero)
147+
run_with_socwatch "$socwatch_output" "${play_command[@]}"
148+
149+
analyze_socwatch_results
150+
}
151+
152+
main()
153+
{
154+
export RUN_SOCWATCH=true
155+
start_test
156+
if [ "$pcm_p" = "" ]||[ "$pcm_c" = "" ];
157+
then
158+
dloge "No playback or capture PCM specified."
159+
exit 2
160+
fi
161+
logger_disabled || func_lib_start_log_collect
162+
163+
run_test
164+
}
165+
166+
{
167+
main "$@"; exit "$?"
168+
}

tools/analyze-pc-states.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import csv
2+
import sys
3+
import json
4+
import re
5+
6+
ACCEPTANCE_BUFFER = 2.0
7+
8+
9+
def compare_values(real, expected):
10+
if abs(real-expected) <= ACCEPTANCE_BUFFER:
11+
return True
12+
return False
13+
14+
15+
def analyze_pc_states(pc_states_file, expected_results):
16+
pattern = re.compile(r'^PC(\d+)\s*,\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\s*$')
17+
failures = 0
18+
19+
with open(pc_states_file) as file:
20+
for line in file:
21+
m = pattern.match(line)
22+
if m:
23+
pc_state_nr = int(m.group(1))
24+
pc_state = "PC"+str(pc_state_nr)
25+
value = float(m.group(2))
26+
expected_value = float(expected_results.get(pc_state))
27+
if not expected_value:
28+
continue
29+
if not compare_values(value, expected_value):
30+
print(f"Incorrect value: {pc_state} time % was {value}, expected {expected_value}")
31+
failures += 1
32+
33+
return 0 if failures == 0 else 1
34+
35+
36+
# This script analyzes if the % of the time spent in given PC state was as expected
37+
if __name__ == "__main__":
38+
if len(sys.argv) != 3:
39+
print("Incorrect number of args!")
40+
sys.exit(1)
41+
42+
pc_states_results_file = sys.argv[1]
43+
pc_states_thresholds = json.loads(sys.argv[2])
44+
45+
result = analyze_pc_states(pc_states_results_file, pc_states_thresholds)
46+
sys.exit(result)

0 commit comments

Comments
 (0)