From 8e1953584cc0acc7f54b5d6d4f22c603f92283a8 Mon Sep 17 00:00:00 2001 From: Srikanth Muppandam Date: Wed, 10 Jun 2026 13:47:05 +0530 Subject: [PATCH 1/2] functestlib: add reusable interrupt counter polling helpers Move generic interrupt counter validation into functestlib.sh so tests can reuse common /proc/interrupts parsing and polling logic. Add helpers to: - compare per-CPU interrupt counters between two interrupt lines - poll a named interrupt until all CPU counters increment - expose initial/final interrupt lines and parsed counter values to callers for test-specific reporting This supports replacing fixed sleeps in interrupt-based tests with a poll-until-progress flow, reducing LAVA runtime while still failing safely when counters do not advance within the configured timeout. Also add local ShellCheck SC2034 suppressions for intentionally exported helper result variables consumed by caller scripts. Signed-off-by: Srikanth Muppandam --- Runner/utils/functestlib.sh | 161 ++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) diff --git a/Runner/utils/functestlib.sh b/Runner/utils/functestlib.sh index 05243a9e..dda69fd1 100755 --- a/Runner/utils/functestlib.sh +++ b/Runner/utils/functestlib.sh @@ -284,6 +284,167 @@ interrupt_counter_delta() { ' } +# Compare per-CPU interrupt counters from two /proc/interrupts lines. +# +# Arguments: +# $1 - initial interrupt line +# $2 - final interrupt line +# +# Return: +# 0 - all parsed per-CPU counters incremented +# 1 - fatal parse/count mismatch +# 2 - counters parsed, but one or more CPUs did not increment yet +# +# Sets globals for callers: +# INTERRUPT_COMPARE_CPU_COUNT +# INTERRUPT_COMPARE_INITIAL_VALUES +# INTERRUPT_COMPARE_FINAL_VALUES +# shellcheck disable=SC2317 +interrupt_cpu_counts_incremented() { + initial_line="$1" + final_line="$2" + + INTERRUPT_COMPARE_INITIAL_VALUES="$(extract_interrupt_cpu_counts "$initial_line")" + INTERRUPT_COMPARE_FINAL_VALUES="$(extract_interrupt_cpu_counts "$final_line")" + + initial_cpu_count="$(count_interrupt_cpu_counts "$INTERRUPT_COMPARE_INITIAL_VALUES")" + final_cpu_count="$(count_interrupt_cpu_counts "$INTERRUPT_COMPARE_FINAL_VALUES")" + + # Export result to caller, used by Interrupts/run.sh after this helper returns. + # shellcheck disable=SC2034 + INTERRUPT_COMPARE_CPU_COUNT="$initial_cpu_count" + + if [ "$initial_cpu_count" -eq 0 ] || [ "$final_cpu_count" -eq 0 ]; then + log_fail "No per-CPU interrupt counters could be parsed from /proc/interrupts" + return 1 + fi + + if [ "$initial_cpu_count" -ne "$final_cpu_count" ]; then + log_fail "Mismatch in parsed CPU interrupt counters: initial=${initial_cpu_count} final=${final_cpu_count}" + return 1 + fi + + cpu_index=0 + while [ "$cpu_index" -lt "$initial_cpu_count" ]; do + initial_value="$(printf '%s\n' "$INTERRUPT_COMPARE_INITIAL_VALUES" | sed -n "$((cpu_index + 1))p")" + final_value="$(printf '%s\n' "$INTERRUPT_COMPARE_FINAL_VALUES" | sed -n "$((cpu_index + 1))p")" + + if [ "$initial_value" -ge "$final_value" ]; then + return 2 + fi + + cpu_index=$((cpu_index + 1)) + done + + return 0 +} + +# Poll a named interrupt until all per-CPU counters increment. +# +# Arguments: +# $1 - interrupt name/pattern, for example arch_timer +# $2 - timeout seconds +# $3 - poll interval seconds +# +# Return: +# 0 - interrupt counters incremented on all CPUs +# 1 - fatal error / timeout +# +# Sets globals for callers: +# INTERRUPT_WAIT_INITIAL_LINE +# INTERRUPT_WAIT_FINAL_LINE +# INTERRUPT_WAIT_IRQ_ID +# INTERRUPT_WAIT_ELAPSED_S +# INTERRUPT_COMPARE_CPU_COUNT +# INTERRUPT_COMPARE_INITIAL_VALUES +# INTERRUPT_COMPARE_FINAL_VALUES +# shellcheck disable=SC2317 +wait_for_interrupt_cpu_count_increment() { + irq_name="$1" + timeout_s="$2" + poll_interval_s="$3" + + if ! is_unsigned_number "$timeout_s"; then + log_warn "Invalid interrupt wait timeout '${timeout_s}', using 30" + timeout_s=30 + fi + + if ! is_unsigned_number "$poll_interval_s"; then + log_warn "Invalid interrupt poll interval '${poll_interval_s}', using 2" + poll_interval_s=2 + fi + + if [ "$poll_interval_s" -eq 0 ]; then + log_warn "Interrupt poll interval cannot be 0, using 1" + poll_interval_s=1 + fi + + INTERRUPT_WAIT_INITIAL_LINE="$(get_first_interrupt_line_by_name "$irq_name")" + INTERRUPT_WAIT_FINAL_LINE="" + INTERRUPT_WAIT_IRQ_ID="" + INTERRUPT_WAIT_ELAPSED_S=0 + + if [ -z "$INTERRUPT_WAIT_INITIAL_LINE" ]; then + log_fail "Could not find interrupt line matching '${irq_name}' in /proc/interrupts" + return 1 + fi + + INTERRUPT_WAIT_IRQ_ID="$(printf '%s\n' "$INTERRUPT_WAIT_INITIAL_LINE" | awk '{ print $1 }')" + + log_info "Initial interrupt line for '${irq_name}':" + log_info "$INTERRUPT_WAIT_INITIAL_LINE" + log_info "Polling '${irq_name}' interrupt counters, timeout=${timeout_s}s interval=${poll_interval_s}s" + + waited=0 + + while [ "$waited" -le "$timeout_s" ]; do + current_line="$(get_interrupt_line_by_name "$irq_name" | awk -v irq="$INTERRUPT_WAIT_IRQ_ID" '$1 == irq { print; exit }')" + + if [ -n "$current_line" ]; then + INTERRUPT_WAIT_FINAL_LINE="$current_line" + + interrupt_cpu_counts_incremented "$INTERRUPT_WAIT_INITIAL_LINE" "$INTERRUPT_WAIT_FINAL_LINE" + compare_rc=$? + + case "$compare_rc" in + 0) + INTERRUPT_WAIT_ELAPSED_S="$waited" + log_info "Final interrupt line for '${irq_name}' after ${waited}s:" + log_info "$INTERRUPT_WAIT_FINAL_LINE" + return 0 + ;; + 1) + INTERRUPT_WAIT_ELAPSED_S="$waited" + return 1 + ;; + 2) + : + ;; + esac + else + log_warn "Interrupt line '${irq_name}' with IRQ ${INTERRUPT_WAIT_IRQ_ID} not found while polling" + fi + + if [ "$waited" -ge "$timeout_s" ]; then + break + fi + + sleep "$poll_interval_s" + waited=$((waited + poll_interval_s)) + done + + # Export result to caller, used by Interrupts/run.sh after this helper returns. + # shellcheck disable=SC2034 + INTERRUPT_WAIT_ELAPSED_S="$waited" + + if [ -n "$INTERRUPT_WAIT_FINAL_LINE" ]; then + log_info "Last interrupt line for '${irq_name}' after timeout:" + log_info "$INTERRUPT_WAIT_FINAL_LINE" + fi + + log_fail "Interrupt counters for '${irq_name}' did not increment on all CPUs within ${timeout_s}s" + return 1 +} # Run bounded workload pinned to one CPU. # From 663aa29a3cd58717b2847ef3150ed1578fba2120 Mon Sep 17 00:00:00 2001 From: Srikanth Muppandam Date: Wed, 10 Jun 2026 13:47:34 +0530 Subject: [PATCH 2/2] Interrupts: poll timer counters instead of fixed sleep The Interrupts test waits for a hardcoded 120 seconds before comparing arch_timer interrupt counters. This is unnecessarily expensive in LAVA, especially when the counters usually increment within a few seconds. Replace the fixed sleep with a poll-until-progress loop. The test now records the initial arch_timer counters and polls until all per-CPU counters increment, with configurable timeout and poll interval. Defaults: - INTERRUPTS_WAIT_TIMEOUT_S=30 - INTERRUPTS_POLL_INTERVAL_S=2 This keeps the same validation goal while reducing LAVA runtime and still failing safely when timer counters do not progress. Signed-off-by: Srikanth Muppandam --- .../Baseport/Interrupts/Interrupts.yaml | 6 +- .../suites/Kernel/Baseport/Interrupts/run.sh | 107 +++++------------- 2 files changed, 35 insertions(+), 78 deletions(-) diff --git a/Runner/suites/Kernel/Baseport/Interrupts/Interrupts.yaml b/Runner/suites/Kernel/Baseport/Interrupts/Interrupts.yaml index 9dd397b0..879d4104 100755 --- a/Runner/suites/Kernel/Baseport/Interrupts/Interrupts.yaml +++ b/Runner/suites/Kernel/Baseport/Interrupts/Interrupts.yaml @@ -11,8 +11,12 @@ metadata: devices: - rb3gen2 +params: + INTERRUPTS_WAIT_TIMEOUT_S: "30" + INTERRUPTS_POLL_INTERVAL_S: "2" + run: steps: - cd Runner - - $PWD/suites/Kernel/Baseport/Interrupts/run.sh || true + - INTERRUPTS_WAIT_TIMEOUT_S="${INTERRUPTS_WAIT_TIMEOUT_S}" INTERRUPTS_POLL_INTERVAL_S="${INTERRUPTS_POLL_INTERVAL_S}" $PWD/suites/Kernel/Baseport/Interrupts/run.sh || true - $PWD/utils/send-to-lava.sh $PWD/suites/Kernel/Baseport/Interrupts/Interrupts.res || true diff --git a/Runner/suites/Kernel/Baseport/Interrupts/run.sh b/Runner/suites/Kernel/Baseport/Interrupts/run.sh index 23a68aae..aaded014 100755 --- a/Runner/suites/Kernel/Baseport/Interrupts/run.sh +++ b/Runner/suites/Kernel/Baseport/Interrupts/run.sh @@ -2,10 +2,12 @@ # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. # SPDX-License-Identifier: BSD-3-Clause + # Robustly find and source init_env SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" INIT_ENV="" SEARCH="$SCRIPT_DIR" + while [ "$SEARCH" != "/" ]; do if [ -f "$SEARCH/init_env" ]; then INIT_ENV="$SEARCH/init_env" @@ -20,10 +22,11 @@ if [ -z "$INIT_ENV" ]; then fi # Only source if not already loaded (idempotent) -if [ -z "$__INIT_ENV_LOADED" ]; then +if [ -z "${__INIT_ENV_LOADED:-}" ]; then # shellcheck disable=SC1090 . "$INIT_ENV" fi + # Always source functestlib.sh, using $TOOLS exported by init_env # shellcheck disable=SC1090,SC1091 . "$TOOLS/functestlib.sh" @@ -31,95 +34,45 @@ fi TESTNAME="Interrupts" test_path=$(find_test_case_by_name "$TESTNAME") cd "$test_path" || exit 1 + # shellcheck disable=SC2034 res_file="./$TESTNAME.res" +INTERRUPTS_WAIT_TIMEOUT_S="${INTERRUPTS_WAIT_TIMEOUT_S:-30}" +INTERRUPTS_POLL_INTERVAL_S="${INTERRUPTS_POLL_INTERVAL_S:-2}" + log_info "-----------------------------------------------------------------------------------------" log_info "-------------------Starting $TESTNAME Testcase----------------------------" log_info "=== Test Initialization ===" +log_info "Config: INTERRUPTS_WAIT_TIMEOUT_S=${INTERRUPTS_WAIT_TIMEOUT_S} INTERRUPTS_POLL_INTERVAL_S=${INTERRUPTS_POLL_INTERVAL_S}" -# Function to get the timer count -get_timer_count() { - get_interrupt_line_by_name "arch_timer" -} +if ! wait_for_interrupt_cpu_count_increment "arch_timer" "$INTERRUPTS_WAIT_TIMEOUT_S" "$INTERRUPTS_POLL_INTERVAL_S"; then + log_fail "$TESTNAME : Test Failed" + echo "$TESTNAME FAIL" > "$res_file" + exit 1 +fi -# Get the initial timer count echo "Initial timer count:" -initial_count=$(get_timer_count) -echo "$initial_count" +echo "$INTERRUPT_WAIT_INITIAL_LINE" -# Wait for 2 minutes -sleep 120 +echo "Timer count after polling:" +echo "$INTERRUPT_WAIT_FINAL_LINE" -# Get the timer count after 2 minutes -echo "Timer count after 2 minutes:" -final_count=$(get_timer_count) -echo "$final_count" - -# Compare the initial and final counts echo "Comparing timer counts:" -while IFS= read -r line; do - [ -n "$line" ] || continue +log_info "Detected timer counters: initial=${INTERRUPT_COMPARE_CPU_COUNT} final=${INTERRUPT_COMPARE_CPU_COUNT}" +log_info "arch_timer counters incremented on all CPUs after ${INTERRUPT_WAIT_ELAPSED_S}s" - irq_id=$(printf '%s\n' "$line" | awk '{print $1}') - final_line=$(printf '%s\n' "$final_count" | awk -v irq="$irq_id" '$1 == irq { print; exit }') +cpu_index=0 +while [ "$cpu_index" -lt "$INTERRUPT_COMPARE_CPU_COUNT" ]; do + initial_value="$(printf '%s\n' "$INTERRUPT_COMPARE_INITIAL_VALUES" | sed -n "$((cpu_index + 1))p")" + final_value="$(printf '%s\n' "$INTERRUPT_COMPARE_FINAL_VALUES" | sed -n "$((cpu_index + 1))p")" - if [ -z "$final_line" ]; then - log_fail "Could not find matching final timer line for IRQ $irq_id" - log_fail "$TESTNAME : Test Failed" - echo "$TESTNAME FAIL" > "$res_file" - exit 1 - fi + echo "CPU $cpu_index: Timer count has incremented. Test PASSED" + log_pass "CPU $cpu_index: Timer count has incremented. initial=${initial_value} final=${final_value}" - initial_values=$(extract_interrupt_cpu_counts "$line") - final_values=$(extract_interrupt_cpu_counts "$final_line") - - initial_cpu_count=$(count_interrupt_cpu_counts "$initial_values") - final_cpu_count=$(count_interrupt_cpu_counts "$final_values") - - log_info "Detected timer counters: initial=${initial_cpu_count} final=${final_cpu_count}" - - if [ "$initial_cpu_count" -eq 0 ] || [ "$final_cpu_count" -eq 0 ]; then - log_fail "No per-CPU timer counters could be parsed from /proc/interrupts" - log_fail "$TESTNAME : Test Failed" - echo "$TESTNAME FAIL" > "$res_file" - exit 1 - fi - - if [ "$initial_cpu_count" -ne "$final_cpu_count" ]; then - log_fail "Mismatch in parsed CPU timer counters: initial=${initial_cpu_count} final=${final_cpu_count}" - log_fail "$TESTNAME : Test Failed" - echo "$TESTNAME FAIL" > "$res_file" - exit 1 - fi + cpu_index=$((cpu_index + 1)) +done - fail_test=false - i=0 - - while [ "$i" -lt "$initial_cpu_count" ]; do - initial_value=$(printf '%s\n' "$initial_values" | sed -n "$((i + 1))p") - final_value=$(printf '%s\n' "$final_values" | sed -n "$((i + 1))p") - - if [ "$initial_value" -lt "$final_value" ]; then - echo "CPU $i: Timer count has incremented. Test PASSED" - log_pass "CPU $i: Timer count has incremented. Test PASSED" - else - echo "CPU $i: Timer count has not incremented. Test FAILED" - log_fail "CPU $i: Timer count has not incremented. Test FAILED" - fail_test=true - fi - i=$((i + 1)) - done - - if [ "$fail_test" = false ]; then - log_pass "$TESTNAME : Test Passed" - echo "$TESTNAME PASS" > "$res_file" - exit 0 - else - log_fail "$TESTNAME : Test Failed" - echo "$TESTNAME FAIL" > "$res_file" - exit 1 - fi -done < "$res_file" +exit 0