From 8311ca5bfa41b5a296057a05be0cad9e3009cdb0 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Fri, 28 Jul 2023 12:54:49 -0400 Subject: [PATCH] kfdtest: add address watch test Address watch test will test read and write operations. Test will also check if operation is precise if precise address watch is available. Signed-off-by: Jonathan Kim Change-Id: I7ef835790e26bf6345682755d7dd26a35853bcd5 --- tests/kfdtest/src/KFDDBGTest.cpp | 112 ++++++++++++++++++++++++++++++ tests/kfdtest/src/ShaderStore.cpp | 36 ++++++++++ tests/kfdtest/src/ShaderStore.hpp | 5 ++ 3 files changed, 153 insertions(+) diff --git a/tests/kfdtest/src/KFDDBGTest.cpp b/tests/kfdtest/src/KFDDBGTest.cpp index 3d5e11eede..51edc5a512 100644 --- a/tests/kfdtest/src/KFDDBGTest.cpp +++ b/tests/kfdtest/src/KFDDBGTest.cpp @@ -518,3 +518,115 @@ exit: LOG() << std::endl; TEST_END } + +TEST_F(KFDDBGTest, HitAddressWatch) { + TEST_START(TESTPROFILE_RUNALL) + if (m_FamilyId >= FAMILY_VI) { + int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode(); + + if (hsaKmtCheckRuntimeDebugSupport()) { + LOG() << "Skip test as debug API not supported"; + goto exit; + } + + ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node"; + HsaNodeProperties nodeProps; + ASSERT_SUCCESS(hsaKmtGetNodeProperties(defaultGPUNode, &nodeProps)); + + HsaMemoryBuffer readerBuf(PAGE_SIZE, defaultGPUNode, true, false, true); + HsaMemoryBuffer writerBuf(PAGE_SIZE, defaultGPUNode, true, false, true); + HsaMemoryBuffer trap(PAGE_SIZE*2, defaultGPUNode, true, false, true); + HsaMemoryBuffer tmaBuf(PAGE_SIZE, defaultGPUNode, false, false, false); + + ASSERT_SUCCESS(m_pAsm->RunAssembleBuf(watch_read_isa, readerBuf.As())); + ASSERT_SUCCESS(m_pAsm->RunAssembleBuf(watch_write_isa, writerBuf.As())); + ASSERT_SUCCESS(m_pAsm->RunAssembleBuf(trap_handler_gfx, trap.As())); + ASSERT_SUCCESS(hsaKmtSetTrapHandler(defaultGPUNode, + trap.As(), + 0x1000, + tmaBuf.As(), + 0x1000)); + + uint32_t rDebug; + ASSERT_SUCCESS(hsaKmtRuntimeEnable(&rDebug, true)); + + struct kfd_runtime_info r_info = {0}; + BaseDebug *debug = new BaseDebug(); + ASSERT_SUCCESS(debug->Attach(&r_info, sizeof(r_info), getpid(), 0)); + ASSERT_EQ(r_info.runtime_state, DEBUG_RUNTIME_STATE_ENABLED); + + const std::vector gpuNodes = m_NodeInfo.GetNodesWithGPU(); + uint32_t numDevices = gpuNodes.size(); + struct kfd_dbg_device_info_entry deviceInfo[numDevices] = {0}; + ASSERT_SUCCESS(debug->DeviceSnapshot(0, (uint64_t)(&deviceInfo[0]), &numDevices)); + ASSERT_EQ(numDevices, gpuNodes.size()); + bool is_precise = nodeProps.Capability.ui32.PreciseMemoryOperationsSupported; + + if (is_precise) { + uint32_t trapFlags = KFD_DBG_TRAP_FLAG_SINGLE_MEM_OP; + ASSERT_SUCCESS(debug->SetFlags(&trapFlags)); + } + + uint32_t enableMask = KFD_DBG_TRAP_MASK_DBG_ADDRESS_WATCH; + uint32_t supportedMask = enableMask; + ASSERT_SUCCESS(debug->SetWaveLaunchOverride(KFD_DBG_TRAP_OVERRIDE_OR, + &enableMask, + &supportedMask)); + ASSERT_NE(supportedMask & KFD_DBG_TRAP_MASK_DBG_ADDRESS_WATCH, 0); + ASSERT_EQ(enableMask & KFD_DBG_TRAP_MASK_DBG_ADDRESS_WATCH, 0); // previous set mask + + PM4Queue queue; + ASSERT_SUCCESS(queue.Create(defaultGPUNode)); + const uint32_t watchMask = -1 & UINT_MAX; + + HsaMemoryBuffer targetBuf(PAGE_SIZE, defaultGPUNode, true, false, false); + HsaMemoryBuffer resultBuf(PAGE_SIZE, defaultGPUNode, true, false, false); + unsigned int *target = targetBuf.As(); + unsigned int *result = resultBuf.As(); + + for (int mode = KFD_DBG_TRAP_ADDRESS_WATCH_MODE_READ; + mode < KFD_DBG_TRAP_ADDRESS_WATCH_MODE_ALL; mode++) { + + // atomics may not be supported on all devices so skip for now. + if (mode != KFD_DBG_TRAP_ADDRESS_WATCH_MODE_READ && + mode != KFD_DBG_TRAP_ADDRESS_WATCH_MODE_NONREAD) + continue; + + uint32_t watchId = -1; + ASSERT_SUCCESS(debug->SetAddressWatch((uint64_t)(&target[0]), mode, + watchMask, deviceInfo[0].gpu_id, &watchId)); + ASSERT_EQ(watchId, 0); + + const HsaMemoryBuffer &shaderBuf = + mode == KFD_DBG_TRAP_ADDRESS_WATCH_MODE_READ ? readerBuf : writerBuf; + uint32_t preciseMask = 0x1; + uint32_t watchStsMask = 0x80; + result[0] = preciseMask; + Dispatch dispatch(shaderBuf); + dispatch.SetDim(1, 1, 1); + dispatch.SetArgs(&target[0], &result[0]); + dispatch.SetPriv(false); // Override GFX11 CWSR WA + dispatch.Submit(queue); + dispatch.Sync(); + + ASSERT_EQ(result[0] & watchStsMask, watchStsMask); + + if (is_precise) + ASSERT_EQ(result[0] & preciseMask, preciseMask); + + ASSERT_SUCCESS(debug->ClearAddressWatch(deviceInfo[0].gpu_id, watchId)); + resultBuf.Fill(0); + targetBuf.Fill(0); + } + + ASSERT_SUCCESS(queue.Destroy()); + debug->Detach(); + hsaKmtRuntimeDisable(); + } else { + LOG() << "Skipping test: Test not supported on family ID 0x" + << m_FamilyId << "." << std::endl; + } +exit: + LOG() << std::endl; + TEST_END +} diff --git a/tests/kfdtest/src/ShaderStore.cpp b/tests/kfdtest/src/ShaderStore.cpp index 827072ee5a..08d82612ee 100644 --- a/tests/kfdtest/src/ShaderStore.cpp +++ b/tests/kfdtest/src/ShaderStore.cpp @@ -926,6 +926,12 @@ const char *trap_handler_gfx = s_getreg_b32 ttmp14, hwreg(HW_REG_TRAPSTS) s_and_b32 ttmp2, ttmp14, 0x800 s_cbranch_scc1 RESTORE_AND_EXIT + /*check for address watch event and record pc check point delta*/ + s_and_b32 ttmp2, ttmp14, 0x7080 + s_cbranch_scc0 GET_DOORBELL + v_mov_b32 v5, v4 // capture watch checkpoint + v_mov_b32 v6, ttmp14 // capture watch trapsts + s_branch RESTORE_AND_EXIT GET_DOORBELL: .if .amdgcn.gfx_generation_number < 11 s_mov_b32 ttmp2, exec_lo @@ -971,3 +977,33 @@ const char *trap_handler_gfx = s_setreg_b32 hwreg(HW_REG_STATUS), ttmp12 s_rfe_b64 [ttmp0, ttmp1] )"; + +#define WATCH_START SHADER_START SHADER_MACROS_U32\ + "v_mov_b32 v0, s0\n"\ + "v_mov_b32 v1, s1\n"\ + "v_mov_b32 v2, s2\n"\ + "v_mov_b32 v3, s3\n"\ + "flat_load_dword v4, v[2:3]\n"\ + "s_waitcnt vmcnt(0) & lgkmcnt(0)\n"\ + "v_mov_b32 v5, 0\n"\ + "v_mov_b32 v6, 0\n" + +#define WATCH_END "\n"\ + "v_mov_b32 v4, 2\n"\ + "LOOP:\n"\ + "V_CMP_EQ_U32 v6, 0\n"\ + "s_cbranch_vccnz LOOP\n"\ + "V_ADD_CO_U32 v6, v6, v5\n"\ + "flat_store_dword v[2:3], v6\n"\ + "s_waitcnt vmcnt(0) & lgkmcnt(0)\n"\ + "s_endpgm\n" + +const char *watch_read_isa = + WATCH_START + "flat_load_dword v7, v[0:1]" + WATCH_END; + +const char *watch_write_isa = + WATCH_START + "flat_store_dword v[0:1], v4" + WATCH_END; diff --git a/tests/kfdtest/src/ShaderStore.hpp b/tests/kfdtest/src/ShaderStore.hpp index e975e28499..cfcfb2761c 100644 --- a/tests/kfdtest/src/ShaderStore.hpp +++ b/tests/kfdtest/src/ShaderStore.hpp @@ -66,4 +66,9 @@ extern const char *GwsAtomicIncreaseIsa; extern const char *jump_to_trap_gfx; extern const char *trap_handler_gfx; +/* HitWatchPointEvent */ +extern const char *watch_read_isa; +extern const char *watch_write_isa; +extern const char *watch_atomic_isa; + #endif // _SHADERSTORE_H_