SWDEV-468424 - Add support to capture multiple AQL Packets

=> Added support to capture multiple AQL Packets.
=> Added Interface to callback to hip runtime from rocclr to allocate
kernel args from the graph kernel arg pool.
=> Enabled Support to capture memset node.

Change-Id: I7e1c2ba06927459e024653058af142bd82192c43
Bu işleme şunda yer alıyor:
Anusha GodavarthySurya
2024-08-01 13:30:04 +00:00
işlemeyi yapan: Anusha Godavarthy Surya
ebeveyn e988e5e448
işleme bd3a35bde1
5 değiştirilmiş dosya ile 87 ekleme ve 75 silme
+11 -4
Dosyayı Görüntüle
@@ -1651,7 +1651,15 @@ hipError_t hipGraphExecMemsetNodeSetParams(hipGraphExec_t hGraphExec, hipGraphNo
if (clonedNode == nullptr) {
HIP_RETURN(hipErrorInvalidValue);
}
HIP_RETURN(reinterpret_cast<hip::GraphMemsetNode*>(clonedNode)->SetParams(pNodeParams, true));
hipError_t status = reinterpret_cast<hip::GraphMemsetNode*>(clonedNode)->SetParams(pNodeParams, true);
if(status != hipSuccess) {
HIP_RETURN(status);
}
if (DEBUG_CLR_GRAPH_PACKET_CAPTURE) {
status = reinterpret_cast<hip::GraphExec*>(hGraphExec)
->UpdateAQLPacket(reinterpret_cast<hip::GraphKernelNode*>(clonedNode));
}
HIP_RETURN(status);
}
hipError_t hipGraphAddDependencies(hipGraph_t graph, const hipGraphNode_t* from,
@@ -1773,7 +1781,7 @@ hipError_t hipGraphExecChildGraphNodeSetParams(hipGraphExec_t hGraphExec, hipGra
std::vector<hip::GraphNode*> childGraphNodes;
reinterpret_cast<hip::ChildGraphNode*>(clonedNode)->TopologicalOrder(childGraphNodes);
for (std::vector<hip::GraphNode*>::size_type i = 0; i != childGraphNodes.size(); i++) {
if (childGraphNodes[i]->GetType() == hipGraphNodeTypeKernel) {
if (childGraphNodes[i]->GraphCaptureEnabled()) {
status = reinterpret_cast<hip::GraphExec*>(hGraphExec)
->UpdateAQLPacket(reinterpret_cast<hip::GraphKernelNode*>(childGraphNodes[i]));
if (status != hipSuccess) {
@@ -2478,8 +2486,7 @@ hipError_t hipGraphExecUpdate(hipGraphExec_t hGraphExec, hipGraph_t hGraph,
*updateResult_out = hipGraphExecUpdateErrorNotSupported;
}
HIP_RETURN(hipErrorGraphExecUpdateFailure);
} else if (DEBUG_CLR_GRAPH_PACKET_CAPTURE &&
oldGraphExecNodes[i]->GetType() == hipGraphNodeTypeKernel) {
} else if (DEBUG_CLR_GRAPH_PACKET_CAPTURE && newGraphNodes[i]->GraphCaptureEnabled()) {
status =
reinterpret_cast<hip::GraphExec*>(hGraphExec)
->UpdateAQLPacket(reinterpret_cast<hip::GraphKernelNode*>(oldGraphExecNodes[i]));
+7 -23
Dosyayı Görüntüle
@@ -392,17 +392,7 @@ hipError_t AllocKernelArgForGraphNode(std::vector<hip::Node>& topoOrder,
}
}
if (node->GraphCaptureEnabled()) {
// From the kernel pool allocate the kern arg size required for the current node.
address kernArgOffset = nullptr;
if (node->GetKernargSegmentByteSize()) {
kernArgOffset = graphExec->kernArgManager_->AllocKernArg(
node->GetKernargSegmentByteSize(), node->GetKernargSegmentAlignment());
if (kernArgOffset == nullptr) {
return hipErrorMemoryAllocation;
}
}
// Form GPU packet capture for the kernel node.
node->CaptureAndFormPacket(capture_stream, kernArgOffset);
node->CaptureAndFormPacket(capture_stream, graphExec->GetKernelArgManager());
} else if (node->GetType() == hipGraphNodeTypeGraph) {
auto childNode = reinterpret_cast<hip::ChildGraphNode*>(node);
auto& childParallelLists = childNode->GetParallelLists();
@@ -443,17 +433,10 @@ hipError_t GraphExec::CaptureAQLPackets() {
}
// ================================================================================================
hipError_t GraphExec::UpdateAQLPacket(hip::GraphKernelNode* node) {
hipError_t GraphExec::UpdateAQLPacket(hip::GraphNode* node) {
hipError_t status = hipSuccess;
if (parallelLists_.size() == 1) {
size_t pool_new_usage = 0;
address kernArgOffset = nullptr;
kernArgOffset =
kernArgManager_->AllocKernArg(node->GetKerArgSize(), node->GetKernargSegmentAlignment());
if (kernArgOffset == nullptr) {
return hipErrorMemoryAllocation;
}
node->CaptureAndFormPacket(capture_stream_, kernArgOffset);
node->CaptureAndFormPacket(capture_stream_, kernArgManager_);
}
return hipSuccess;
}
@@ -556,9 +539,10 @@ hipError_t EnqueueGraphWithSingleList(std::vector<hip::Node>& topoOrder, hip::St
for (int i = 0; i < topoOrder.size(); i++) {
if (topoOrder[i]->GraphCaptureEnabled()) {
if (topoOrder[i]->GetEnabled()) {
hip_stream->vdev()->dispatchAqlPacket(topoOrder[i]->GetAqlPacket(),
topoOrder[i]->GetKernelName(),
accumulate);
std::vector<uint8_t*>& gpuPackets = topoOrder[i]->GetAqlPackets();
for (auto& packet : gpuPackets) {
hip_stream->vdev()->dispatchAqlPacket(packet, topoOrder[i]->GetKernelName(), accumulate);
}
}
} else {
topoOrder[i]->SetStream(hip_stream, graphExec);
+46 -39
Dosyayı Görüntüle
@@ -166,6 +166,41 @@ struct hipGraphNodeDOTAttribute {
}
};
class GraphKernelArgManager : public amd::ReferenceCountedObject, public amd::GraphKernelArgManager {
public:
GraphKernelArgManager() : amd::ReferenceCountedObject() {}
~GraphKernelArgManager() {
//! Release the kernel arg pools
auto device = g_devices[ihipGetDevice()]->devices()[0];
for (auto& element : kernarg_graph_) {
device->hostFree(element.kernarg_pool_addr_, element.kernarg_pool_size_);
}
kernarg_graph_.clear();
}
// Allocate kernel arg pool for the given size.
bool AllocGraphKernargPool(size_t pool_size);
// Allocate kernel args from current chunck for given size and alignment.
// If kernel arg pool is full allocate new chunck and alloc kern args from new pool.
address AllocKernArg(size_t size, size_t alignment) override;
// Do HDP flush/When HDP flush register is invalid fallback to Readback
void ReadBackOrFlush();
private:
struct KernelArgPoolGraph {
KernelArgPoolGraph(address base_addr, size_t size)
: kernarg_pool_addr_(base_addr), kernarg_pool_size_(size), kernarg_pool_offset_(0) {}
address kernarg_pool_addr_; //! Base address of the kernel arg pool
size_t kernarg_pool_size_; //! Size of the pool
size_t kernarg_pool_offset_; //! Current offset in the kernel arg alloc
};
bool device_kernarg_pool_ = false; //! Indicate if kernel pool in device mem
std::vector<KernelArgPoolGraph> kernarg_graph_; //! Vector of allocated kernarg pool
using KernelArgImpl = device::Settings::KernelArgImpl;
};
struct GraphNode : public hipGraphNodeDOTAttribute {
protected:
hip::Stream* stream_ = nullptr;
@@ -184,7 +219,7 @@ struct GraphNode : public hipGraphNodeDOTAttribute {
static std::unordered_set<GraphNode*> nodeSet_;
static amd::Monitor nodeSetLock_;
unsigned int isEnabled_;
uint8_t gpuPacket_[64]; //!< GPU Packet to enqueue during graph launch
std::vector<uint8_t *> gpuPackets_; //!< GPU Packet to enqueue during graph launch
std::string capturedKernelName_;
size_t alignedKernArgSize_ = 256; //!< Aligned size required for kernel args
size_t kernargSegmentByteSize_ = 256; //!< Kernel arg segment byte size
@@ -224,6 +259,9 @@ struct GraphNode : public hipGraphNodeDOTAttribute {
for (auto node : dependencies_) {
node->RemoveEdge(this);
}
for (auto packet : gpuPackets_) {
delete packet;
}
amd::ScopedLock lock(nodeSetLock_);
nodeSet_.erase(this);
}
@@ -237,16 +275,16 @@ struct GraphNode : public hipGraphNodeDOTAttribute {
return true;
}
// Return gpu packet address to update with actual packet under capture.
uint8_t* GetAqlPacket() { return gpuPacket_; }
std::vector<uint8_t *>& GetAqlPackets() { return gpuPackets_; }
void SetKernelName(const std::string& kernelName) { capturedKernelName_ = kernelName; }
const std::string& GetKernelName() const { return capturedKernelName_; }
size_t GetKerArgSize() const { return alignedKernArgSize_; }
size_t GetKernargSegmentByteSize() const { return kernargSegmentByteSize_; }
size_t GetKernargSegmentAlignment() const { return kernargSegmentAlignment_; }
void CaptureAndFormPacket(hip::Stream* capture_stream, address kernArgOffset) {
void CaptureAndFormPacket(hip::Stream* capture_stream, GraphKernelArgManager* kernArgMgr) {
hipError_t status = CreateCommand(capture_stream);
for (auto& command : commands_) {
command->setCapturingState(true, GetAqlPacket(), kernArgOffset, &capturedKernelName_);
command->setCapturingState(true, &gpuPackets_, kernArgMgr, &capturedKernelName_);
// Enqueue command to capture GPU Packet. The packet is not submitted to the device.
// The packet is stored in gpuPacket_ and submitted during graph launch.
command->submit(*(command->queue())->vdev());
@@ -404,6 +442,9 @@ struct GraphNode : public hipGraphNodeDOTAttribute {
case hipGraphNodeTypeKernel:
isGraphCapture = true;
break;
case hipGraphNodeTypeMemset:
isGraphCapture = true;
break;
default:
break;
}
@@ -582,40 +623,6 @@ struct Graph {
}
};
struct GraphKernelNode;
struct GraphKernelArgManager : public amd::ReferenceCountedObject {
public:
GraphKernelArgManager() : ReferenceCountedObject() {}
~GraphKernelArgManager() {
//! Release the kernel arg pools
auto device = g_devices[ihipGetDevice()]->devices()[0];
for (auto& element : kernarg_graph_) {
device->hostFree(element.kernarg_pool_addr_, element.kernarg_pool_size_);
}
kernarg_graph_.clear();
}
// Allocate kernel arg pool for the given size.
bool AllocGraphKernargPool(size_t pool_size);
// Allocate kernel args from current chunck for given size and alignment.
// If kernel arg pool is full allocate new chunck and alloc kern args from new pool.
address AllocKernArg(size_t size, size_t alignment);
// Do HDP flush/When HDP flush register is invalid fallback to Readback
void ReadBackOrFlush();
private:
struct KernelArgPoolGraph {
KernelArgPoolGraph(address base_addr, size_t size)
: kernarg_pool_addr_(base_addr), kernarg_pool_size_(size), kernarg_pool_offset_(0) {}
address kernarg_pool_addr_; //! Base address of the kernel arg pool
size_t kernarg_pool_size_; //! Size of the pool
size_t kernarg_pool_offset_; //! Current offset in the kernel arg alloc
};
bool device_kernarg_pool_ = false; //! Indicate if kernel pool in device mem
std::vector<KernelArgPoolGraph> kernarg_graph_; //! Vector of allocated kernarg pool
using KernelArgImpl = device::Settings::KernelArgImpl;
};
struct GraphExec : public amd::ReferenceCountedObject {
std::vector<std::vector<Node>> parallelLists_;
@@ -699,7 +706,7 @@ struct GraphExec : public amd::ReferenceCountedObject {
hipError_t Run(hipStream_t stream);
// Capture GPU Packets from graph commands
hipError_t CaptureAQLPackets();
hipError_t UpdateAQLPacket(hip::GraphKernelNode* node);
hipError_t UpdateAQLPacket(hip::GraphNode* node);
// Kenrel arg manger is for the entire graph.
// Child graph also shares the same kernel arg manager object. some apps have 100's of
// child graph nodes and each child graph has only one node.
+2 -1
Dosyayı Görüntüle
@@ -3242,7 +3242,8 @@ bool VirtualGPU::submitKernelInternal(const amd::NDRangeContainer& sizes,
if (!kernel.parameters().deviceKernelArgs() || gpuKernel.isInternalKernel()) {
// Allocate buffer to hold kernel arguments
if (isGraphCapture) {
argBuffer = currCmd_->getKernArgOffset();
argBuffer = currCmd_->getKernArgOffset(gpuKernel.KernargSegmentByteSize(),
gpuKernel.KernargSegmentAlignment());
currCmd_->SetKernelName(gpuKernel.name());
} else {
+21 -8
Dosyayı Görüntüle
@@ -239,6 +239,12 @@ union CopyMetadata {
copyEnginePreference_(copyEnginePreference) {}
};
// Interface to callback to allocate kernel args from the graph kernel arg pool.
class GraphKernelArgManager {
public:
virtual address AllocKernArg(size_t size, size_t alignment) = 0;
};
/*! \brief An operation that is submitted to a command queue.
*
* %Command is the abstract base type of all OpenCL operations
@@ -257,7 +263,8 @@ class Command : public Event {
const Event* waitingEvent_; //!< Waiting event associated with the marker
bool capturing_ = false; //!< Flag to enable/disable graph gpu packet capture
uint8_t* gpuPacket_ = nullptr; //!< GPU packet to capture, when graph capturing is enabled
std::vector<uint8_t*>* gpuPackets_; //!< GPU packets captured when graph capturing is enabled
GraphKernelArgManager* graphKernArgMgr_ = nullptr; //!< KernelMgr for graph
address kernArgOffset_ = nullptr; //!< KernelArg buffer to used when graph capturing is enabled
std::string* capturedKernelName_ = nullptr; //!< Kenrnel under capture
protected:
@@ -300,11 +307,12 @@ class Command : public Event {
bool getCapturingState() const { return capturing_; }
//! Sets AQL capture state, aql packet to capture and where to copy kernArgs
void setCapturingState(bool state, uint8_t* packet, address kernArgOffset,
void setCapturingState(bool state, std::vector<uint8_t*>* packet,
amd::GraphKernelArgManager* graphKernArgMgr,
std::string* capturedKernelName) {
capturing_ = state;
gpuPacket_ = packet;
kernArgOffset_ = kernArgOffset;
gpuPackets_ = packet;
graphKernArgMgr_ = graphKernArgMgr;
capturedKernelName_ = capturedKernelName;
}
@@ -315,11 +323,16 @@ class Command : public Event {
}
}
//! returns the graph executable object command belongs to.
const uint8_t* getAqlPacket() const { return gpuPacket_; }
//! Returns the graph executable object command belongs to.
const uint8_t* getAqlPacket() const {
uint8_t* packet = new uint8_t[64];
gpuPackets_->push_back(packet);
return packet;
}
//! returns the graph executable object command belongs to.
const address getKernArgOffset() const { return kernArgOffset_; }
address getKernArgOffset(int size, int alignment) {
return graphKernArgMgr_->AllocKernArg(size, alignment);
}
//! Overload new/delete for fast commands allocation/destruction
void* operator new(size_t size);