compute-runtime/opencl/source/event/event_tracker.cpp

254 lines
7.8 KiB
C++

/*
* Copyright (C) 2018-2022 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "opencl/source/event/event_tracker.h"
#include "opencl/source/command_queue/command_queue.h"
#include "opencl/source/helpers/cl_helper.h"
#include <fstream>
namespace NEO {
std::unique_ptr<EventsTracker> EventsTracker::globalEvTracker = nullptr;
EventsTracker &EventsTracker::getEventsTracker() {
static std::mutex initMutex;
std::lock_guard<std::mutex> autolock(initMutex);
if (!EventsTracker::globalEvTracker) {
EventsTracker::globalEvTracker = std::unique_ptr<EventsTracker>{new EventsTracker()};
}
UNRECOVERABLE_IF(EventsTracker::globalEvTracker == nullptr);
return *EventsTracker::globalEvTracker;
}
std::string EventsTracker::label(Event *node, const EventIdMap &eventsIdMapping) {
std::string retLabel("e");
auto eventTag = eventsIdMapping.find(node);
if (eventTag != eventsIdMapping.end()) {
auto id = eventTag->second;
retLabel += std::to_string(id);
}
return retLabel;
}
std::string EventsTracker::label(CommandQueue *cmdQ) {
return "cq" + std::to_string(reinterpret_cast<uintptr_t>(cmdQ));
}
void EventsTracker::dumpQueue(CommandQueue *cmdQ, std::ostream &out, CmdqSet &dumpedCmdQs) {
if ((cmdQ == nullptr) || (dumpedCmdQs.find(cmdQ) != dumpedCmdQs.end())) {
return;
}
out << label(cmdQ) << "[label=\"{------CmdQueue, ptr=" << cmdQ << "------|task count=";
auto taskCount = cmdQ->taskCount;
auto taskLevel = cmdQ->taskLevel;
if (taskCount == CompletionStamp::notReady) {
out << "NOT_READY";
} else {
out << taskCount;
}
out << ", level=";
if (taskLevel == CompletionStamp::notReady) {
out << "NOT_READY";
} else {
out << taskLevel;
}
out << "}\",color=blue];\n";
dumpedCmdQs.insert(cmdQ);
}
void EventsTracker::dumpNode(Event *node, std::ostream &out, const EventIdMap &eventsIdMapping) {
if (node == nullptr) {
out << "eNULL[label=\"{ptr=nullptr}\",color=red];\n";
return;
}
bool isUserEvent = node->isUserEvent();
uint32_t statusId = static_cast<uint32_t>(node->peekExecutionStatus());
// clamp to aborted
statusId = (statusId > CL_QUEUED) ? (CL_QUEUED + 1) : statusId;
const char *color = ((statusId == CL_COMPLETE) || (statusId > CL_QUEUED)) ? "green" : (((statusId == CL_SUBMITTED) && (isUserEvent == false)) ? "yellow" : "red");
std::string eventType = isUserEvent ? "USER_EVENT" : (node->isCurrentCmdQVirtualEvent() ? "---V_EVENT " : "-----EVENT ");
std::string commandType = "";
if (isUserEvent == false) {
commandType = NEO::cmdTypetoString(node->getCommandType());
}
static const char *status[] = {
"CL_COMPLETE",
"CL_RUNNING",
"CL_SUBMITTED",
"CL_QUEUED",
"ABORTED"};
auto taskCount = node->peekTaskCount();
auto taskLevel = node->taskLevel.load();
out << label(node, eventsIdMapping) << "[label=\"{------" << eventType << " ptr=" << node << "------"
"|"
<< commandType << "|" << status[statusId] << "|"
"task count=";
if (taskCount == CompletionStamp::notReady) {
out << "NOT_READY";
} else {
out << taskCount;
}
out << ", level=";
if (taskLevel == CompletionStamp::notReady) {
out << "NOT_READY";
} else {
out << taskLevel;
}
out << "|CALLBACKS=" << (node->peekHasCallbacks() ? "TRUE" : "FALSE") << "}\",color=" << color << "];\n";
if (node->isCurrentCmdQVirtualEvent()) {
out << label(node->getCommandQueue()) << "->" << label(node, eventsIdMapping);
out << "[label=\"VIRTUAL_EVENT\"]";
out << ";\n";
}
}
void EventsTracker::dumpEdge(Event *leftNode, Event *rightNode, std::ostream &out, const EventIdMap &eventsIdMapping) {
out << label(leftNode, eventsIdMapping) << "->" << label(rightNode, eventsIdMapping) << ";\n";
}
// walk in DFS manner
void EventsTracker::dumpGraph(Event *node, std::ostream &out, CmdqSet &dumpedCmdQs, std::set<Event *> &dumpedEvents,
const EventIdMap &eventsIdMapping) {
if ((node == nullptr) || (dumpedEvents.find(node) != dumpedEvents.end())) {
return;
}
dumpedEvents.insert(node);
if (node->getCommandQueue() != nullptr) {
dumpQueue(node->getCommandQueue(), out, dumpedCmdQs);
}
dumpNode(node, out, eventsIdMapping);
auto *childNode = node->peekChildEvents();
while (childNode != nullptr) {
dumpGraph(childNode->ref, out, dumpedCmdQs, dumpedEvents, eventsIdMapping);
dumpEdge(node, childNode->ref, out, eventsIdMapping);
childNode = childNode->next;
}
}
TrackedEvent *EventsTracker::getNodes() {
return trackedEvents.detachNodes();
}
void EventsTracker::dump() {
static std::mutex mutex;
std::lock_guard<std::mutex> lock(mutex);
auto time = std::chrono::system_clock::now();
std::string dumpFileName = "eg_"
"reg" +
std::to_string(reinterpret_cast<uintptr_t>(this)) + "_" + std::to_string(time.time_since_epoch().count()) + ".gv";
auto out = createDumpStream(dumpFileName);
*out << "digraph events_registry_" << this << " {\n";
*out << "node [shape=record]\n";
*out << "//pragma: somePragmaData"
<< "\n";
auto allNodes = getNodes();
EventIdMap deadNodeTags;
auto curr = allNodes;
TrackedEvent *prev = nullptr;
EventIdMap eventsIdMapping;
while (curr != nullptr) {
auto next = curr->next;
bool eraseNode = false;
if (curr->eventId < 0) {
auto prevTag = deadNodeTags.find(curr->ev);
if (prevTag == deadNodeTags.end()) {
deadNodeTags[curr->ev] = -curr->eventId;
}
eraseNode = true;
} else if ((deadNodeTags.find(curr->ev) != deadNodeTags.end()) && (deadNodeTags[curr->ev] > curr->eventId)) {
eraseNode = true;
}
if (eraseNode) {
if (prev != nullptr) {
prev->next = next;
}
if (allNodes == curr) {
allNodes = nullptr;
}
delete curr;
} else {
if (allNodes == nullptr) {
allNodes = curr;
}
prev = curr;
eventsIdMapping[curr->ev] = curr->eventId;
}
curr = next;
}
auto node = allNodes;
CmdqSet dumpedCmdQs;
std::set<Event *> dumpedEvents;
while (node != nullptr) {
if (node->ev->peekNumEventsBlockingThis() != 0) {
node = node->next;
continue;
}
dumpGraph(node->ev, *out, dumpedCmdQs, dumpedEvents, eventsIdMapping);
node = node->next;
}
*out << "\n}\n";
if (allNodes == nullptr) {
return;
}
if (trackedEvents.peekHead() != nullptr) {
trackedEvents.peekHead()->getTail()->insertAllNext(*allNodes);
} else {
auto rest = allNodes->next;
trackedEvents.pushFrontOne(*allNodes);
if (rest != nullptr) {
allNodes->insertAllNext(*rest);
}
}
}
void EventsTracker::notifyCreation(Event *eventToTrack) {
dump();
auto trackedE = new TrackedEvent{eventToTrack, eventId++};
trackedEvents.pushFrontOne(*trackedE);
}
void EventsTracker::notifyDestruction(Event *eventToDestroy) {
auto trackedE = new TrackedEvent{eventToDestroy, -(eventId++)};
trackedEvents.pushFrontOne(*trackedE);
dump();
}
void EventsTracker::notifyTransitionedExecutionStatus() {
dump();
}
std::unique_ptr<std::ostream> EventsTracker::createDumpStream(const std::string &filename) {
return std::make_unique<std::fstream>(filename, std::ios::binary | std::ios::out);
}
} // namespace NEO