SWDEV-415772, SWDEV-414682 - Fix childgraph node execution
Change-Id: If9ffc08d98a57b8daa5f131f72ef1bf2317f29e1
[ROCm/clr commit: f76a40c26d]
This commit is contained in:
committed by
Maneesh Gupta
parent
779e5c3a22
commit
b25939b4de
@@ -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();
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user