From 464b99373b8b2e104f4951781c621b8fb01cde54 Mon Sep 17 00:00:00 2001 From: Ioannis Assiouras Date: Mon, 19 Aug 2024 20:41:11 +0100 Subject: [PATCH] SWDEV-470612 - Added fixes in optimized multistream path for graph execution This change adds fixes in optimized multistream path for childGraph uses cases. 1) For childgraph nodes, rely on runNodes() only to process the childgraph and skip calls to createCommand and enqueueCommands. This ensures that the start/end markers are enqueued correctly with respect to the childGraph commands. In addition, the runNodes() for the childgraph should be called after the dependency walkthrough to make sure that the subgraph is executed once. 2) Nodes with no outgoing edges should be marked as a leafs regardless of which stream they are assigned to. This is to ensure that marker dependencies from nodes that run on non-zero stream to subgraph leafs that run on zero stream are still set up correctly. Change-Id: I4a5f4f3b0e0d01e515cdcb045b46c2798f291255 --- hipamd/src/hip_graph_internal.cpp | 79 ++++++++++++++++++------------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/hipamd/src/hip_graph_internal.cpp b/hipamd/src/hip_graph_internal.cpp index 36abf8f47a..ad1614d772 100644 --- a/hipamd/src/hip_graph_internal.cpp +++ b/hipamd/src/hip_graph_internal.cpp @@ -640,11 +640,6 @@ void Graph::UpdateStreams( // ================================================================================================ bool Graph::RunOneNode(Node node, bool wait) { if (node->launch_id_ == -1) { - // Process child graph separately, since, there is no connection - if (node->GetType() == hipGraphNodeTypeGraph) { - auto child = reinterpret_cast(node)->childGraph_; - child->RunNodes(node->stream_id_, &streams_); - } // Clear the storage of the wait nodes memset(&wait_order_[0], 0, sizeof(Node) * wait_order_.size()); amd::Command::EventWaitList waitList; @@ -668,35 +663,47 @@ bool Graph::RunOneNode(Node node, bool wait) { return true; } } - // Create a wait list from the last launches of all dependencies - for (auto dep : wait_order_) { - if (dep != nullptr) { - // Add all commands in the wait list - for (auto command : dep->GetCommands()) { - waitList.push_back(command); + + if (node->GetType() == hipGraphNodeTypeGraph) { + // Process child graph separately, since, there is no connection + auto child = reinterpret_cast(node)->childGraph_; + if (!reinterpret_cast(node)->graphCaptureStatus_) { + child->RunNodes(node->stream_id_, &streams_); + } + } else { + // Create a wait list from the last launches of all dependencies + for (auto dep : wait_order_) { + if (dep != nullptr) { + // Add all commands in the wait list + if (dep->GetType() != hipGraphNodeTypeGraph) { + for (auto command : dep->GetCommands()) { + waitList.push_back(command); + } + } } } - } - // Assing a stream to the current node - node->SetStream(streams_); - // Create the execution commands on the assigned stream - auto status = node->CreateCommand(node->GetQueue()); - if (status != hipSuccess) { - LogPrintfError("Command creation for node id(%d) failed!", current_id_ + 1); - return false; - } - // Retain all commands, since potentially the command can finish before a wait signal - for (auto command : node->GetCommands()) { - command->retain(); - } + // Assing a stream to the current node + node->SetStream(streams_); + // Create the execution commands on the assigned stream + auto status = node->CreateCommand(node->GetQueue()); + if (status != hipSuccess) { + LogPrintfError("Command creation for node id(%d) failed!", current_id_ + 1); + return false; + } + // Retain all commands, since potentially the command can finish before a wait signal + for (auto command : node->GetCommands()) { + command->retain(); + } - // If a wait was requested, then process the list - if (wait && !waitList.empty()) { - node->UpdateEventWaitLists(waitList); + // If a wait was requested, then process the list + if (wait && !waitList.empty()) { + node->UpdateEventWaitLists(waitList); + } + // Start the execution + node->EnqueueCommands(node->GetQueue()); } - // Start the execution - node->EnqueueCommands(node->GetQueue()); // Assign the launch ID of the submmitted node + // This is also applied to childGraphs to prevent them from being reprocessed node->launch_id_ = current_id_++; uint32_t i = 0; // Execute the nodes in the edges list @@ -710,7 +717,7 @@ bool Graph::RunOneNode(Node node, bool wait) { } i++; } - if ((i == 0) && (node->stream_id_ != 0)) { + if (i == 0) { // Add a leaf node into the list for a wait. // Always use the last node, since it's the latest for the particular queue leafs_[node->stream_id_] = node; @@ -764,8 +771,10 @@ bool Graph::RunNodes( for (uint32_t i = 0; i < DEBUG_HIP_FORCE_GRAPH_QUEUES; ++i) { if ((base_stream != i) && (leafs_[i] != nullptr)) { // Add all commands in the wait list - for (auto command : leafs_[i]->GetCommands()) { - wait_list.push_back(command); + if (leafs_[i]->GetType() != hipGraphNodeTypeGraph) { + for (auto command : leafs_[i]->GetCommands()) { + wait_list.push_back(command); + } } } } @@ -780,8 +789,10 @@ bool Graph::RunNodes( // Release commands after execution for (auto& node : vertices_) { node->launch_id_ = -1; - for (auto command : node->GetCommands()) { - command->release(); + if (node->GetType() != hipGraphNodeTypeGraph) { + for (auto command : node->GetCommands()) { + command->release(); + } } } return true;