diff --git a/projects/clr/hipamd/src/hip_graph.cpp b/projects/clr/hipamd/src/hip_graph.cpp index 2a03120975..9eb9864426 100644 --- a/projects/clr/hipamd/src/hip_graph.cpp +++ b/projects/clr/hipamd/src/hip_graph.cpp @@ -2758,8 +2758,13 @@ hipError_t hipUserObjectRelease(hipUserObject_t object, unsigned int count) { HIP_RETURN(hipSuccess); } //! If all the counts are gone not longer need the obj in the list + //! If user object is about to be deleted, It's reference needs to be + //! removed from graph's user object list. if (userObject->referenceCount() == count) { hip::UserObject::removeUSerObj(userObject); + for (auto& g : userObject->owning_graphs_) { + g->RemoveUserObjGraph(userObject); + } } userObject->decreaseRefCount(count); HIP_RETURN(hipSuccess); @@ -2796,11 +2801,10 @@ hipError_t hipGraphRetainUserObject(hipGraph_t graph, hipUserObject_t object, un if (status != hipSuccess) { HIP_RETURN(status); } - } else { - //! if flag is UserObjMove delete userobj from list - hip::UserObject::removeUSerObj(userObject); } g->addUserObjGraph(userObject); + userObject->owning_graphs_.insert(g); + g->IncrementGraphUserObjRefCount(userObject, count); HIP_RETURN(status); } @@ -2814,11 +2818,14 @@ hipError_t hipGraphReleaseUserObject(hipGraph_t graph, hipUserObject_t object, u if (!g->isUserObjGraphValid(userObject) || userObject->referenceCount() < count) { HIP_RETURN(hipSuccess); } + g->DecrementGraphUserObjRefCount(userObject, count); //! Obj is being destroyed unsigned int releaseCount = (userObject->referenceCount() < count) ? userObject->referenceCount() : count; if (userObject->referenceCount() == releaseCount) { g->RemoveUserObjGraph(userObject); + //! If user object is about to be deleted, Its owner needs to be updated. + userObject->owning_graphs_.erase(g); } hipError_t status = hip::hipUserObjectRelease(object, count); HIP_RETURN(status); diff --git a/projects/clr/hipamd/src/hip_graph_internal.cpp b/projects/clr/hipamd/src/hip_graph_internal.cpp index f9465ca5a5..77189c7eea 100644 --- a/projects/clr/hipamd/src/hip_graph_internal.cpp +++ b/projects/clr/hipamd/src/hip_graph_internal.cpp @@ -357,9 +357,12 @@ Graph* Graph::clone(std::unordered_map& clonedNodes) const { } clonedNodes[node]->SetDependencies(clonedDependencies); } - for (auto userObj : graphUserObj_) { - userObj->retain(); + for (auto& userObj : graphUserObj_) { + userObj.first->retain(); newGraph->graphUserObj_.insert(userObj); + // Clone graph should have its separate graph owned ref count = 1 + newGraph->graphUserObj_[userObj.first] = 1; + userObj.first->owning_graphs_.insert(newGraph); } // Clone the root nodes to the new graph if (roots_.size() > 0) { diff --git a/projects/clr/hipamd/src/hip_graph_internal.hpp b/projects/clr/hipamd/src/hip_graph_internal.hpp index 39d65de658..0dd918b782 100644 --- a/projects/clr/hipamd/src/hip_graph_internal.hpp +++ b/projects/clr/hipamd/src/hip_graph_internal.hpp @@ -58,7 +58,10 @@ struct UserObject : public amd::ReferenceCountedObject { typedef void (*UserCallbackDestructor)(void* data); static std::unordered_set ObjectSet_; static amd::Monitor UserObjectLock_; - + // Graphs owns this user object. + // In case if User object is about to be deleted (last release()), Pointer refering to it + // should be cleared from Graph's list of user object. + std::unordered_set owning_graphs_; public: UserObject(UserCallbackDestructor callback, void* data, unsigned int flags) : ReferenceCountedObject(), callback_(callback), data_(data), flags_(flags) { @@ -72,6 +75,7 @@ struct UserObject : public amd::ReferenceCountedObject { callback_(data_); } ObjectSet_.erase(this); + owning_graphs_.clear(); } void increaseRefCount(const unsigned int refCount) { @@ -478,7 +482,8 @@ struct Graph { const Graph* pOriginalGraph_ = nullptr; static std::unordered_set graphSet_; static amd::Monitor graphSetLock_; - std::unordered_set graphUserObj_; + //! graphUserObj_; unsigned int id_; static int nextID; int max_streams_ = 0; //!< Maximum number of extra streams used in the graph launch @@ -508,16 +513,38 @@ struct Graph { leafs_.resize(DEBUG_HIP_FORCE_GRAPH_QUEUES); wait_order_.resize(DEBUG_HIP_FORCE_GRAPH_QUEUES); } - + void RemoveUserObjectFromOwingGraphs(UserObject* uObj) { + for (auto& g : uObj->owning_graphs_) { + if (g != this) { + g->RemoveUserObjGraph(uObj); + } + } + } ~Graph() { for (auto node : vertices_) { delete node; } amd::ScopedLock lock(graphSetLock_); graphSet_.erase(this); - for (auto userobj : graphUserObj_) { - userobj->release(); + for (auto& userobj : graphUserObj_) { + // Graph is destorying so remove it from user object's graph list. + userobj.first->owning_graphs_.erase(this); + // Bypass if graph owned refcount is more then actual refcount of user object + if (userobj.second > userobj.first->referenceCount()) { + continue; + } + // User object is about to die and hence remove it. + if (userobj.first->referenceCount() == userobj.second) { + RemoveUserObjectFromOwingGraphs(userobj.first); + } + // Release user object = # of times it is owned by this graph. + for (int i = 0; i < userobj.second; i++) { + if (userobj.first->referenceCount() >= 1) { + userobj.first->release(); + } + } } + graphUserObj_.clear(); if (mem_pool_ != nullptr) { mem_pool_->release(); } @@ -558,7 +585,23 @@ struct Graph { // Add user obj resource to graph void addUserObjGraph(UserObject* pUserObj) { amd::ScopedLock lock(graphSetLock_); - graphUserObj_.insert(pUserObj); + graphUserObj_.insert({pUserObj, 0}); + } + // Increments graphUserObj_.second. + void IncrementGraphUserObjRefCount(UserObject* pUserObj, unsigned int count) { + amd::ScopedLock lock(graphSetLock_); + auto it = graphUserObj_.find(pUserObj); + if (it != graphUserObj_.end()) { + it->second += count; + } + } + // Decrements graphUserObj_.second. + void DecrementGraphUserObjRefCount(UserObject* pUserObj, unsigned int count) { + amd::ScopedLock lock(graphSetLock_); + auto it = graphUserObj_.find(pUserObj); + if (it != graphUserObj_.end()) { + it->second -= count; + } } // Check user obj resource from graph is valid bool isUserObjGraphValid(UserObject* pUserObj) {