Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions case-lib/hijack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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:"
Expand Down
44 changes: 44 additions & 0 deletions case-lib/lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -1599,3 +1603,43 @@ analyze_mixed_sound()
return 1
fi
}

# Generates 20s .mp3 file for testing
# Arguments: 1 - output filename
generate_mp3_file()
{
mkdir -p "$HOME/Music"
ffmpeg -f lavfi -i "sine=frequency=1000:duration=20" -ac 2 "$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 $?"
}
9 changes: 2 additions & 7 deletions test-case/residency-time-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
}

Expand Down
144 changes: 144 additions & 0 deletions test-case/test-cplay.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
#!/bin/bash

##
## Case Name: check alsabat
##
## Preconditions:
## This test case requires physical loopback between playback and capture.
## playback <=====> capture
## nocodec : no need to use hw loopback cable, It support DSP loopback by quirk
##
## Description:
## Run two alsabat instances concurrently, one on each specified PCM: playback
## and capture.
##
## Warning: as of January 2024, "man alsabat" is incomplete and
## documents only the "single instance" mode where a single alsabat
## process performs both playback and capture.
##
## Case step:
## 1. Specify the pcm IDs for playback and catpure
## 3. run alsabat test
##
## Expect result:
## The return value of alsabat is 0
##

# remove the existing alsabat wav files
rm -f /tmp/bat.wav.*

# shellcheck source=case-lib/lib.sh
source "$(dirname "${BASH_SOURCE[0]}")"/../case-lib/lib.sh

OPT_NAME['p']='pcm_p' OPT_DESC['p']='pcm for playback. Example: hw:0,0'
OPT_HAS_ARG['p']=1 OPT_VAL['p']=''

OPT_NAME['C']='channel_c' OPT_DESC['C']='channel number for capture.'
OPT_HAS_ARG['C']=1 OPT_VAL['C']='1'

OPT_NAME['N']='channel_p' OPT_DESC['N']='channel number for playback.'
OPT_HAS_ARG['N']=1 OPT_VAL['N']='2'

OPT_NAME['r']='rate' OPT_DESC['r']='sample rate'
OPT_HAS_ARG['r']=1 OPT_VAL['r']=48000

OPT_NAME['c']='pcm_c' OPT_DESC['c']='pcm for capture. Example: hw:1,0'
OPT_HAS_ARG['c']=1 OPT_VAL['c']=''

OPT_NAME['f']='format' OPT_DESC['f']='target format'
OPT_HAS_ARG['f']=1 OPT_VAL['f']="S16_LE"

OPT_NAME['F']='frequency' OPT_DESC['F']='target frequency'
OPT_HAS_ARG['F']=1 OPT_VAL['F']=821

OPT_NAME['k']='sigmak' OPT_DESC['k']='sigma k value'
OPT_HAS_ARG['k']=1 OPT_VAL['k']=2.1

OPT_NAME['n']='frames' OPT_DESC['n']='test frames'
OPT_HAS_ARG['n']=1 OPT_VAL['n']=240000

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 socwatch to collect the data'
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']}
pcm_c=${OPT_VAL['c']}
rate=${OPT_VAL['r']}
channel_c=${OPT_VAL['C']}
channel_p=${OPT_VAL['N']}
format=${OPT_VAL['f']}
frequency=${OPT_VAL['F']}
sigmak=${OPT_VAL['k']}
frames=${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
}

check_the_pcms()
{
aplay "-Dplug${pcm_p}" -d 1 /dev/zero -q || die "Failed to play on PCM: ${pcm_p}"
arecord "-Dplug${pcm_c}" -d 1 /dev/null -q || die "Failed to capture on PCM: ${pcm_c}"
}

# Checks for soundfile needed for test, generates missing ones
prepare_test_soundfile()
{
if [ ! -f "$audio_filename" ]; then
generate_mp3_file "$audio_filename"
fi
}

run_test()
{
check_the_pcms
audio_filename="$HOME/Music/test.mp3"
prepare_test_soundfile

socwatch_output="$LOG_ROOT/socwatch-results/socwatch_report"

play_command="cplay -d 0 -c 50 ${audio_filename}"
run_with_socwatch "$socwatch_output" "${play_command[@]}"

analyze_socwatch_results
}

main()
{
export RUN_SOCWATCH=true
start_test
# if [ "$pcm_p" = "" ]||[ "$pcm_c" = "" ];
# then
# dloge "No playback or capture PCM specified."
# exit 2
# fi
logger_disabled || func_lib_start_log_collect

run_test
}

{
main "$@"; exit "$?"
}
46 changes: 46 additions & 0 deletions tools/analyze-pc-states.py
Original file line number Diff line number Diff line change
@@ -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)
Loading