SWDEV-415772, SWDEV-414682 - Fix childgraph node execution

Change-Id: If9ffc08d98a57b8daa5f131f72ef1bf2317f29e1


[ROCm/clr commit: f76a40c26d]
This commit is contained in:
Anusha GodavarthySurya
2023-08-08 13:25:46 +00:00
committed by Maneesh Gupta
parent 779e5c3a22
commit b25939b4de
3 changed files with 72 additions and 75 deletions
+2 -4
View File
@@ -1227,15 +1227,13 @@ hipError_t ihipGraphInstantiate(hip::GraphExec** pGraphExec, hip::Graph* graph,
} }
std::vector<std::vector<hip::GraphNode*>> parallelLists; std::vector<std::vector<hip::GraphNode*>> parallelLists;
std::unordered_map<hip::GraphNode*, std::vector<hip::GraphNode*>> nodeWaitLists; std::unordered_map<hip::GraphNode*, std::vector<hip::GraphNode*>> nodeWaitLists;
std::unordered_set<hip::UserObject*> graphExeUserObj;
clonedGraph->GetRunList(parallelLists, nodeWaitLists); clonedGraph->GetRunList(parallelLists, nodeWaitLists);
std::vector<hip::GraphNode*> graphNodes; std::vector<hip::GraphNode*> graphNodes;
if (false == clonedGraph->TopologicalOrder(graphNodes)) { if (false == clonedGraph->TopologicalOrder(graphNodes)) {
return hipErrorInvalidValue; return hipErrorInvalidValue;
} }
clonedGraph->GetUserObjs(graphExeUserObj); *pGraphExec =
*pGraphExec = new hip::GraphExec(graphNodes, parallelLists, nodeWaitLists, clonedNodes, new hip::GraphExec(graphNodes, parallelLists, nodeWaitLists, clonedGraph, clonedNodes, flags);
graphExeUserObj, flags);
if (*pGraphExec != nullptr) { if (*pGraphExec != nullptr) {
graph->SetGraphInstantiated(true); graph->SetGraphInstantiated(true);
return (*pGraphExec)->Init(); return (*pGraphExec)->Init();
+41 -39
View File
@@ -495,8 +495,8 @@ hipError_t GraphExec::Init() {
hipError_t FillCommands(std::vector<std::vector<Node>>& parallelLists, hipError_t FillCommands(std::vector<std::vector<Node>>& parallelLists,
std::unordered_map<Node, std::vector<Node>>& nodeWaitLists, std::unordered_map<Node, std::vector<Node>>& nodeWaitLists,
std::vector<Node>& topoOrder, std::vector<amd::Command*>& rootCommands, std::vector<Node>& topoOrder, Graph* clonedGraph,
amd::Command*& endCommand, hip::Stream* stream) { amd::Command*& graphStart, amd::Command*& graphEnd, hip::Stream* stream) {
hipError_t status; hipError_t status;
for (auto& node : topoOrder) { for (auto& node : topoOrder) {
// TODO: clone commands from next launch // TODO: clone commands from next launch
@@ -510,44 +510,48 @@ hipError_t FillCommands(std::vector<std::vector<Node>>& parallelLists,
} }
node->UpdateEventWaitLists(waitList); node->UpdateEventWaitLists(waitList);
} }
// rootCommand ensures graph is started (all parallel branches) after all the previous work is std::vector<Node> rootNodes = clonedGraph->GetRootNodes();
// finished ClPrint(amd::LOG_INFO, amd::LOG_CODE,
bool first = true; "[hipGraph] RootCommand get launched on stream (stream:%p)\n", stream);
for (auto& singleList : parallelLists) { for (auto& root : rootNodes) {
if (first) { //If rootnode is launched on to the same stream dont add dependency
first = false; if (root->GetQueue() != stream) {
continue; if (graphStart == nullptr) {
} graphStart = new amd::Marker(*stream, false, {});
// marker from the same queue as the list if (graphStart == nullptr) {
amd::Command* rootCommand = new amd::Marker(*singleList[0]->GetQueue(), false, {}); return hipErrorOutOfMemory;
amd::Command::EventWaitList waitList; }
waitList.push_back(rootCommand); }
if (!singleList.empty()) { amd::Command::EventWaitList waitList;
auto commands = singleList[0]->GetCommands(); waitList.push_back(graphStart);
auto commands = root->GetCommands();
if (!commands.empty()) { if (!commands.empty()) {
commands[0]->updateEventWaitList(waitList); commands[0]->updateEventWaitList(waitList);
rootCommands.push_back(rootCommand);
} }
} }
} }
// endCommand ensures next enqueued ones start after graph is finished (all parallel branches)
// graphEnd ensures next enqueued ones start after graph is finished (all parallel branches)
amd::Command::EventWaitList graphLastCmdWaitList; amd::Command::EventWaitList graphLastCmdWaitList;
first = true; std::vector<Node> leafNodes = clonedGraph->GetLeafNodes();
for (auto& singleList : parallelLists) {
if (first) { for (auto& leaf : leafNodes) {
first = false; // If leaf node is launched on to the same stream dont add dependency
continue; if (leaf->GetQueue() != stream) {
} amd::Command::EventWaitList waitList;
if (!singleList.empty()) { waitList.push_back(graphEnd);
auto commands = singleList.back()->GetCommands(); auto commands = leaf->GetCommands();
if (!commands.empty()) { if (!commands.empty()) {
graphLastCmdWaitList.push_back(commands.back()); graphLastCmdWaitList.push_back(commands.back());
} }
} }
} }
if (!graphLastCmdWaitList.empty()) { if (!graphLastCmdWaitList.empty()) {
endCommand = new amd::Marker(*stream, false, graphLastCmdWaitList); graphEnd = new amd::Marker(*stream, false, graphLastCmdWaitList);
if (endCommand == nullptr) { ClPrint(amd::LOG_INFO, amd::LOG_CODE,
"[hipGraph] EndCommand will get launched on stream (stream:%p)\n", stream);
if (graphEnd == nullptr) {
graphStart->release();
return hipErrorOutOfMemory; return hipErrorOutOfMemory;
} }
} }
@@ -592,25 +596,24 @@ hipError_t GraphExec::Run(hipStream_t stream) {
for (auto& node : topoOrder_) { for (auto& node : topoOrder_) {
if (node->GetType() == hipGraphNodeTypeMemAlloc && if (node->GetType() == hipGraphNodeTypeMemAlloc &&
static_cast<GraphMemAllocNode*>(node)->IsActiveMem() == true) { static_cast<GraphMemAllocNode*>(node)->IsActiveMem() == true) {
return hipErrorInvalidValue; return hipErrorInvalidValue;
} }
} }
} } else {
else {
repeatLaunch_ = true; repeatLaunch_ = true;
} }
UpdateStream(parallelLists_, hip_stream, this); UpdateStream(parallelLists_, hip_stream, this);
std::vector<amd::Command*> rootCommands; amd::Command* rootCommand = nullptr;
amd::Command* endCommand = nullptr; amd::Command* endCommand = nullptr;
status = status = FillCommands(parallelLists_, nodeWaitLists_, topoOrder_, clonedGraph_, rootCommand,
FillCommands(parallelLists_, nodeWaitLists_, topoOrder_, rootCommands, endCommand, hip_stream); endCommand, hip_stream);
if (status != hipSuccess) { if (status != hipSuccess) {
return status; return status;
} }
for (auto& cmd : rootCommands) { if (rootCommand != nullptr) {
cmd->enqueue(); rootCommand->enqueue();
cmd->release(); rootCommand->release();
} }
for (int i = 0; i < topoOrder_.size(); i++) { for (int i = 0; i < topoOrder_.size(); i++) {
if (DEBUG_CLR_GRAPH_ENABLE_BUFFERING) { if (DEBUG_CLR_GRAPH_ENABLE_BUFFERING) {
@@ -618,8 +621,7 @@ hipError_t GraphExec::Run(hipStream_t stream) {
if (parallelLists_.size() == 1) { if (parallelLists_.size() == 1) {
// Peep through the next node. If current and next node are kernel then enable AQL // Peep through the next node. If current and next node are kernel then enable AQL
// buffering // buffering
if (((i + 1) != topoOrder_.size()) && if (((i + 1) != topoOrder_.size()) && topoOrder_[i]->GetType() == hipGraphNodeTypeKernel &&
topoOrder_[i]->GetType() == hipGraphNodeTypeKernel &&
topoOrder_[i + 1]->GetType() == hipGraphNodeTypeKernel) { topoOrder_[i + 1]->GetType() == hipGraphNodeTypeKernel) {
topoOrder_[i]->EnableBuffering(); topoOrder_[i]->EnableBuffering();
} }
+29 -32
View File
@@ -34,6 +34,7 @@
#include "hip_platform.hpp" #include "hip_platform.hpp"
#include "hip_mempool_impl.hpp" #include "hip_mempool_impl.hpp"
#include "hip_vm.hpp" #include "hip_vm.hpp"
namespace hip { namespace hip {
struct Graph; struct Graph;
struct GraphNode; struct GraphNode;
@@ -42,8 +43,8 @@ struct UserObject;
typedef GraphNode* Node; typedef GraphNode* Node;
hipError_t FillCommands(std::vector<std::vector<Node>>& parallelLists, hipError_t FillCommands(std::vector<std::vector<Node>>& parallelLists,
std::unordered_map<Node, std::vector<Node>>& nodeWaitLists, std::unordered_map<Node, std::vector<Node>>& nodeWaitLists,
std::vector<Node>& topoOrder, std::vector<amd::Command*>& rootCommands, std::vector<Node>& topoOrder, Graph* clonedGraph, amd::Command*& graphStart,
amd::Command*& endCommand, hip::Stream* stream); amd::Command*& graphEnd, hip::Stream* stream);
void UpdateStream(std::vector<std::vector<Node>>& parallelLists, hip::Stream* stream, void UpdateStream(std::vector<std::vector<Node>>& parallelLists, hip::Stream* stream,
GraphExec* ptr); GraphExec* ptr);
@@ -552,27 +553,26 @@ struct GraphExec {
// Topological order of the graph doesn't include nodes embedded as part of the child graph // Topological order of the graph doesn't include nodes embedded as part of the child graph
std::vector<Node> topoOrder_; std::vector<Node> topoOrder_;
std::unordered_map<Node, std::vector<Node>> nodeWaitLists_; std::unordered_map<Node, std::vector<Node>> nodeWaitLists_;
struct Graph* clonedGraph_;
std::vector<hip::Stream*> parallel_streams_; std::vector<hip::Stream*> parallel_streams_;
uint currentQueueIndex_; uint currentQueueIndex_;
std::unordered_map<Node, Node> clonedNodes_; std::unordered_map<Node, Node> clonedNodes_;
amd::Command* lastEnqueuedCommand_; amd::Command* lastEnqueuedCommand_;
static std::unordered_set<GraphExec*> graphExecSet_; static std::unordered_set<GraphExec*> graphExecSet_;
std::unordered_set<UserObject*> graphExeUserObj_;
static amd::Monitor graphExecSetLock_; static amd::Monitor graphExecSetLock_;
uint64_t flags_ = 0; uint64_t flags_ = 0;
bool repeatLaunch_ = false; bool repeatLaunch_ = false;
public: public:
GraphExec(std::vector<Node>& topoOrder, std::vector<std::vector<Node>>& lists, GraphExec(std::vector<Node>& topoOrder, std::vector<std::vector<Node>>& lists,
std::unordered_map<Node, std::vector<Node>>& nodeWaitLists, std::unordered_map<Node, std::vector<Node>>& nodeWaitLists, struct Graph*& clonedGraph,
std::unordered_map<Node, Node>& clonedNodes, std::unordered_map<Node, Node>& clonedNodes, uint64_t flags = 0)
std::unordered_set<UserObject*>& userObjs,
uint64_t flags = 0)
: parallelLists_(lists), : parallelLists_(lists),
topoOrder_(topoOrder), topoOrder_(topoOrder),
nodeWaitLists_(nodeWaitLists), nodeWaitLists_(nodeWaitLists),
clonedGraph_(clonedGraph),
clonedNodes_(clonedNodes), clonedNodes_(clonedNodes),
lastEnqueuedCommand_(nullptr), lastEnqueuedCommand_(nullptr),
graphExeUserObj_(userObjs),
currentQueueIndex_(0), currentQueueIndex_(0),
flags_(flags) { flags_(flags) {
amd::ScopedLock lock(graphExecSetLock_); amd::ScopedLock lock(graphExecSetLock_);
@@ -587,12 +587,9 @@ struct GraphExec {
hip::Stream::Destroy(stream); hip::Stream::Destroy(stream);
} }
} }
for (auto it = clonedNodes_.begin(); it != clonedNodes_.end(); it++) delete it->second;
amd::ScopedLock lock(graphExecSetLock_); amd::ScopedLock lock(graphExecSetLock_);
for (auto userobj : graphExeUserObj_) {
userobj->release();
}
graphExecSet_.erase(this); graphExecSet_.erase(this);
delete clonedGraph_;
} }
Node GetClonedNode(Node node) { Node GetClonedNode(Node node) {
@@ -623,11 +620,14 @@ struct ChildGraphNode : public GraphNode {
std::vector<std::vector<Node>> parallelLists_; std::vector<std::vector<Node>> parallelLists_;
std::unordered_map<Node, std::vector<Node>> nodeWaitLists_; std::unordered_map<Node, std::vector<Node>> nodeWaitLists_;
amd::Command* lastEnqueuedCommand_; amd::Command* lastEnqueuedCommand_;
amd::Command* startCommand_;
amd::Command* endCommand_;
public: public:
ChildGraphNode(Graph* g) : GraphNode(hipGraphNodeTypeGraph, "solid", "rectangle") { ChildGraphNode(Graph* g) : GraphNode(hipGraphNodeTypeGraph, "solid", "rectangle") {
childGraph_ = g->clone(); childGraph_ = g->clone();
lastEnqueuedCommand_ = nullptr; lastEnqueuedCommand_ = nullptr;
startCommand_ = nullptr;
endCommand_ = nullptr;
} }
~ChildGraphNode() { delete childGraph_; } ~ChildGraphNode() { delete childGraph_; }
@@ -672,44 +672,41 @@ struct ChildGraphNode : public GraphNode {
if (status != hipSuccess) { if (status != hipSuccess) {
return status; return status;
} }
commands_.reserve(2); startCommand_ = nullptr;
std::vector<amd::Command*> rootCommands; endCommand_ = nullptr;
amd::Command* endCommand = nullptr; status = FillCommands(parallelLists_, nodeWaitLists_, childGraphNodeOrder_, childGraph_,
status = FillCommands(parallelLists_, nodeWaitLists_, childGraphNodeOrder_, rootCommands, startCommand_, endCommand_, stream);
endCommand, stream);
for (auto& cmd : rootCommands) {
commands_.push_back(cmd);
}
if (endCommand != nullptr) {
commands_.push_back(endCommand);
}
return status; return status;
} }
// //
void UpdateEventWaitLists(amd::Command::EventWaitList waitList) { void UpdateEventWaitLists(amd::Command::EventWaitList waitList) {
parallelLists_[0].front()->UpdateEventWaitLists(waitList); if (startCommand_ != nullptr) {
startCommand_->updateEventWaitList(waitList);
}
} }
void GetRunList(std::vector<std::vector<Node>>& parallelList, void GetRunList(std::vector<std::vector<Node>>& parallelList,
std::unordered_map<Node, std::vector<Node>>& dependencies) { std::unordered_map<Node, std::vector<Node>>& dependencies) {
childGraph_->GetRunList(parallelLists_, nodeWaitLists_); childGraph_->GetRunList(parallelLists_, nodeWaitLists_);
} }
bool TopologicalOrder(std::vector<Node>& TopoOrder) { return childGraph_->TopologicalOrder(TopoOrder); } bool TopologicalOrder(std::vector<Node>& TopoOrder) {
return childGraph_->TopologicalOrder(TopoOrder);
}
void EnqueueCommands(hipStream_t stream) { void EnqueueCommands(hipStream_t stream) {
// enqueue child graph start command // enqueue child graph start command
if (commands_.size() == 1) { if (startCommand_ != nullptr) {
commands_[0]->enqueue(); startCommand_->enqueue();
commands_[0]->release(); startCommand_->release();
} }
// enqueue nodes in child graph in level order // enqueue nodes in child graph in level order
for (auto& node : childGraphNodeOrder_) { for (auto& node : childGraphNodeOrder_) {
node->EnqueueCommands(stream); node->EnqueueCommands(stream);
} }
// enqueue child graph end command // enqueue child graph end command
if (commands_.size() == 2) { if (endCommand_ != nullptr) {
commands_[1]->enqueue(); endCommand_->enqueue();
commands_[1]->release(); endCommand_->release();
} }
} }