From 80f1cde6b27678b34090cd55b5cc74ff84342ef9 Mon Sep 17 00:00:00 2001 From: Roman Kennke Date: Wed, 21 Oct 2026 16:14:06 +0200 Subject: [PATCH 1/2] ci: upload test reports when a watchdog-dumped job times out A test JVM that hangs runs the job into its 180-minute timeout, which ends the job as cancelled, not failed. The gdb watchdog's thread dump is then copied into test-reports by prepare_reports.sh (an always() step), but the "Upload test reports" step only runs on failure(), so the dump is lost in exactly the case the watchdog exists for. Also upload the test reports on cancellation when the watchdog left a dump (build/logs/gdb-watchdog.log), in the two jobs that have a watchdog. Runs cancelled for other reasons (e.g. superseded by a newer push) still upload nothing. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/test_workflow.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test_workflow.yml b/.github/workflows/test_workflow.yml index 85844a6656..d2b9309818 100644 --- a/.github/workflows/test_workflow.yml +++ b/.github/workflows/test_workflow.yml @@ -139,7 +139,8 @@ jobs: # GDB watchdog for debug config: dumps all native threads if the JVM hangs # inside JVMTI (e.g. the IBM SDK 8 slow-suite deadlock) before the 180-min # job timeout fires, so a thread dump lands in the test-reports artifact. - # prepare_reports.sh copies build/logs/gdb-watchdog.log on failure. + # prepare_reports.sh copies build/logs/gdb-watchdog.log, and the test + # reports are uploaded on failure or, if the dump exists, on timeout. if [[ "${{ matrix.config }}" == "debug" ]]; then mkdir -p build/logs ( @@ -233,9 +234,11 @@ jobs: with: name: (unwinding-reports) unwinding-linux-glibc-amd64 (${{ matrix.java_version }}, ${{ matrix.config }}, ${{ inputs.slow_tests && 'slow' || 'regular' }}) path: unwinding-reports + # A hang that runs into the job timeout ends the job as cancelled, not + # failed; upload then too if the gdb watchdog left a thread dump. - name: Upload test reports uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - if: failure() + if: failure() || (cancelled() && hashFiles('build/logs/gdb-watchdog.log') != '') with: name: (test-reports) test-linux-glibc-amd64 (${{ matrix.java_version }}, ${{ matrix.config }}, ${{ inputs.slow_tests && 'slow' || 'regular' }}) path: test-reports @@ -607,9 +610,11 @@ jobs: with: name: (unwinding-reports) unwinding-linux-glibc-aarch64 (${{ matrix.java_version }}, ${{ matrix.config }}, ${{ inputs.slow_tests && 'slow' || 'regular' }}) path: unwinding-reports + # A hang that runs into the job timeout ends the job as cancelled, not + # failed; upload then too if the gdb watchdog left a thread dump. - name: Upload test reports uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - if: failure() + if: failure() || (cancelled() && hashFiles('build/logs/gdb-watchdog.log') != '') with: name: (test-reports) test-linux-glibc-aarch64 (${{ matrix.java_version }}, ${{ matrix.config }}, ${{ inputs.slow_tests && 'slow' || 'regular' }}) path: test-reports From 600c4730b42eefef9ceaf4bed6c46683ffd46352 Mon Sep 17 00:00:00 2001 From: Roman Kennke Date: Wed, 21 Oct 2026 20:48:20 +0200 Subject: [PATCH 2/2] ci: let the hang watchdog attach, and dump Java stacks too The watchdog's gdb has never produced a dump on the GitHub runners: Ubuntu's yama ptrace_scope=1 only allows attaching to descendants, so every attach failed with "ptrace: Inappropriate ioctl for device". Run it with sudo, as the runners allow without a password. Before attaching, send the JVM SIGQUIT as well, for the Java-level picture (stacks, monitors and their owners): HotSpot prints it to stdout, J9 writes a javacore file, which prepare_reports.sh already collects. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/test_workflow.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_workflow.yml b/.github/workflows/test_workflow.yml index d2b9309818..9a33e9db1d 100644 --- a/.github/workflows/test_workflow.yml +++ b/.github/workflows/test_workflow.yml @@ -148,7 +148,12 @@ jobs: echo "::warning::GDB watchdog triggered after 20 minutes" for pid in $(pgrep -f 'java.*ddprof-test'); do echo "=== Thread dump for PID $pid ===" >> build/logs/gdb-watchdog.log - gdb -batch -ex 'thread apply all bt full' -p "$pid" >> build/logs/gdb-watchdog.log 2>&1 || true + # Java-level stacks and lock owners: HotSpot prints them to stdout, + # J9 writes a javacore file that prepare_reports.sh collects. + kill -QUIT "$pid" 2>/dev/null || true + # sudo: Ubuntu's yama ptrace_scope=1 only lets a process attach to its + # own descendants, and the JVM is not one of the watchdog's. + sudo gdb -batch -ex 'thread apply all bt full' -p "$pid" >> build/logs/gdb-watchdog.log 2>&1 || true done ) & GDB_WATCHDOG_PID=$! @@ -524,7 +529,12 @@ jobs: echo "::warning::GDB watchdog triggered after 25 minutes" for pid in $(pgrep -f 'java.*ddprof-test'); do echo "=== Thread dump for PID $pid ===" >> build/logs/gdb-watchdog.log - gdb -batch -ex 'thread apply all bt full' -p "$pid" >> build/logs/gdb-watchdog.log 2>&1 || true + # Java-level stacks and lock owners: HotSpot prints them to stdout, + # J9 writes a javacore file that prepare_reports.sh collects. + kill -QUIT "$pid" 2>/dev/null || true + # sudo: Ubuntu's yama ptrace_scope=1 only lets a process attach to its + # own descendants, and the JVM is not one of the watchdog's. + sudo gdb -batch -ex 'thread apply all bt full' -p "$pid" >> build/logs/gdb-watchdog.log 2>&1 || true done ) & GDB_WATCHDOG_PID=$!