From 6e0aa72a8973637f0d1d495e1d0afe553ecaeaa8 Mon Sep 17 00:00:00 2001 From: Philip Yang Date: Tue, 17 Aug 2021 17:51:44 -0400 Subject: [PATCH] kfdtest: add KFDSVMRangeTest ReadOnlyRangeTest Map readonly range to GPU, test GPU can read range but write to range trigger GPU vm fault. Change-Id: Id2ce106055a353f21f4c34fa7f562d546523bc49 Signed-off-by: Philip Yang [ROCm/ROCR-Runtime commit: f9648c501464d32c7824441f4599d042fbced53a] --- .../tests/kfdtest/src/KFDSVMRangeTest.cpp | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/projects/rocr-runtime/tests/kfdtest/src/KFDSVMRangeTest.cpp b/projects/rocr-runtime/tests/kfdtest/src/KFDSVMRangeTest.cpp index 6c7e3fd2af..937849d6b3 100644 --- a/projects/rocr-runtime/tests/kfdtest/src/KFDSVMRangeTest.cpp +++ b/projects/rocr-runtime/tests/kfdtest/src/KFDSVMRangeTest.cpp @@ -1257,3 +1257,127 @@ TEST_F(KFDSVMRangeTest, MigrateFileBackedRangeTest) { TEST_END } + +/* + * Test SVM support read only range + * + * Map read only range to GPU, test sdma can read the range + * write to range should trigger GPU vm fault for both xnack on and off + */ +TEST_F(KFDSVMRangeTest, ReadOnlyRangeTest) { + TEST_REQUIRE_ENV_CAPABILITIES(ENVCAPS_64BITLINUX); + TEST_START(TESTPROFILE_RUNALL); + + if (!SVMAPISupported()) + return; + + int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode(); + ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node"; + + if (!GetVramSize(defaultGPUNode)) { + LOG() << "Skipping test: No VRAM found." << std::endl; + return; + } + + /* + * Use child process to run test because the test trigger GPU vm fault, KFD evict all user queues + * of the process and no more test can run after vm fault on the process. + */ + int pid = fork(); + if (pid == 0) { + if (hsaKmtOpenKFD() != HSAKMT_STATUS_SUCCESS) { + WARN() << "KFD open failed in child process" << std::endl; + exit(1); + } + } else { + int childStatus; + + waitpid(pid, &childStatus, 0); + if (is_dgpu()) { + EXPECT_EQ(true, WIFEXITED(childStatus)); + EXPECT_EQ(0, WEXITSTATUS(childStatus)); + } else { + EXPECT_EQ(true, WIFSIGNALED(childStatus)); + EXPECT_EQ(SIGSEGV, WTERMSIG(childStatus)); + } + + return; + } + + /* Use child process to run test */ + int ret = 0; + HsaSVMRange inBuffer(PAGE_SIZE * 2, defaultGPUNode); + HSAuint8 *pinBuf = inBuffer.As(); + + memset(pinBuf, 0x55, PAGE_SIZE); + + /* Map readonly pinBuf to GPU, sDMA should be able to read it */ + mprotect(pinBuf, PAGE_SIZE, PROT_READ); + + HsaSVMRange outputBuffer(PAGE_SIZE, defaultGPUNode); + HSAuint8 *pBuf = outputBuffer.As(); + + HsaEvent *vmFaultEvent; + HSAuint64 faultAddress; + HsaEventDescriptor eventDesc; + eventDesc.EventType = HSA_EVENTTYPE_MEMORY; + eventDesc.NodeId = defaultGPUNode; + eventDesc.SyncVar.SyncVar.UserData = NULL; + eventDesc.SyncVar.SyncVarSize = 0; + + ret = hsaKmtCreateEvent(&eventDesc, true, false, &vmFaultEvent); + if (ret != HSAKMT_STATUS_SUCCESS) { + WARN() << "Event create failed" << std::endl; + exit(ret); + } + + SDMAQueue sdmaQueue; + + ret = sdmaQueue.Create(defaultGPUNode); + if (ret != HSAKMT_STATUS_SUCCESS) { + WARN() << "Queue create failed" << std::endl; + goto queue_fail; + } + sdmaQueue.PlaceAndSubmitPacket(SDMACopyDataPacket(sdmaQueue.GetFamilyId(), + pBuf, reinterpret_cast(pinBuf), PAGE_SIZE)); + sdmaQueue.Wait4PacketConsumption(); + EXPECT_EQ(0x55, pBuf[0]); + if (pBuf[0] != 0x55) + goto event_fail; + + /* sDMA write to readonly pinBuf should fail with GPU vm fault, check if pinBuf content is + * not changed, and KFD send HSA_EVENTTYPE_MEMORY event back with fault address pinBuf. + * + * This must be the last step of test because all queues are evicted after vm fault. + */ + + memset(pBuf, 0xAA, PAGE_SIZE); + sdmaQueue.PlaceAndSubmitPacket(SDMACopyDataPacket(sdmaQueue.GetFamilyId(), + pinBuf, reinterpret_cast(pBuf), PAGE_SIZE)); + + ret = hsaKmtWaitOnEvent(vmFaultEvent, g_TestTimeOut); + if (ret != HSAKMT_STATUS_SUCCESS) { + WARN() << "Wait failed. No Exception triggered" << std::endl; + goto event_fail; + } + if (vmFaultEvent->EventData.EventType != HSA_EVENTTYPE_MEMORY) { + WARN() << "Unexpected Event Received " << vmFaultEvent->EventData.EventType << std::endl; + ret = HSAKMT_STATUS_ERROR; + + goto event_fail; + } + faultAddress = vmFaultEvent->EventData.EventData.MemoryAccessFault.VirtualAddress; + if (faultAddress != (HSAuint64)pinBuf) { + WARN() << "Unexpected Fault Address " << faultAddress << std::endl; + ret = HSAKMT_STATUS_ERROR; + } + +event_fail: + EXPECT_SUCCESS(sdmaQueue.Destroy()); +queue_fail: + hsaKmtDestroyEvent(vmFaultEvent); + /* Child process exit, otherwise it will continue to run remaining tests */ + exit(ret); + + TEST_END +}