fix: Write tail index even for fifo wrap around case

Related-To: NEO-7990
Signed-off-by: Jitendra Sharma <jitendra.sharma@intel.com>
This commit is contained in:
Jitendra Sharma 2024-09-30 19:02:45 +00:00 committed by Compute-Runtime-Automation
parent 2b48599c38
commit 733ca5ac28
5 changed files with 91 additions and 42 deletions

View File

@ -1653,24 +1653,19 @@ void DebugSessionImp::getNotStoppedThreads(const std::vector<EuThread::ThreadId>
}
}
bool DebugSessionImp::isValidNode(uint64_t vmHandle, uint64_t gpuVa, SIP::fifo_node &node) {
ze_result_t DebugSessionImp::isValidNode(uint64_t vmHandle, uint64_t gpuVa, SIP::fifo_node &node) {
constexpr uint32_t failsafeTimeoutMax = 100, failsafeTimeoutWait = 50;
uint32_t timeCount = 0;
while (!node.valid && (timeCount < failsafeTimeoutMax)) {
auto retVal = readGpuMemory(vmHandle, reinterpret_cast<char *>(&node), sizeof(SIP::fifo_node), gpuVa);
if (retVal != ZE_RESULT_SUCCESS) {
PRINT_DEBUGGER_ERROR_LOG("Reading FIFO failed, error = %d\n", retVal);
return false;
return retVal;
}
NEO::sleep(std::chrono::milliseconds(failsafeTimeoutWait));
timeCount += failsafeTimeoutWait;
}
if (!node.valid) {
PRINT_DEBUGGER_ERROR_LOG("%S", "Invalid entry in SW FIFO\n");
return false;
}
return true;
return ZE_RESULT_SUCCESS;
}
ze_result_t DebugSessionImp::readFifo(uint64_t vmHandle, std::vector<EuThread::ThreadId> &threadsWithAttention) {
@ -1683,29 +1678,33 @@ ze_result_t DebugSessionImp::readFifo(uint64_t vmHandle, std::vector<EuThread::T
// Drain the fifo
uint32_t drainRetries = 2, lastHead = ~0u;
uint64_t offsetTail = (sizeof(SIP::StateSaveArea)) + offsetof(struct SIP::intelgt_state_save_area_V3, fifo_tail);
uint64_t offsetHead = (sizeof(SIP::StateSaveArea)) + offsetof(struct SIP::intelgt_state_save_area_V3, fifo_head);
const uint64_t offsetTail = (sizeof(SIP::StateSaveArea)) + offsetof(struct SIP::intelgt_state_save_area_V3, fifo_tail);
const uint64_t offsetHead = (sizeof(SIP::StateSaveArea)) + offsetof(struct SIP::intelgt_state_save_area_V3, fifo_head);
const uint64_t offsetFifoSize = (sizeof(SIP::StateSaveArea)) + offsetof(struct SIP::intelgt_state_save_area_V3, fifo_size);
const uint64_t offsetFifo = gpuVa + (stateSaveAreaHeader->versionHeader.size * 8) + stateSaveAreaHeader->regHeaderV3.fifo_offset;
while (drainRetries--) {
constexpr uint32_t failsafeTimeoutWait = 50;
std::vector<uint32_t> fifoIndices(2);
uint32_t fifoHeadIndex = 0, fifoTailIndex = 0;
std::vector<uint32_t> fifoIndices(3);
uint32_t fifoHeadIndex = 0, fifoTailIndex = 0, fifoSize = 0;
auto retVal = readGpuMemory(vmHandle, reinterpret_cast<char *>(fifoIndices.data()), fifoIndices.size() * sizeof(uint32_t), gpuVa + offsetHead);
auto retVal = readGpuMemory(vmHandle, reinterpret_cast<char *>(fifoIndices.data()), fifoIndices.size() * sizeof(uint32_t), gpuVa + offsetFifoSize);
if (retVal != ZE_RESULT_SUCCESS) {
PRINT_DEBUGGER_ERROR_LOG("Reading FIFO indices failed, error = %d\n", retVal);
return retVal;
}
fifoHeadIndex = fifoIndices[0];
fifoTailIndex = fifoIndices[1];
fifoSize = fifoIndices[0];
fifoHeadIndex = fifoIndices[1];
fifoTailIndex = fifoIndices[2];
if (lastHead != fifoHeadIndex) {
drainRetries++;
}
PRINT_DEBUGGER_FIFO_LOG("fifoHeadIndex: %u fifoTailIndex: %u fifoSize: %u lastHead: %u drainRetries: %u\n",
fifoHeadIndex, fifoTailIndex, fifoSize, lastHead, drainRetries);
while (fifoTailIndex != fifoHeadIndex) {
uint32_t readSize = fifoTailIndex < fifoHeadIndex ? fifoHeadIndex - fifoTailIndex : stateSaveAreaHeader->regHeaderV3.fifo_size - fifoTailIndex;
uint32_t readSize = fifoTailIndex < fifoHeadIndex ? fifoHeadIndex - fifoTailIndex : fifoSize - fifoTailIndex;
std::vector<SIP::fifo_node> nodes(readSize);
uint64_t currentFifoOffset = offsetFifo + (sizeof(SIP::fifo_node) * fifoTailIndex);
@ -1715,8 +1714,21 @@ ze_result_t DebugSessionImp::readFifo(uint64_t vmHandle, std::vector<EuThread::T
return retVal;
}
for (uint32_t i = 0; i < readSize; i++) {
PRINT_DEBUGGER_INFO_LOG("Validate entry at index %u in SW Fifo\n", (i + fifoTailIndex));
UNRECOVERABLE_IF(!isValidNode(vmHandle, currentFifoOffset + (i * sizeof(SIP::fifo_node)), nodes[i]));
const uint64_t gpuVa = currentFifoOffset + (i * sizeof(SIP::fifo_node));
PRINT_DEBUGGER_FIFO_LOG("Validate entry at index %u in SW Fifo:: vmHandle: %" SCNx64
" gpuVa: %" SCNx64
" valid: %" SCNx8
" thread_id: %" SCNx8
" eu_id: %" SCNx8
" subslice_id: %" SCNx8
" slice_id: %" SCNx8
"\n",
(i + fifoTailIndex), vmHandle, gpuVa, nodes[i].valid, nodes[i].thread_id, nodes[i].eu_id, nodes[i].subslice_id, nodes[i].slice_id);
retVal = isValidNode(vmHandle, gpuVa, nodes[i]);
if (retVal != ZE_RESULT_SUCCESS) {
return retVal;
}
UNRECOVERABLE_IF(!nodes[i].valid);
threadsWithAttention.emplace_back(0, nodes[i].slice_id, nodes[i].subslice_id, nodes[i].eu_id, nodes[i].thread_id);
nodes[i].valid = 0;
}
@ -1729,16 +1741,18 @@ ze_result_t DebugSessionImp::readFifo(uint64_t vmHandle, std::vector<EuThread::T
if (fifoTailIndex < fifoHeadIndex) {
// then we read to the head and are done
fifoTailIndex = fifoHeadIndex;
retVal = writeGpuMemory(vmHandle, reinterpret_cast<char *>(&fifoTailIndex), sizeof(uint32_t), gpuVa + offsetTail);
if (retVal != ZE_RESULT_SUCCESS) {
PRINT_DEBUGGER_ERROR_LOG("Writing FIFO failed, error = %d\n", retVal);
return retVal;
}
} else {
// wrap around
fifoTailIndex = 0;
}
}
retVal = writeGpuMemory(vmHandle, reinterpret_cast<char *>(&fifoTailIndex), sizeof(uint32_t), gpuVa + offsetTail);
if (retVal != ZE_RESULT_SUCCESS) {
PRINT_DEBUGGER_ERROR_LOG("Writing FIFO failed, error = %d\n", retVal);
return retVal;
}
retVal = readGpuMemory(vmHandle, reinterpret_cast<char *>(&lastHead), sizeof(uint32_t), gpuVa + offsetHead);
if (retVal != ZE_RESULT_SUCCESS) {
PRINT_DEBUGGER_ERROR_LOG("Reading fifo_head failed, error = %d\n", retVal);

View File

@ -120,7 +120,7 @@ struct DebugSessionImp : DebugSession {
void validateAndSetStateSaveAreaHeader(uint64_t vmHandle, uint64_t gpuVa);
virtual void readStateSaveAreaHeader(){};
MOCKABLE_VIRTUAL ze_result_t readFifo(uint64_t vmHandle, std::vector<EuThread::ThreadId> &threadsWithAttention);
MOCKABLE_VIRTUAL bool isValidNode(uint64_t vmHandle, uint64_t gpuVa, SIP::fifo_node &node);
MOCKABLE_VIRTUAL ze_result_t isValidNode(uint64_t vmHandle, uint64_t gpuVa, SIP::fifo_node &node);
virtual uint64_t getContextStateSaveAreaGpuVa(uint64_t memoryHandle) = 0;
virtual size_t getContextStateSaveAreaSize(uint64_t memoryHandle) = 0;

View File

@ -1911,6 +1911,32 @@ TEST_F(DebugSessionTestSwFifoFixture, GivenSwFifoWhenReadingSwFifoThenFifoIsCorr
}
}
TEST_F(DebugSessionTestSwFifoFixture, GivenSwFifoWithHeadIndexAtZeroWhenReadingSwFifoThenFifoIsCorrectlyReadAndDrained) {
EXPECT_FALSE(session->stateSaveAreaHeader.empty());
stateSaveAreaHeaderPtr = reinterpret_cast<NEO::StateSaveAreaHeader *>(session->stateSaveAreaHeader.data());
stateSaveAreaHeaderPtr->regHeaderV3.fifo_head = 0;
std::vector<EuThread::ThreadId> threadsWithAttention;
session->readFifo(0, threadsWithAttention);
std::vector<SIP::fifo_node> readFifoForValidation(stateSaveAreaHeaderPtr->regHeaderV3.fifo_size);
session->readGpuMemory(0, reinterpret_cast<char *>(readFifoForValidation.data()), readFifoForValidation.size() * sizeof(SIP::fifo_node),
reinterpret_cast<uint64_t>(session->stateSaveAreaHeader.data()) + offsetFifo);
for (size_t i = fifoTail; i < readFifoForValidation.size(); i++) {
EXPECT_EQ(readFifoForValidation[i].valid, 0);
}
EXPECT_EQ(stateSaveAreaHeaderPtr->regHeaderV3.fifo_head, stateSaveAreaHeaderPtr->regHeaderV3.fifo_tail);
EXPECT_EQ(threadsWithAttention.size(), fifoVecFromTail.size());
size_t index = 0;
for (; index < fifoVecFromTail.size(); index++) {
EXPECT_EQ(threadsWithAttention[index].slice, fifoVecFromTail[index].slice_id);
EXPECT_EQ(threadsWithAttention[index].subslice, fifoVecFromTail[index].subslice_id);
EXPECT_EQ(threadsWithAttention[index].eu, fifoVecFromTail[index].eu_id);
EXPECT_EQ(threadsWithAttention[index].thread, fifoVecFromTail[index].thread_id);
}
}
TEST_F(DebugSessionTestSwFifoFixture, GivenSwFifoWhenWriteGpuMemoryFailsWhileInValidatingNodeDuringFifoReadThenErrorReturned) {
EXPECT_FALSE(session->stateSaveAreaHeader.empty());
session->writeMemoryResult = ZE_RESULT_ERROR_UNKNOWN;
@ -1968,22 +1994,14 @@ TEST(DebugSessionTest, GivenSwFifoWhenStateSaveAreaVersionIsLessThanThreeDuringF
EXPECT_EQ(ZE_RESULT_SUCCESS, session->readFifo(0, threadsWithAttention));
}
TEST_F(DebugSessionTest, GivenSwFifoNodeWhenCheckingIsValidNodeThenAfterCheckingValidityOfNodeTrueOrFalseReturned) {
zet_debug_config_t config = {};
config.pid = 0x1234;
auto hwInfo = *NEO::defaultHwInfo.get();
NEO::MockDevice *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment<NEO::MockDevice>(&hwInfo, 0));
MockDeviceImp deviceImp(neoDevice, neoDevice->getExecutionEnvironment());
auto session = std::make_unique<MockDebugSession>(config, &deviceImp);
SIP::fifo_node node1 = {0, 1, 1, 0, 0};
EXPECT_FALSE(session->isValidNode(0, 0, node1));
SIP::fifo_node node2 = {1, 1, 1, 0, 0};
EXPECT_TRUE(session->isValidNode(0, 0, node2));
TEST_F(DebugSessionTestSwFifoFixture, GivenSwFifoWhenReadingSwFifoAndIsValidNodeFailsThenFifoReadReturnsError) {
EXPECT_FALSE(session->stateSaveAreaHeader.empty());
std::vector<EuThread::ThreadId> threadsWithAttention;
session->isValidNodeResult = ZE_RESULT_ERROR_NOT_AVAILABLE;
EXPECT_EQ(ZE_RESULT_ERROR_NOT_AVAILABLE, session->readFifo(0, threadsWithAttention));
}
TEST_F(DebugSessionTest, GivenInvalidSwFifoNodeWhenCheckingIsValidNodeAndOnReadingMemoryAgainNodeTurnsValidThenTrueReturned) {
TEST_F(DebugSessionTest, GivenInvalidSwFifoNodeWhenCheckingIsValidNodeAndOnReadingMemoryAgainNodeTurnsValidThenSuccessReturned) {
zet_debug_config_t config = {};
config.pid = 0x1234;
auto hwInfo = *NEO::defaultHwInfo.get();
@ -1993,16 +2011,18 @@ TEST_F(DebugSessionTest, GivenInvalidSwFifoNodeWhenCheckingIsValidNodeAndOnReadi
// Declare node whose valid field is 0
SIP::fifo_node invalidNode = {0, 1, 1, 0, 0};
EXPECT_FALSE(session->isValidNode(0, reinterpret_cast<uint64_t>(session->readMemoryBuffer.data()), invalidNode));
EXPECT_EQ(ZE_RESULT_SUCCESS, session->isValidNode(0, reinterpret_cast<uint64_t>(session->readMemoryBuffer.data()), invalidNode));
EXPECT_FALSE(invalidNode.valid);
SIP::fifo_node correctedNode = {1, 1, 1, 0, 0};
session->readMemoryBuffer.resize(sizeof(SIP::fifo_node));
memcpy_s(session->readMemoryBuffer.data(), session->readMemoryBuffer.size(), reinterpret_cast<void *>(&correctedNode), sizeof(SIP::fifo_node));
EXPECT_TRUE(session->isValidNode(0, reinterpret_cast<uint64_t>(session->readMemoryBuffer.data()), invalidNode));
EXPECT_EQ(ZE_RESULT_SUCCESS, session->isValidNode(0, reinterpret_cast<uint64_t>(session->readMemoryBuffer.data()), invalidNode));
EXPECT_TRUE(invalidNode.valid);
}
TEST_F(DebugSessionTest, GivenInvalidSwFifoNodeWhenCheckingIsValidNodeAndOnReadingMemoryAgainReadMemoryFailsThenFalseReturned) {
TEST_F(DebugSessionTest, GivenInvalidSwFifoNodeWhenCheckingIsValidNodeAndOnReadingMemoryAgainReadMemoryFailsThenErrorReturned) {
zet_debug_config_t config = {};
config.pid = 0x1234;
auto hwInfo = *NEO::defaultHwInfo.get();
@ -2013,7 +2033,7 @@ TEST_F(DebugSessionTest, GivenInvalidSwFifoNodeWhenCheckingIsValidNodeAndOnReadi
// Declare node whose valid field is 0
SIP::fifo_node invalidNode = {0, 1, 1, 0, 0};
session->readMemoryResult = ZE_RESULT_ERROR_UNKNOWN;
EXPECT_FALSE(session->isValidNode(0, reinterpret_cast<uint64_t>(session->readMemoryBuffer.data()), invalidNode));
EXPECT_EQ(ZE_RESULT_ERROR_UNKNOWN, session->isValidNode(0, reinterpret_cast<uint64_t>(session->readMemoryBuffer.data()), invalidNode));
}
TEST_F(DebugSessionTest, givenTssMagicCorruptedWhenStateSaveAreIsReadThenHeaderIsNotSet) {

View File

@ -250,6 +250,14 @@ struct MockDebugSession : public L0::DebugSessionImp {
return ZE_RESULT_SUCCESS;
}
ze_result_t isValidNode(uint64_t vmHandle, uint64_t gpuVa, SIP::fifo_node &node) override {
if (isValidNodeResult != ZE_RESULT_SUCCESS) {
return isValidNodeResult;
} else {
return DebugSessionImp::isValidNode(vmHandle, gpuVa, node);
}
}
ze_result_t readRegistersImp(EuThread::ThreadId thread, uint32_t type, uint32_t start, uint32_t count, void *pRegisterValues) override {
readRegistersCallCount++;
readRegistersReg = type;
@ -535,6 +543,7 @@ struct MockDebugSession : public L0::DebugSessionImp {
ze_result_t writeMemoryResult = ZE_RESULT_SUCCESS;
ze_result_t writeRegistersResult = ZE_RESULT_FORCE_UINT32;
ze_result_t readThreadScratchRegistersResult = ZE_RESULT_FORCE_UINT32;
ze_result_t isValidNodeResult = ZE_RESULT_SUCCESS;
uint32_t readStateSaveAreaHeaderCalled = 0;
uint32_t readRegistersCallCount = 0;

View File

@ -105,6 +105,7 @@ struct DebugVariables { // NOLINT(clang-analyzer
constexpr static int32_t LOG_ERROR{1 << 1}; // NOLINT(readability-identifier-naming)
constexpr static int32_t LOG_THREADS{1 << 2}; // NOLINT(readability-identifier-naming)
constexpr static int32_t LOG_MEM{1 << 3}; // NOLINT(readability-identifier-naming)
constexpr static int32_t LOG_FIFO{1 << 4}; // NOLINT(readability-identifier-naming)
constexpr static int32_t DUMP_ELF{1 << 10}; // NOLINT(readability-identifier-naming)
constexpr static int32_t DUMP_TO_FILE{1 << 16}; // NOLINT(readability-identifier-naming)
};
@ -220,6 +221,11 @@ class DurationLog {
PRINT_DEBUGGER_LOG(stdout, "\nINFO: " STR, __VA_ARGS__) \
}
#define PRINT_DEBUGGER_FIFO_LOG(STR, ...) \
if (NEO::debugManager.flags.DebuggerLogBitmask.get() & NEO::DebugVariables::DEBUGGER_LOG_BITMASK::LOG_FIFO) { \
PRINT_DEBUGGER_LOG(stdout, "\nFIFO ACCESS: " STR, __VA_ARGS__) \
}
template <DebugFunctionalityLevel debugLevel>
const char *DebugSettingsManager<debugLevel>::settingsDumpFileName = "igdrcl_dumped.config";
}; // namespace NEO