mirror of
https://github.com/intel/compute-runtime.git
synced 2026-01-12 17:33:00 +08:00
feature: include API calls parameters in graph visualisation
- add logic for extracting parameters from closures - move dump-related types to specified graph_export file - extract test fixtures to header file for reuse - rename test_graph_exporter.cpp -> test_graph_export.cpp Related-To: NEO-15377 Signed-off-by: Naklicki, Mateusz <mateusz.naklicki@intel.com>
This commit is contained in:
committed by
Compute-Runtime-Automation
parent
7063d159b9
commit
737f81c491
@@ -7,15 +7,11 @@
|
||||
|
||||
#include "level_zero/experimental/source/graph/graph.h"
|
||||
|
||||
#include "shared/source/utilities/io_functions.h"
|
||||
|
||||
#include "level_zero/core/source/cmdlist/cmdlist.h"
|
||||
#include "level_zero/core/source/context/context.h"
|
||||
#include "level_zero/core/source/event/event.h"
|
||||
#include "level_zero/core/source/kernel/kernel_imp.h"
|
||||
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace L0 {
|
||||
@@ -463,256 +459,4 @@ void recordHandleSignalEventFromPreviousCommand(L0::CommandList &srcCmdList, Gra
|
||||
captureTarget.registerSignallingEventFromPreviousCommand(*L0::Event::fromHandle(event));
|
||||
}
|
||||
|
||||
ze_result_t GraphDotExporter::exportToFile(const Graph &graph, const char *filePath) const {
|
||||
if (nullptr == filePath) {
|
||||
return ZE_RESULT_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
FILE *file = NEO::IoFunctions::fopenPtr(filePath, "w");
|
||||
if (nullptr == file) {
|
||||
return ZE_RESULT_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
std::string dotContent = exportToString(graph);
|
||||
size_t bytesWritten = NEO::IoFunctions::fwritePtr(dotContent.c_str(), 1, dotContent.size(), file);
|
||||
NEO::IoFunctions::fclosePtr(file);
|
||||
|
||||
if (bytesWritten != dotContent.size()) {
|
||||
return ZE_RESULT_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return ZE_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
std::string GraphDotExporter::exportToString(const Graph &graph) const {
|
||||
std::ostringstream dot;
|
||||
|
||||
writeHeader(dot);
|
||||
writeNodes(dot, graph, 0, 0);
|
||||
writeEdges(dot, graph, 0, 0);
|
||||
writeSubgraphs(dot, graph, 0);
|
||||
|
||||
dot << "}\n";
|
||||
return dot.str();
|
||||
}
|
||||
|
||||
void GraphDotExporter::writeHeader(std::ostringstream &dot) const {
|
||||
dot << "digraph \"graph\" {\n";
|
||||
dot << " rankdir=TB;\n";
|
||||
dot << " nodesep=1;\n";
|
||||
dot << " ranksep=1;\n";
|
||||
dot << " node [shape=box, style=filled];\n";
|
||||
dot << " edge [color=black];\n\n";
|
||||
}
|
||||
|
||||
void GraphDotExporter::writeNodes(std::ostringstream &dot, const Graph &graph, uint32_t level, uint32_t subgraphId) const {
|
||||
const std::string indent(static_cast<size_t>(level + 1) * 2, ' ');
|
||||
dot << indent << "// Command nodes:\n";
|
||||
|
||||
const auto &commands = graph.getCapturedCommands();
|
||||
for (CapturedCommandId cmdId = 0; cmdId < static_cast<uint32_t>(commands.size()); ++cmdId) {
|
||||
const std::string nodeId = generateNodeId(level, subgraphId, cmdId);
|
||||
const std::string label = getCommandNodeLabel(graph, cmdId);
|
||||
const std::string attributes = getCommandNodeAttributes(graph, cmdId);
|
||||
|
||||
dot << indent << nodeId << " [label=\"" << label << "\"" << attributes << "];\n";
|
||||
}
|
||||
dot << "\n";
|
||||
}
|
||||
|
||||
void GraphDotExporter::writeEdges(std::ostringstream &dot, const Graph &graph, uint32_t level, uint32_t subgraphId) const {
|
||||
writeSequentialEdges(dot, graph, level, subgraphId);
|
||||
writeForkJoinEdges(dot, graph, level, subgraphId);
|
||||
writeUnjoinedForkEdges(dot, graph, level, subgraphId);
|
||||
|
||||
dot << "\n";
|
||||
}
|
||||
|
||||
void GraphDotExporter::writeSequentialEdges(std::ostringstream &dot, const Graph &graph, uint32_t level, uint32_t subgraphId) const {
|
||||
const std::string indent(static_cast<size_t>(level + 1) * 2, ' ');
|
||||
|
||||
const auto &commands = graph.getCapturedCommands();
|
||||
dot << indent << "// Sequential edges:\n";
|
||||
|
||||
for (CapturedCommandId cmdId = 1; cmdId < static_cast<uint32_t>(commands.size()); ++cmdId) {
|
||||
const std::string fromNode = generateNodeId(level, subgraphId, cmdId - 1);
|
||||
const std::string toNode = generateNodeId(level, subgraphId, cmdId);
|
||||
dot << indent << fromNode << " -> " << toNode << ";\n";
|
||||
}
|
||||
}
|
||||
|
||||
void GraphDotExporter::writeForkJoinEdges(std::ostringstream &dot, const Graph &graph, uint32_t level, uint32_t subgraphId) const {
|
||||
const std::string indent(static_cast<size_t>(level + 1) * 2, ' ');
|
||||
|
||||
const auto &joinedForks = graph.getJoinedForks();
|
||||
const auto &subGraphs = graph.getSubgraphs();
|
||||
|
||||
dot << "\n"
|
||||
<< indent << "// Fork/Join edges:\n";
|
||||
|
||||
for (const auto &[forkCmdId, forkJoinInfo] : joinedForks) {
|
||||
const auto subgraphIndex = findSubgraphIndex(subGraphs, forkJoinInfo.forkDestiny);
|
||||
if (subgraphIndex && !forkJoinInfo.forkDestiny->getCapturedCommands().empty()) {
|
||||
const auto &subgraphCommands = forkJoinInfo.forkDestiny->getCapturedCommands();
|
||||
const std::string forkNode = generateNodeId(level, subgraphId, forkJoinInfo.forkCommandId);
|
||||
const std::string subgraphFirstNode = generateNodeId(level + 1, *subgraphIndex, 0);
|
||||
const std::string subgraphLastNode = generateNodeId(level + 1, *subgraphIndex, static_cast<uint32_t>(subgraphCommands.size()) - 1);
|
||||
const std::string joinNode = generateNodeId(level, subgraphId, forkJoinInfo.joinCommandId);
|
||||
|
||||
dot << indent << forkNode << " -> " << subgraphFirstNode << ";\n";
|
||||
dot << indent << subgraphLastNode << " -> " << joinNode << ";\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GraphDotExporter::writeUnjoinedForkEdges(std::ostringstream &dot, const Graph &graph, uint32_t level, uint32_t subgraphId) const {
|
||||
const std::string indent(static_cast<size_t>(level + 1) * 2, ' ');
|
||||
|
||||
const auto &unjoinedForks = graph.getUnjoinedForks();
|
||||
const auto &subGraphs = graph.getSubgraphs();
|
||||
|
||||
dot << "\n"
|
||||
<< indent << "// Unjoined forks:\n";
|
||||
|
||||
for (const auto &[cmdList, forkInfo] : unjoinedForks) {
|
||||
const auto subgraphIndex = findSubgraphIndexByCommandList(subGraphs, cmdList);
|
||||
if (subgraphIndex && !subGraphs[*subgraphIndex]->getCapturedCommands().empty()) {
|
||||
const std::string forkNode = generateNodeId(level, subgraphId, forkInfo.forkCommandId);
|
||||
const std::string subgraphFirstNode = generateNodeId(level + 1, *subgraphIndex, 0);
|
||||
dot << indent << forkNode << " -> " << subgraphFirstNode << " [color=red, label=\"unjoined fork\"];\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<uint32_t> GraphDotExporter::findSubgraphIndex(const StackVec<Graph *, 16> &subGraphs, const Graph *targetGraph) const {
|
||||
for (uint32_t i = 0; i < static_cast<uint32_t>(subGraphs.size()); ++i) {
|
||||
if (subGraphs[i] == targetGraph) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<uint32_t> GraphDotExporter::findSubgraphIndexByCommandList(const StackVec<Graph *, 16> &subGraphs, const L0::CommandList *cmdList) const {
|
||||
for (uint32_t i = 0; i < static_cast<uint32_t>(subGraphs.size()); ++i) {
|
||||
if (subGraphs[i]->getExecutionTarget() == cmdList) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void GraphDotExporter::writeSubgraphs(std::ostringstream &dot, const Graph &graph, uint32_t level) const {
|
||||
const auto &subGraphs = graph.getSubgraphs();
|
||||
if (subGraphs.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string indent(static_cast<size_t>(level + 1) * 2, ' ');
|
||||
dot << indent << "// Subgraphs:\n";
|
||||
|
||||
for (uint32_t subgraphId = 0; subgraphId < static_cast<uint32_t>(subGraphs.size()); ++subgraphId) {
|
||||
const std::string clusterName = "cluster_" + generateSubgraphId(level + 1, subgraphId);
|
||||
|
||||
dot << indent << "subgraph " << clusterName << " {\n";
|
||||
dot << indent << " label=\"Subgraph " << (level + 1) << "-" << subgraphId << "\";\n";
|
||||
dot << indent << " style=filled;\n";
|
||||
dot << indent << " fillcolor=" << getSubgraphFillColor(level + 1) << ";\n\n";
|
||||
|
||||
writeNodes(dot, *subGraphs[subgraphId], level + 1, subgraphId);
|
||||
writeEdges(dot, *subGraphs[subgraphId], level + 1, subgraphId);
|
||||
writeSubgraphs(dot, *subGraphs[subgraphId], level + 1);
|
||||
|
||||
dot << indent << " }\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
std::string GraphDotExporter::getCommandNodeLabel(const Graph &graph, CapturedCommandId cmdId) const {
|
||||
const auto &commands = graph.getCapturedCommands();
|
||||
const auto &cmd = commands[cmdId];
|
||||
|
||||
std::string baseLabel;
|
||||
switch (static_cast<CaptureApi>(cmd.index())) {
|
||||
#define RR_CAPTURED_API(X) \
|
||||
case CaptureApi::X: \
|
||||
baseLabel = #X; \
|
||||
break;
|
||||
|
||||
RR_CAPTURED_APIS()
|
||||
#undef RR_CAPTURED_API
|
||||
|
||||
default:
|
||||
baseLabel = "Unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
return baseLabel;
|
||||
}
|
||||
|
||||
std::string GraphDotExporter::getCommandNodeAttributes(const Graph &graph, CapturedCommandId cmdId) const {
|
||||
const auto &commands = graph.getCapturedCommands();
|
||||
const auto &cmd = commands[cmdId];
|
||||
|
||||
switch (static_cast<CaptureApi>(cmd.index())) {
|
||||
case CaptureApi::zeCommandListAppendMemoryCopy:
|
||||
case CaptureApi::zeCommandListAppendMemoryCopyRegion:
|
||||
case CaptureApi::zeCommandListAppendMemoryCopyFromContext:
|
||||
case CaptureApi::zeCommandListAppendMemoryFill:
|
||||
return ", fillcolor=lightblue";
|
||||
|
||||
case CaptureApi::zeCommandListAppendBarrier:
|
||||
case CaptureApi::zeCommandListAppendMemoryRangesBarrier:
|
||||
return ", fillcolor=orange";
|
||||
|
||||
case CaptureApi::zeCommandListAppendSignalEvent:
|
||||
case CaptureApi::zeCommandListAppendWaitOnEvents:
|
||||
case CaptureApi::zeCommandListAppendEventReset:
|
||||
return ", fillcolor=yellow";
|
||||
|
||||
case CaptureApi::zeCommandListAppendImageCopy:
|
||||
case CaptureApi::zeCommandListAppendImageCopyRegion:
|
||||
case CaptureApi::zeCommandListAppendImageCopyToMemory:
|
||||
case CaptureApi::zeCommandListAppendImageCopyFromMemory:
|
||||
case CaptureApi::zeCommandListAppendImageCopyToMemoryExt:
|
||||
case CaptureApi::zeCommandListAppendImageCopyFromMemoryExt:
|
||||
return ", fillcolor=lightgreen";
|
||||
|
||||
case CaptureApi::zeCommandListAppendWriteGlobalTimestamp:
|
||||
case CaptureApi::zeCommandListAppendQueryKernelTimestamps:
|
||||
return ", fillcolor=pink";
|
||||
|
||||
default:
|
||||
return ", fillcolor=aliceblue";
|
||||
}
|
||||
}
|
||||
|
||||
std::string GraphDotExporter::generateNodeId(uint32_t level, uint32_t subgraphId, CapturedCommandId cmdId) const {
|
||||
std::ostringstream oss;
|
||||
oss << "L" << level << "_S" << subgraphId << "_C" << cmdId;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string GraphDotExporter::generateSubgraphId(uint32_t level, uint32_t subgraphId) const {
|
||||
std::ostringstream oss;
|
||||
oss << "L" << level << "_S" << subgraphId;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string GraphDotExporter::getSubgraphFillColor(uint32_t level) const {
|
||||
const std::vector<std::string> colors = {
|
||||
"grey90", // Level 1
|
||||
"grey80", // Level 2
|
||||
"grey70", // Level 3
|
||||
"grey60", // Level 4
|
||||
"grey50" // Level 5+
|
||||
};
|
||||
|
||||
size_t colorIndex = static_cast<size_t>(level) - 1;
|
||||
if (colorIndex >= colors.size()) {
|
||||
colorIndex = colors.size() - 1;
|
||||
}
|
||||
|
||||
return colors[colorIndex];
|
||||
}
|
||||
|
||||
} // namespace L0
|
||||
Reference in New Issue
Block a user