Implement memory fault analysis through context save area
When a fatal memory fault occurs the scheduler context-saves all queues in the process and notifies the runtime through the memory event. The saved state contains all GPR/LDS data at the moment of the fault. Retrieve this state and present it to the user if HSA_DEBUG_FAULT is set to "analyze" and the wavefront caused the fault. If amdgcn-capable objdump is in the PATH invoke this to disassemble code around the PC. Queue lifetime is now managed by the runtime to allow querying the context save state for all active queues. Change-Id: I6fee662fad1c4f9aa125bf5c53d7d0ea1ab32f95
このコミットが含まれているのは:
@@ -53,6 +53,7 @@
|
||||
|
||||
#include "core/inc/hsa_ext_interface.h"
|
||||
#include "core/inc/amd_cpu_agent.h"
|
||||
#include "core/inc/amd_debugger.h"
|
||||
#include "core/inc/amd_gpu_agent.h"
|
||||
#include "core/inc/amd_memory_region.h"
|
||||
#include "core/inc/amd_topology.h"
|
||||
@@ -916,55 +917,24 @@ void Runtime::BindVmFaultHandler() {
|
||||
return;
|
||||
}
|
||||
|
||||
SetAsyncSignalHandler(core::Signal::Convert(vm_fault_signal_),
|
||||
HSA_SIGNAL_CONDITION_NE, 0, VMFaultHandler,
|
||||
reinterpret_cast<void*>(vm_fault_signal_));
|
||||
SetAsyncSignalHandler(core::Signal::Convert(vm_fault_signal_), HSA_SIGNAL_CONDITION_NE, 0,
|
||||
VMFaultHandler, this);
|
||||
}
|
||||
}
|
||||
|
||||
bool Runtime::VMFaultHandler(hsa_signal_value_t val, void* arg) {
|
||||
core::InterruptSignal* vm_fault_signal =
|
||||
reinterpret_cast<core::InterruptSignal*>(arg);
|
||||
Runtime* runtime = reinterpret_cast<Runtime*>(arg);
|
||||
assert(runtime->vm_fault_signal_ != NULL);
|
||||
|
||||
assert(vm_fault_signal != NULL);
|
||||
HsaEvent* vm_fault_event = runtime->vm_fault_signal_->EopEvent();
|
||||
const HsaMemoryAccessFault& fault = vm_fault_event->EventData.EventData.MemoryAccessFault;
|
||||
|
||||
if (vm_fault_signal == NULL) {
|
||||
return false;
|
||||
}
|
||||
auto agent_it = std::find_if(runtime->gpu_agents_.begin(), runtime->gpu_agents_.end(),
|
||||
[&](Agent* agent) { return agent->node_id() == fault.NodeId; });
|
||||
assert(agent_it != runtime->gpu_agents_.end());
|
||||
|
||||
if (runtime_singleton_->flag().enable_vm_fault_message()) {
|
||||
HsaEvent* vm_fault_event = vm_fault_signal->EopEvent();
|
||||
amd::Debugger::HandleFault(fault, static_cast<amd::GpuAgentInt*>(*agent_it));
|
||||
|
||||
const HsaMemoryAccessFault& fault =
|
||||
vm_fault_event->EventData.EventData.MemoryAccessFault;
|
||||
|
||||
std::string reason = "";
|
||||
if (fault.Failure.NotPresent == 1) {
|
||||
reason += "Page not present or supervisor privilege";
|
||||
} else if (fault.Failure.ReadOnly == 1) {
|
||||
reason += "Write access to a read-only page";
|
||||
} else if (fault.Failure.NoExecute == 1) {
|
||||
reason += "Execute access to a page marked NX";
|
||||
} else if (fault.Failure.GpuAccess == 1) {
|
||||
reason += "Host access only";
|
||||
} else if (fault.Failure.ECC == 1) {
|
||||
reason += "ECC failure (if supported by HW)";
|
||||
} else {
|
||||
reason += "Unknown";
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
"Memory access fault by GPU node-%u on address %p%s. Reason: %s.\n",
|
||||
fault.NodeId, reinterpret_cast<const void*>(fault.VirtualAddress),
|
||||
(fault.Failure.Imprecise == 1) ? "(may not be exact address)" : "",
|
||||
reason.c_str());
|
||||
} else {
|
||||
assert(false && "GPU memory access fault.");
|
||||
}
|
||||
|
||||
std::abort();
|
||||
|
||||
// No need to keep the signal because we are done.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
新しいイシューから参照
ユーザーをブロックする