diff --git a/Runner/suites/Multimedia/Graphics/KMSCube/README_KMSCube.md b/Runner/suites/Multimedia/Graphics/KMSCube/README_KMSCube.md index 5c31fdbe..c05b2b6d 100644 --- a/Runner/suites/Multimedia/Graphics/KMSCube/README_KMSCube.md +++ b/Runner/suites/Multimedia/Graphics/KMSCube/README_KMSCube.md @@ -83,11 +83,20 @@ applicable desktop systems. An explicit `--base` request on Ubuntu Desktop reports SKIP because the supported Ubuntu graphics configuration is the Qualcomm overlay. -KMSCube execution is bounded to 60 seconds by default. `--timeout SECONDS` -changes that limit. A timeout is reported as FAIL, and display-manager or Weston -state stopped by the suite is restored before exit. `-h` and `--help` print -usage and exit without changing package, GPU, display-manager, or Weston state. -Unknown arguments are reported as FAIL. +The suite detects the capabilities of the installed `kmscube` instead of +assuming one package implementation. A build advertising `--count` runs in the +foreground with `--count=999`, preserving the DRM/page-flip behavior of the +Yocto implementation. Its exit status and rendered-frame summary are both +validated. Standard builds without `--count`, including the common Debian +package, run continuously under the managed timeout. For those builds, reaching +the timeout is the expected controlled completion, and retained EGL plus OpenGL +initialization output is required for PASS. + +`--timeout SECONDS` changes the continuous-build runtime from its 60-second +default. Display-manager or Weston state stopped by the suite is restored before +the final result. `-h` and `--help` print usage and exit without changing +package, GPU, display-manager, or Weston state. Unknown arguments are reported +as FAIL. #### Sample output: ``` @@ -116,12 +125,15 @@ sh-5.2# - It validates the graphics gles2 functionalities. - If any critical tool is missing, the script exits with an error message. -- A non-zero KMSCube exit status, insufficient rendered frames, or a - case-insensitive `ERROR`, `FAIL`, `FAILED`, or `FAILURE` marker in the retained - KMSCube output is classified as FAIL. Common zero-failure summaries such as - `Failed: 0` and `0 failed` are ignored. +- A non-zero finite-run exit status, insufficient rendered frames, a missing + finite-run frame summary, an unexpected continuous-run exit, missing EGL or + OpenGL initialization evidence, or a case-insensitive `ERROR`, `FAIL`, + `FAILED`, or `FAILURE` marker in the retained KMSCube output is classified as + FAIL. Common zero-failure summaries such as `Failed: 0` and `0 failed` are + ignored. - Output markers are retained in `KMSCube_failure_markers.log` and the complete command output remains in `KMSCube_run.log`. +- Capability-probe output is retained in `KMSCube_capabilities.log`. ## CentOS Stream 10 overlay preparation diff --git a/Runner/suites/Multimedia/Graphics/KMSCube/run.sh b/Runner/suites/Multimedia/Graphics/KMSCube/run.sh index e34f17e1..e73fa2d4 100755 --- a/Runner/suites/Multimedia/Graphics/KMSCube/run.sh +++ b/Runner/suites/Multimedia/Graphics/KMSCube/run.sh @@ -15,7 +15,7 @@ Options: --base Use upstream MSM/freedreno on supported desktop distros. --overlay Use the Qualcomm graphics overlay on supported desktop distros. --auto Preserve and validate the currently active graphics stack. - --timeout SECONDS Stop kmscube if it exceeds this duration, default: 60. + --timeout SECONDS Set continuous-build runtime, default: 60. -h, --help Show this help text and exit without changing target state. EOF } @@ -135,6 +135,7 @@ cd "$test_path" || exit 1 LOG_FILE="./${TESTNAME}_run.log" FAILURE_LOG="./${TESTNAME}_failure_markers.log" +CAPABILITY_LOG="./${TESTNAME}_capabilities.log" if [ "$PARSE_RC" -ne 0 ]; then rm -f "$RES_FILE" @@ -175,6 +176,7 @@ rm -f \ "$RES_FILE" \ "$LOG_FILE" \ "$FAILURE_LOG" \ + "$CAPABILITY_LOG" \ "$DISPLAY_MANAGER_STATE_FILE" trap ' @@ -465,6 +467,31 @@ if ! command -v run_with_managed_timeout >/dev/null 2>&1; then exit 0 fi +for required_helper in \ + display_kmscube_supports_count \ + display_kmscube_collect_failure_markers \ + display_kmscube_parse_frame_count \ + display_kmscube_has_initialization_evidence; do + if ! command -v "$required_helper" >/dev/null 2>&1; then + log_fail "$TESTNAME FAIL - required KMSCube helper is unavailable: $required_helper" + echo "$TESTNAME FAIL" >"$RES_FILE" + exit 0 + fi +done + +KMSCUBE_SUPPORTS_COUNT=0 + +if display_kmscube_supports_count \ + "$KMSCUBE_BIN" \ + "$CAPABILITY_LOG"; then + KMSCUBE_SUPPORTS_COUNT=1 + log_info "KMSCube capability, finite --count execution supported" +else + log_info "KMSCube capability, continuous execution without --count" +fi + +log_info "KMSCube capability output retained in $CAPABILITY_LOG" + # --- GPU acceleration gating ------------------------------------------------- if command -v display_is_cpu_renderer >/dev/null 2>&1; then if display_is_cpu_renderer gbm >/dev/null 2>&1; then @@ -528,27 +555,50 @@ EGL_PLATFORM_SAVED="${EGL_PLATFORM:-}" export EGL_PLATFORM=gbm rc=0 +KMSCUBE_EXECUTION_MODE="continuous" + +if [ "$KMSCUBE_SUPPORTS_COUNT" -eq 1 ]; then + KMSCUBE_EXECUTION_MODE="finite-count" + set -- "$KMSCUBE_BIN" +else + if command -v stdbuf >/dev/null 2>&1; then + set -- stdbuf -oL -eL "$KMSCUBE_BIN" + log_info "Using stdbuf so continuous KMSCube initialization output is retained" + else + set -- "$KMSCUBE_BIN" + log_warn "stdbuf is unavailable, continuous KMSCube output may remain buffered until exit" + fi +fi if [ -n "$KMSCUBE_DRM_DEV" ]; then - log_info "Running kmscube on $KMSCUBE_DRM_DEV with --count=${FRAME_COUNT}, timeout=${KMSCUBE_TIMEOUT}s" + set -- "$@" -D "$KMSCUBE_DRM_DEV" +fi - run_with_managed_timeout \ - "$KMSCUBE_TIMEOUT" \ - /tmp \ - kmscube \ - "$KMSCUBE_BIN" \ - -D "$KMSCUBE_DRM_DEV" \ - --count="${FRAME_COUNT}" >"$LOG_FILE" 2>&1 - rc=$? +if [ "$KMSCUBE_SUPPORTS_COUNT" -eq 1 ]; then + set -- "$@" --count="${FRAME_COUNT}" + + if [ -n "$KMSCUBE_DRM_DEV" ]; then + log_info "Running finite kmscube on $KMSCUBE_DRM_DEV with --count=${FRAME_COUNT}" + else + log_info "Running finite kmscube with default DRM device selection and --count=${FRAME_COUNT}" + fi else - log_info "Running kmscube with default DRM device selection and --count=${FRAME_COUNT}, timeout=${KMSCUBE_TIMEOUT}s" + if [ -n "$KMSCUBE_DRM_DEV" ]; then + log_info "Running continuous kmscube on $KMSCUBE_DRM_DEV for ${KMSCUBE_TIMEOUT}s" + else + log_info "Running continuous kmscube with default DRM device selection for ${KMSCUBE_TIMEOUT}s" + fi +fi +if [ "$KMSCUBE_SUPPORTS_COUNT" -eq 1 ]; then + "$@" >"$LOG_FILE" 2>&1 + rc=$? +else run_with_managed_timeout \ "$KMSCUBE_TIMEOUT" \ /tmp \ kmscube \ - "$KMSCUBE_BIN" \ - --count="${FRAME_COUNT}" >"$LOG_FILE" 2>&1 + "$@" >"$LOG_FILE" 2>&1 rc=$? fi @@ -558,45 +608,20 @@ else unset EGL_PLATFORM fi -if [ "$rc" -eq 124 ]; then - log_fail "$TESTNAME : Execution timed out after ${KMSCUBE_TIMEOUT}s - see $LOG_FILE" - cat "$LOG_FILE" - echo "$TESTNAME FAIL" >"$RES_FILE" - - if [ "$weston_stopped_by_test" -eq 1 ]; then - log_info "Restoring Weston after timeout" - - if weston_restore_runtime 15; then - weston_stopped_by_test=0 - else - log_error "Failed to restore Weston runtime after $TESTNAME timeout" - fi - fi +POSTPROCESS_FAILURE="" - display_restore_service_from_state "$DISPLAY_MANAGER_STATE_FILE" || true - exit 1 +if FAILURE_MARKER_COUNT="$( + display_kmscube_collect_failure_markers \ + "$LOG_FILE" \ + "$FAILURE_LOG" +)"; then + : +else + FAILURE_MARKER_COUNT=0 + POSTPROCESS_FAILURE="unable to parse KMSCube failure markers from $LOG_FILE" + log_error "$POSTPROCESS_FAILURE" fi -# Treat explicit error and failure words from kmscube as authoritative even -# when the process exits successfully. Ignore common zero-failure summaries. -awk ' - { - line = tolower($0) - has_error = line ~ /(^|[^[:alnum:]_])error([^[:alnum:]_]|$)/ - has_failure = line ~ /(^|[^[:alnum:]_])fail(ed|ure|ures)?([^[:alnum:]_]|$)/ - zero_failure = ( - line ~ /fail(ed|ure|ures)?[[:space:]]*[:=][[:space:]]*0([^0-9]|$)/ || - line ~ /(^|[^0-9])0[[:space:]]+(tests?[[:space:]]+)?fail(ed|ure|ures)?([^[:alnum:]_]|$)/ - ) - - if ((has_error || has_failure) && !zero_failure) { - print - } - } -' "$LOG_FILE" >"$FAILURE_LOG" - -FAILURE_MARKER_COUNT="$(awk 'END { print NR + 0 }' "$FAILURE_LOG")" - if [ "$FAILURE_MARKER_COUNT" -gt 0 ]; then log_error "kmscube reported ERROR or FAIL output, matches=$FAILURE_MARKER_COUNT artifact=$FAILURE_LOG" @@ -606,57 +631,34 @@ if [ "$FAILURE_MARKER_COUNT" -gt 0 ]; then done <"$FAILURE_LOG" fi -if [ "$rc" -ne 0 ]; then - log_fail "$TESTNAME : Execution failed (rc=$rc) - see $LOG_FILE" - cat "$LOG_FILE" - echo "$TESTNAME FAIL" >"$RES_FILE" - - if [ "$weston_stopped_by_test" -eq 1 ]; then - log_info "Restoring Weston after failure" - - if weston_restore_runtime 15; then - weston_stopped_by_test=0 - else - log_error "Failed to restore Weston runtime after $TESTNAME failure" - fi - fi - - display_restore_service_from_state "$DISPLAY_MANAGER_STATE_FILE" || true - exit 1 +# --- Parse rendered frame count ---------------------------------------------- +if FRAMES_RENDERED="$( + display_kmscube_parse_frame_count "$LOG_FILE" +)"; then + : +else + FRAMES_RENDERED="" + POSTPROCESS_FAILURE="unable to parse the rendered-frame summary from $LOG_FILE" + log_error "$POSTPROCESS_FAILURE" fi -# --- Parse rendered frame count ---------------------------------------------- -FRAMES_RENDERED="$( - awk ' - BEGIN { - IGNORECASE = 1 - } - - /Rendered[[:space:]][0-9]+[[:space:]]+frames/ { - for (i = 1; i <= NF; i++) { - if ($i ~ /^[0-9]+$/) { - n = $i - } - } - - last = n - } - - END { - if (last != "") { - print last - } - } - ' "$LOG_FILE" -)" +KMSCUBE_INITIALIZED=0 -[ -n "$FRAMES_RENDERED" ] || FRAMES_RENDERED=0 +if display_kmscube_has_initialization_evidence "$LOG_FILE"; then + KMSCUBE_INITIALIZED=1 +fi if [ "$EXPECTED_MIN" -lt 0 ]; then EXPECTED_MIN=0 fi -log_info "kmscube reported: Rendered ${FRAMES_RENDERED} frames (requested ${FRAME_COUNT}, min acceptable ${EXPECTED_MIN})" +if [ -n "$FRAMES_RENDERED" ]; then + log_info "kmscube reported: Rendered ${FRAMES_RENDERED} frames (requested ${FRAME_COUNT}, min acceptable ${EXPECTED_MIN})" +elif [ "$KMSCUBE_SUPPORTS_COUNT" -eq 1 ]; then + log_warn "kmscube did not emit a numeric frame summary for the finite --count run" +else + log_info "kmscube did not emit a numeric frame summary, continuous-build validation uses initialization evidence" +fi restore_failed=0 @@ -676,20 +678,48 @@ if ! display_restore_service_from_state "$DISPLAY_MANAGER_STATE_FILE"; then fi # --- Verdict ----------------------------------------------------------------- -if [ "$FAILURE_MARKER_COUNT" -gt 0 ]; then - log_fail "$TESTNAME : FAIL (kmscube reported ERROR or FAIL output, matches=${FAILURE_MARKER_COUNT})" - printf '%s\n' "$TESTNAME FAIL" >"$RES_FILE" - exit 1 +VERDICT_FAILURE="$POSTPROCESS_FAILURE" + +if [ -z "$VERDICT_FAILURE" ] && + [ "$KMSCUBE_SUPPORTS_COUNT" -eq 1 ]; then + if [ "$rc" -ne 0 ]; then + VERDICT_FAILURE="finite --count execution failed with rc=$rc" + elif [ "$FAILURE_MARKER_COUNT" -gt 0 ]; then + VERDICT_FAILURE="kmscube reported ERROR or FAIL output, matches=$FAILURE_MARKER_COUNT" + elif [ -z "$FRAMES_RENDERED" ]; then + VERDICT_FAILURE="finite --count execution emitted no recognized rendered-frame summary" + elif [ -n "$FRAMES_RENDERED" ] && + [ "$FRAMES_RENDERED" -lt "$EXPECTED_MIN" ]; then + VERDICT_FAILURE="rendered ${FRAMES_RENDERED} frames, minimum required is ${EXPECTED_MIN}" + fi +elif [ -z "$VERDICT_FAILURE" ]; then + if [ "$rc" -eq 124 ]; then + log_info "Continuous KMSCube reached the expected controlled ${KMSCUBE_TIMEOUT}s timeout" + elif [ "$rc" -eq 0 ]; then + VERDICT_FAILURE="continuous KMSCube exited before the controlled ${KMSCUBE_TIMEOUT}s validation completed" + else + VERDICT_FAILURE="continuous KMSCube execution failed with rc=$rc" + fi + + if [ -z "$VERDICT_FAILURE" ] && + [ "$FAILURE_MARKER_COUNT" -gt 0 ]; then + VERDICT_FAILURE="kmscube reported ERROR or FAIL output, matches=$FAILURE_MARKER_COUNT" + fi + + if [ -z "$VERDICT_FAILURE" ] && + [ "$KMSCUBE_INITIALIZED" -ne 1 ]; then + VERDICT_FAILURE="continuous KMSCube output did not confirm EGL and OpenGL initialization" + fi fi -if [ "$FRAMES_RENDERED" -lt "$EXPECTED_MIN" ]; then - log_fail "$TESTNAME : FAIL (rendered ${FRAMES_RENDERED} < ${EXPECTED_MIN})" - echo "$TESTNAME FAIL" >"$RES_FILE" - exit 1 +if [ "$restore_failed" -ne 0 ] && + [ -z "$VERDICT_FAILURE" ]; then + VERDICT_FAILURE="display runtime restore failed after $KMSCUBE_EXECUTION_MODE execution" fi -if [ "$restore_failed" -ne 0 ]; then - log_fail "$TESTNAME : FAIL (rendered ${FRAMES_RENDERED}, but display runtime restore failed)" +if [ -n "$VERDICT_FAILURE" ]; then + log_fail "$TESTNAME : FAIL ($VERDICT_FAILURE), see $LOG_FILE" + cat "$LOG_FILE" echo "$TESTNAME FAIL" >"$RES_FILE" exit 1 fi diff --git a/Runner/utils/lib_display.sh b/Runner/utils/lib_display.sh index ca7b3f9b..01e75ea6 100755 --- a/Runner/utils/lib_display.sh +++ b/Runner/utils/lib_display.sh @@ -6379,3 +6379,165 @@ display_apply_test_fps_gate_policy() { log_info "Desktop functional FPS gate passed, avg=$datfgp_avg (~$datfgp_rounded) >= ${DISPLAY_TEST_FPS_MIN_OK:-1} (target=${DISPLAY_TEST_FPS_EXPECTED:-unknown})" return 0 } + +# Probe whether a KMSCube executable advertises the finite --count option. +# Arguments: KMSCube executable path and capability-log path. +# Stdout: none. Returns: 0 when --count is advertised, 1 otherwise. +# Side effects: replaces the capability log with the retained help output. +display_kmscube_supports_count() { + dksc_bin="$1" + dksc_log="$2" + + : >"$dksc_log" || return 1 + + printf '%s\n' "command=$dksc_bin --help" >>"$dksc_log" + if command -v run_with_managed_timeout >/dev/null 2>&1; then + run_with_managed_timeout \ + 5 \ + /tmp \ + kmscube-capability \ + "$dksc_bin" \ + --help >>"$dksc_log" 2>&1 + else + "$dksc_bin" --help >>"$dksc_log" 2>&1 + fi + dksc_rc=$? + printf '%s\n' "exit_status=$dksc_rc" >>"$dksc_log" + + if awk ' + { + line = tolower($0) + if (line ~ /(^|[^[:alnum:]_])--count([=[:space:]]|$)/) { + found = 1 + } + } + END { exit(found ? 0 : 1) } + ' "$dksc_log"; then + return 0 + fi + + printf '%s\n' "command=$dksc_bin -h" >>"$dksc_log" + if command -v run_with_managed_timeout >/dev/null 2>&1; then + run_with_managed_timeout \ + 5 \ + /tmp \ + kmscube-capability \ + "$dksc_bin" \ + -h >>"$dksc_log" 2>&1 + else + "$dksc_bin" -h >>"$dksc_log" 2>&1 + fi + dksc_rc=$? + printf '%s\n' "exit_status=$dksc_rc" >>"$dksc_log" + + awk ' + { + line = tolower($0) + if (line ~ /(^|[^[:alnum:]_])--count([=[:space:]]|$)/) { + found = 1 + } + } + END { exit(found ? 0 : 1) } + ' "$dksc_log" +} + +# Extract KMSCube error and failure markers while ignoring zero-failure totals. +# Arguments: KMSCube output-log path and failure-marker-log path. +# Stdout: one non-negative marker count. Returns: 0 after parsing. +# Side effects: replaces the failure-marker log. +display_kmscube_collect_failure_markers() { + dkcfm_log="$1" + dkcfm_failure_log="$2" + + if ! awk ' + { + line = tolower($0) + has_error = line ~ /(^|[^[:alnum:]_])error([^[:alnum:]_]|$)/ + has_failure = line ~ /(^|[^[:alnum:]_])fail(ed|ure|ures)?([^[:alnum:]_]|$)/ + zero_failure = 0 + + if (line ~ /fail(ed|ure|ures)?[[:space:]]*[:=][[:space:]]*0([^0-9]|$)/) { + zero_failure = 1 + } + + if (line ~ /(^|[^0-9])0[[:space:]]+(tests?[[:space:]]+)?fail(ed|ure|ures)?([^[:alnum:]_]|$)/) { + zero_failure = 1 + } + + if ((has_error || has_failure) && !zero_failure) { + print + } + } + ' "$dkcfm_log" >"$dkcfm_failure_log"; then + return 1 + fi + + awk 'END { print NR + 0 }' "$dkcfm_failure_log" +} + +# Parse the last numeric rendered-frame summary from KMSCube output. +# Arguments: KMSCube output-log path. +# Stdout: the last frame count, or no output when no supported summary exists. +# Returns: 0 after parsing. Side effects: none. +display_kmscube_parse_frame_count() { + dkpf_log="$1" + + awk ' + { + line = tolower($0) + gsub(/[^[:alnum:]_]+/, " ", line) + count = split(line, fields, /[[:space:]]+/) + + for (i = 1; i <= count; i++) { + if (fields[i] == "rendered" && + fields[i + 1] ~ /^[0-9]+$/ && + fields[i + 2] == "frames") { + last = fields[i + 1] + } + + if (fields[i] == "rendered" && + fields[i + 1] == "frames" && + fields[i + 2] ~ /^[0-9]+$/) { + last = fields[i + 2] + } + + if (fields[i] ~ /^[0-9]+$/ && + fields[i + 1] == "frames" && + fields[i + 2] == "rendered") { + last = fields[i] + } + } + } + END { + if (last != "") { + print last + } + } + ' "$dkpf_log" +} + +# Check retained KMSCube output for successful EGL and OpenGL initialization. +# Arguments: KMSCube output-log path. Stdout: none. +# Returns: 0 when both EGL and OpenGL evidence are present, 1 otherwise. +# Side effects: none. +display_kmscube_has_initialization_evidence() { + dkhie_log="$1" + + awk ' + { + line = tolower($0) + + if (line ~ /using display .*egl version/ || + line ~ /egl[[:space:]_-]*information/ || + line ~ /egl[[:space:]_-]*(version|vendor)/) { + have_egl = 1 + } + + if (line ~ /opengl es/ || + line ~ /(^|[^[:alnum:]_])gl[[:space:]_-]*(version|vendor|renderer)/) { + have_gl = 1 + } + } + END { exit(have_egl && have_gl ? 0 : 1) } + ' "$dkhie_log" +}