From 115ff68bdade78b373d0fe12832d1955407fecf0 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Wed, 13 Apr 2022 16:09:35 -0400 Subject: [PATCH] kfdtest: add runtime enable and attach test Add debug attach and runtime enable test for attaching to a spawned and running process. Signed-off-by: Jonathan Kim Change-Id: I72302ff73494d9dae0c79a299508085d7ca0552b [ROCm/ROCR-Runtime commit: 097ee967d15aaf9abfb7f1d6c1acb18397c61049] --- .../rocr-runtime/tests/kfdtest/CMakeLists.txt | 1 + .../tests/kfdtest/src/KFDDBGTest.cpp | 187 ++++++++++++++++++ 2 files changed, 188 insertions(+) diff --git a/projects/rocr-runtime/tests/kfdtest/CMakeLists.txt b/projects/rocr-runtime/tests/kfdtest/CMakeLists.txt index 4e4ef6ad03..00d95d7c5f 100644 --- a/projects/rocr-runtime/tests/kfdtest/CMakeLists.txt +++ b/projects/rocr-runtime/tests/kfdtest/CMakeLists.txt @@ -196,6 +196,7 @@ set (SRC_FILES gtest-1.6.0/gtest-all.cpp src/KFDExceptionTest.cpp src/KFDGraphicsInterop.cpp src/KFDPerfCounters.cpp + src/KFDDBGTest.cpp src/KFDGWSTest.cpp src/KFDIPCTest.cpp src/KFDASMTest.cpp diff --git a/projects/rocr-runtime/tests/kfdtest/src/KFDDBGTest.cpp b/projects/rocr-runtime/tests/kfdtest/src/KFDDBGTest.cpp index 224c43e46e..a93c1563dc 100644 --- a/projects/rocr-runtime/tests/kfdtest/src/KFDDBGTest.cpp +++ b/projects/rocr-runtime/tests/kfdtest/src/KFDDBGTest.cpp @@ -21,6 +21,7 @@ * */ +#include "BaseDebug.hpp" #include "KFDDBGTest.hpp" #include #include @@ -50,3 +51,189 @@ void KFDDBGTest::TearDown() { ROUTINE_END } +/* + * To test debug attaching to a spawned process (i.e. attach prior to the tracee + * opening a KFD device), have the child request the parent to PTRACE attach and + * wait for the parent to debug attach then allow the child to runtime enable. + * + * The following will be exercised: + * - The KFD shall create a KFD process on behalf of the tracee during debug + * attach since the tracee has not opened a KFD device. + * - Runtime enable on the tracee shall raise an event to the debugging parent + * and block until parent has signalled that it has recieved the runtime + * enable event. + * - Tracee should follow a similar hand shake for runtime disable and debug + * detach should follow. + * + * */ +TEST_F(KFDDBGTest, AttachToSpawnedProcess) { + TEST_START(TESTPROFILE_RUNALL) + if (m_FamilyId >= FAMILY_AI) { + + if (hsaKmtCheckRuntimeDebugSupport()) { + LOG() << "Skip test as debug API not supported"; + goto exit; + } + + pid_t childPid = fork(); + + if (childPid == 0) { /* Debugged process */ + uint32_t rDebug; + int r; + + /* Let parent become the debugger and wait for attach. */ + ptrace(PTRACE_TRACEME); + raise(SIGSTOP); + + r = hsaKmtOpenKFD(); + + if (r != HSAKMT_STATUS_SUCCESS) { + WARN() << "KFD open failed in debugged process" << std::endl; + exit(1); + } + + LOG() << std::dec << "--- Debugged PID " << getpid() << " runtime enable" << std::endl; + + r = hsaKmtRuntimeEnable(&rDebug, true); + + if (r != HSAKMT_STATUS_SUCCESS) { + WARN() << "Runtime enabled failed" << std::endl; + exit(1); + } + + LOG() << std::dec << "--- Debugged PID " << getpid() << " runtime disable and exit" << std::endl; + + hsaKmtRuntimeDisable(); + + exit(0); + } else { + BaseDebug *debug = new BaseDebug(); + struct kfd_runtime_info r_info = {0}; + uint64_t runtimeMask = KFD_EC_MASK(EC_PROCESS_RUNTIME); + int childStatus; + + waitpid(childPid, &childStatus, 0); + while (!WIFSTOPPED(childStatus)); + + /* Attach and let new debugged process continue with runtime enable */ + LOG() << std::dec << "Attaching to PID " << childPid << std::endl; + ASSERT_SUCCESS(debug->Attach(&r_info, sizeof(r_info), childPid, runtimeMask)); + ASSERT_EQ(r_info.runtime_state, DEBUG_RUNTIME_STATE_DISABLED); + ASSERT_EQ(r_info.ttmp_setup, false); + + ptrace(PTRACE_CONT, childPid, NULL, NULL); + + /* Wait and unblock runtime enable */ + ASSERT_SUCCESS(debug->QueryDebugEvent(&runtimeMask, NULL, NULL, 5000)); + ASSERT_EQ(runtimeMask, KFD_EC_MASK(EC_PROCESS_RUNTIME)); + ASSERT_SUCCESS(debug->SendRuntimeEvent(runtimeMask, 0, 0)); + + /* Wait and unblock runtime disable */ + ASSERT_SUCCESS(debug->QueryDebugEvent(&runtimeMask, NULL, NULL, 5000)); + ASSERT_EQ(runtimeMask, KFD_EC_MASK(EC_PROCESS_RUNTIME)); + ASSERT_SUCCESS(debug->SendRuntimeEvent(runtimeMask, 0, 0)); + + LOG() << std::dec << "Detaching from PID " << childPid << std::endl; + debug->Detach(); + + ptrace(PTRACE_DETACH, childPid, NULL, NULL); + + LOG() << std::dec << "Waiting on PID " << childPid << " to exit" << std::endl; + waitpid(childPid, &childStatus, 0); + EXPECT_EQ(WIFEXITED(childStatus), true); + EXPECT_EQ(WEXITSTATUS(childStatus), HSAKMT_STATUS_SUCCESS); + } + } else { + LOG() << "Skipping test: Test not supported on family ID 0x" + << m_FamilyId << "." << std::endl; + } +exit: + LOG() << std::endl; + TEST_END +} + +/* + * Unlike AttachToSpawnedProcess, the debug parent will only attach after + * a non-blocked runtime enable by the tracee. The parent should expect + * a status update that the tracee is runtime enabled on debug attach. + * Cleanup with appropriate runtime disable and debug detach handshake. + */ +TEST_F(KFDDBGTest, AttachToRunningProcess) { + TEST_START(TESTPROFILE_RUNALL) + if (m_FamilyId >= FAMILY_AI) { + + if (hsaKmtCheckRuntimeDebugSupport()) { + LOG() << "Skip test as debug API not supported"; + goto exit; + } + + pid_t childPid = fork(); + + if (childPid == 0) { /* Debugged process */ + uint32_t rDebug; + int r; + + r = hsaKmtOpenKFD(); + + if (r != HSAKMT_STATUS_SUCCESS) { + WARN() << "KFD open failed in debugged process" << std::endl; + exit(1); + } + + LOG() << std::dec << "--- Debugged PID " << getpid() << " runtime enable" << std::endl; + + r = hsaKmtRuntimeEnable(&rDebug, true); + if (r != HSAKMT_STATUS_SUCCESS) { + WARN() << "Runtime enabled failed" << std::endl; + exit(1); + } + + /* Let parent become the debugger and wait for attach. */ + ptrace(PTRACE_TRACEME); + raise(SIGSTOP); + + LOG() << std::dec << "--- Debugged PID " << getpid() << " runtime disable and exit" << std::endl; + + hsaKmtRuntimeDisable(); + + exit(0); + } else { + BaseDebug *debug = new BaseDebug(); + struct kfd_runtime_info r_info = {0}; + uint64_t runtimeMask = KFD_EC_MASK(EC_PROCESS_RUNTIME); + int childStatus; + + waitpid(childPid, &childStatus, 0); + while (!WIFSTOPPED(childStatus)); + + /* Attach to running process and let it continue */ + LOG() << std::dec << "Attaching to PID " << childPid << std::endl; + ASSERT_SUCCESS(debug->Attach(&r_info, sizeof(r_info), childPid, runtimeMask)); + ASSERT_EQ(r_info.runtime_state, DEBUG_RUNTIME_STATE_ENABLED); + ASSERT_EQ(r_info.ttmp_setup, true); + + ptrace(PTRACE_CONT, childPid, NULL, NULL); + + /* Wait and unblock runtime disable */ + ASSERT_SUCCESS(debug->QueryDebugEvent(&runtimeMask, NULL, NULL, 5000)); + ASSERT_EQ(runtimeMask, KFD_EC_MASK(EC_PROCESS_RUNTIME)); + ASSERT_SUCCESS(debug->SendRuntimeEvent(runtimeMask, 0, 0)); + + LOG() << std::dec << "Detaching from PID " << childPid << std::endl; + debug->Detach(); + + ptrace(PTRACE_DETACH, childPid, NULL, NULL); + + LOG() << std::dec << "Waiting on PID " << childPid << " to exit" << std::endl; + waitpid(childPid, &childStatus, 0); + EXPECT_EQ(WIFEXITED(childStatus), true); + EXPECT_EQ(WEXITSTATUS(childStatus), HSAKMT_STATUS_SUCCESS); + } + } else { + LOG() << "Skipping test: Test not supported on family ID 0x" + << m_FamilyId << "." << std::endl; + } +exit: + LOG() << std::endl; + TEST_END +}