Skip to content

Commit 4d23ccb

Browse files
authored
Merge pull request #61 from smuppand/main
CPUFreq: Add policy-aware validation and robust frequency walker
2 parents 5693465 + c4ec552 commit 4d23ccb

File tree

3 files changed

+126
-116
lines changed

3 files changed

+126
-116
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# CPUFreq_Validation
2+
3+
## Overview
4+
5+
The `CPUFreq_Validation` test validates the CPU frequency scaling capabilities of a system using the Linux `cpufreq` subsystem. It verifies the ability to set and reflect CPU frequencies across shared policy domains (e.g., clusters of CPUs sharing frequency control).
6+
7+
This test is designed to be **SoC-agnostic**, supporting platforms with per-policy frequency management (e.g., Qualcomm SoCs with `policy0`, `policy4`, etc.).
8+
9+
## Test Goals
10+
11+
- Ensure all cpufreq policies are present and functional
12+
- Iterate through all available frequencies and validate correct scaling
13+
- Ensure that CPU governors can be set to `userspace`
14+
- Provide robust reporting per policy (e.g., `CPU0-3 [via policy0] = PASS`)
15+
- Avoid flaky failures in CI by using retries and proper checks
16+
17+
## Prerequisites
18+
19+
- Kernel must be built with `CONFIG_CPU_FREQ` and `CONFIG_CPU_FREQ_GOV_USERSPACE`
20+
- `sysfs` access to `/sys/devices/system/cpu/cpufreq/*`
21+
- Root privileges (to write to cpufreq entries)
22+
23+
## Script Location
24+
25+
```
26+
Runner/suites/Kernel/FunctionalArea/baseport/CPUFreq_Validation/run.sh
27+
```
28+
29+
## Files
30+
31+
- `run.sh` - Main test script
32+
- `CPUFreq_Validation.res` - Summary result file with PASS/FAIL
33+
- `CPUFreq_Validation.log` - Full execution log (generated if logging is enabled)
34+
35+
## How It Works
36+
37+
1. The script detects all cpufreq policies under `/sys/devices/system/cpu/cpufreq/`
38+
2. For each policy:
39+
- Reads the list of related CPUs
40+
- Attempts to set each available frequency using the `userspace` governor
41+
- Verifies that the frequency was correctly applied
42+
3. The result is logged per policy
43+
4. The overall test passes only if all policies succeed
44+
45+
## Example Output
46+
47+
```
48+
[INFO] CPU0-3 [via policy0] = PASS
49+
[FAIL] CPU4-6 [via policy4] = FAIL
50+
[INFO] CPU7 [via policy7] = PASS
51+
```
52+
53+
## Return Code
54+
55+
- `0` — All policies passed
56+
- `1` — One or more policies failed
57+
58+
## Integration in CI
59+
60+
- Can be run standalone or via LAVA
61+
- Result file `CPUFreq_Validation.res` will be parsed by `result_parse.sh`
62+
63+
## Notes
64+
65+
- Some CPUs may share frequency domains, so per-core testing is not reliable
66+
- The test includes retries to reduce false failures due to transient conditions
67+
68+
## License
69+
70+
SPDX-License-Identifier: BSD-3-Clause-Clear
71+
(c) Qualcomm Technologies, Inc. and/or its subsidiaries.
72+

Runner/suites/Kernel/FunctionalArea/baseport/CPUFreq_Validation/run.sh

Lines changed: 53 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -20,162 +20,99 @@ if [ -z "$INIT_ENV" ]; then
2020
exit 1
2121
fi
2222

23-
# Only source if not already loaded (idempotent)
2423
if [ -z "$__INIT_ENV_LOADED" ]; then
2524
# shellcheck disable=SC1090
2625
. "$INIT_ENV"
2726
fi
28-
# Always source functestlib.sh, using $TOOLS exported by init_env
2927
# shellcheck disable=SC1090,SC1091
3028
. "$TOOLS/functestlib.sh"
3129

3230
TESTNAME="CPUFreq_Validation"
3331
test_path=$(find_test_case_by_name "$TESTNAME")
3432
cd "$test_path" || exit 1
35-
# shellcheck disable=SC2034
3633
res_file="./$TESTNAME.res"
3734

38-
log_info "-----------------------------------------------------------------------------------------"
39-
log_info "-------------------Starting $TESTNAME Testcase----------------------------"
40-
log_info "=== CPUFreq Frequency Walker with Retry and Cleanup ==="
41-
42-
NUM_CPUS=$(nproc)
43-
log_info "Detected $NUM_CPUS CPU cores."
35+
log_info "------------------------------------------------------------"
36+
log_info "Starting $TESTNAME Testcase"
4437

4538
overall_pass=0
4639
status_dir="/tmp/cpufreq_status.$$"
4740
mkdir -p "$status_dir"
4841

49-
validate_cpu_core() {
50-
local cpu="$1"
51-
local core_id="$2"
52-
local status_file="$status_dir/core_$core_id"
53-
echo "unknown" > "$status_file"
54-
55-
log_info "Processing $cpu..."
56-
57-
local cpu_num
58-
cpu_num=$(basename "$cpu" | tr -dc '0-9')
59-
if [ -f "/sys/devices/system/cpu/cpu$cpu_num/online" ]; then
60-
echo 1 > "/sys/devices/system/cpu/cpu$cpu_num/online"
61-
fi
62-
63-
if [ ! -d "$cpu/cpufreq" ]; then
64-
log_info "[SKIP] $cpu does not support cpufreq."
65-
echo "skip" > "$status_file"
66-
return
67-
fi
42+
for policy_dir in /sys/devices/system/cpu/cpufreq/policy*; do
43+
policy=$(basename "$policy_dir")
6844

69-
local freqs_file="$cpu/cpufreq/scaling_available_frequencies"
70-
read -r available_freqs < "$freqs_file" 2>/dev/null
71-
if [ -z "$available_freqs" ]; then
72-
log_info "[SKIP] No available frequencies for $cpu"
73-
echo "skip" > "$status_file"
74-
return
45+
if [ ! -d "$policy_dir" ]; then
46+
log_warn "Skipping $policy_dir, not a directory"
47+
continue
7548
fi
7649

77-
local original_governor
78-
original_governor=$(cat "$cpu/cpufreq/scaling_governor" 2>/dev/null)
79-
80-
if echo "userspace" > "$cpu/cpufreq/scaling_governor"; then
81-
log_info "[INFO] Set governor to userspace."
82-
sync
83-
sleep 0.5
84-
else
85-
log_error "Cannot set userspace governor for $cpu."
86-
echo "fail" > "$status_file"
87-
return
50+
cpus=$(cat "$policy_dir/related_cpus" 2>/dev/null)
51+
[ -z "$cpus" ] && {
52+
log_warn "No related CPUs found for $policy_dir"
53+
continue
54+
}
55+
56+
available_freqs=$(cat "$policy_dir/scaling_available_frequencies" 2>/dev/null)
57+
[ -z "$available_freqs" ] && {
58+
log_warn "No available frequencies for $policy_dir"
59+
continue
60+
}
61+
62+
original_governor=$(cat "$policy_dir/scaling_governor" 2>/dev/null)
63+
if ! echo "userspace" > "$policy_dir/scaling_governor"; then
64+
log_fail "$policy_dir: Unable to set userspace governor"
65+
echo "fail" > "$status_dir/$policy"
66+
overall_pass=1
67+
continue
8868
fi
8969

90-
echo "pass" > "$status_file"
70+
echo "pass" > "$status_dir/$policy"
9171

9272
for freq in $available_freqs; do
93-
log_info "Setting $cpu to frequency $freq kHz..."
94-
95-
echo "$freq" > "$cpu/cpufreq/scaling_min_freq" 2>/dev/null
96-
echo "$freq" > "$cpu/cpufreq/scaling_max_freq" 2>/dev/null
97-
98-
if ! echo "$freq" > "$cpu/cpufreq/scaling_setspeed" 2>/dev/null; then
99-
log_error "[SKIP] Kernel rejected freq $freq for $cpu"
73+
log_info "$policy: Trying frequency $freq"
74+
echo "$freq" > "$policy_dir/scaling_min_freq" 2>/dev/null
75+
echo "$freq" > "$policy_dir/scaling_max_freq" 2>/dev/null
76+
if ! echo "$freq" > "$policy_dir/scaling_setspeed" 2>/dev/null; then
77+
log_warn "$policy: Kernel rejected frequency $freq"
10078
continue
10179
fi
10280

103-
retry=0
104-
success=0
105-
while [ "$retry" -lt 5 ]; do
106-
cur=$(cat "$cpu/cpufreq/scaling_cur_freq")
107-
if [ "$cur" = "$freq" ]; then
108-
log_info "[PASS] $cpu set to $freq kHz."
109-
success=1
110-
break
111-
fi
112-
sleep 0.2
113-
retry=$((retry + 1))
114-
done
115-
116-
if [ "$success" -eq 0 ]; then
117-
log_info "[RETRY] Re-attempting to set $cpu to $freq kHz..."
118-
echo "$freq" > "$cpu/cpufreq/scaling_setspeed"
119-
sleep 0.3
120-
cur=$(cat "$cpu/cpufreq/scaling_cur_freq")
121-
if [ "$cur" = "$freq" ]; then
122-
log_info "[PASS-after-retry] $cpu set to $freq kHz."
123-
else
124-
log_error "[FAIL] $cpu failed to set $freq kHz twice. Current: $cur"
125-
echo "fail" > "$status_file"
126-
fi
81+
sleep 0.3
82+
cur_freq=$(cat "$policy_dir/scaling_cur_freq" 2>/dev/null)
83+
84+
if [ "$cur_freq" = "$freq" ]; then
85+
log_info "[PASS] $policy reached $freq kHz"
86+
else
87+
log_warn "Mismatch freq: tried $freq, got $cur_freq on $policy"
88+
echo "fail" > "$status_dir/$policy"
89+
overall_pass=1
12790
fi
12891
done
12992

130-
log_info "Restoring $cpu governor to '$original_governor'..."
131-
echo "$original_governor" > "$cpu/cpufreq/scaling_governor"
132-
echo 0 > "$cpu/cpufreq/scaling_min_freq" 2>/dev/null
133-
echo 0 > "$cpu/cpufreq/scaling_max_freq" 2>/dev/null
134-
}
135-
136-
cpu_index=0
137-
for cpu in /sys/devices/system/cpu/cpu[0-9]*; do
138-
validate_cpu_core "$cpu" "$cpu_index" &
139-
cpu_index=$((cpu_index + 1))
93+
echo "$original_governor" > "$policy_dir/scaling_governor"
14094
done
14195

142-
wait
143-
14496
log_info ""
145-
log_info "=== Per-Core Test Summary ==="
146-
for status_file in "$status_dir"/core_*; do
147-
idx=$(basename "$status_file" | cut -d_ -f2)
148-
status=$(cat "$status_file")
149-
case "$status" in
150-
pass)
151-
log_info "CPU$idx: [PASS]"
152-
;;
153-
fail)
154-
log_error "CPU$idx: [FAIL]"
155-
overall_pass=1
156-
;;
157-
skip)
158-
log_info "CPU$idx: [SKIPPED]"
159-
;;
160-
*)
161-
log_error "CPU$idx: [UNKNOWN STATUS]"
162-
overall_pass=1
163-
;;
164-
esac
97+
log_info "=== Per-Policy CPU Group Summary ==="
98+
for f in "$status_dir"/*; do
99+
policy=$(basename "$f")
100+
result=$(cat "$f")
101+
cpus=$(tr '\n' ' ' < "/sys/devices/system/cpu/cpufreq/$policy/related_cpus")
102+
cpulist=$(echo "$cpus" | sed 's/ /,/g')
103+
status_str=$(echo "$result" | tr '[:lower:]' '[:upper:]')
104+
echo "CPU$cpulist [via $policy] = $status_str"
165105
done
166106

167107
log_info ""
168-
log_info "=== Overall CPUFreq Validation Result ==="
169-
108+
log_info "=== Final Result ==="
170109
if [ "$overall_pass" -eq 0 ]; then
171-
log_pass "$TESTNAME : Test Passed"
110+
log_pass "$TESTNAME: All policies passed"
172111
echo "$TESTNAME PASS" > "$res_file"
173112
else
174-
log_fail "$TESTNAME : Test Failed"
113+
log_fail "$TESTNAME: One or more policies failed"
175114
echo "$TESTNAME FAIL" > "$res_file"
176115
fi
177116

178-
rm -r "$status_dir"
179-
sync
180-
sleep 1
117+
rm -rf "$status_dir"
181118
exit "$overall_pass"

Runner/utils/functestlib.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ log_pass() { log "PASS" "$@"; }
1414
log_fail() { log "FAIL" "$@"; }
1515
log_error() { log "ERROR" "$@"; }
1616
log_skip() { log "SKIP" "$@"; }
17+
log_warn() { log "WARN" "$@"; }
1718

1819
# --- Dependency check ---
1920
check_dependencies() {

0 commit comments

Comments
 (0)