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 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. #