SWDEV-486602 - Optimize HSA callback performance
- Don't generate callbacks for HIP events
- Don't process profiling info in the callback for HIP events
- Wait for CPU status update of the submitted commands
every 50 calls. That will allow to drain the commands and
destroy HSA signals.
Change-Id: Ib601a350e7e7c2b6c6209a172385389baccf73a9
[ROCm/clr commit: 364dfb0ed1]
This commit is contained in:
@@ -64,6 +64,7 @@ hipError_t Event::query() {
|
||||
return ready() ? hipSuccess : hipErrorNotReady;
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
hipError_t Event::synchronize() {
|
||||
amd::ScopedLock lock(lock_);
|
||||
|
||||
@@ -76,19 +77,12 @@ hipError_t Event::synchronize() {
|
||||
// Check HW status of the ROCcrl event. Note: not all ROCclr modes support HW status
|
||||
static constexpr bool kWaitCompletion = true;
|
||||
if (!hip_device->devices()[0]->IsHwEventReady(*event_, kWaitCompletion, flags_)) {
|
||||
if (event_->HwEvent() != nullptr) {
|
||||
amd::Command* command = nullptr;
|
||||
hipError_t status = recordCommand(command, event_->command().queue(), flags_);
|
||||
command->enqueue();
|
||||
hip_device->devices()[0]->IsHwEventReady(command->event(), kWaitCompletion, flags_);
|
||||
command->release();
|
||||
} else {
|
||||
event_->awaitCompletion();
|
||||
}
|
||||
event_->awaitCompletion();
|
||||
}
|
||||
return hipSuccess;
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
bool Event::awaitEventCompletion() {
|
||||
return event_->awaitCompletion();
|
||||
}
|
||||
@@ -222,8 +216,9 @@ hipError_t Event::streamWait(hipStream_t stream, uint flags) {
|
||||
return hipSuccess;
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
hipError_t Event::recordCommand(amd::Command*& command, amd::HostQueue* stream,
|
||||
uint32_t ext_flags ) {
|
||||
uint32_t ext_flags, bool batch_flush) {
|
||||
if (command == nullptr) {
|
||||
int32_t releaseFlags = ((ext_flags == 0) ? flags_ : ext_flags) &
|
||||
(hipEventReleaseToDevice | hipEventReleaseToSystem |
|
||||
@@ -234,11 +229,12 @@ hipError_t Event::recordCommand(amd::Command*& command, amd::HostQueue* stream,
|
||||
releaseFlags = amd::Device::kCacheStateInvalid;
|
||||
}
|
||||
// Always submit a EventMarker.
|
||||
command = new hip::EventMarker(*stream, !kMarkerDisableFlush, true, releaseFlags);
|
||||
command = new hip::EventMarker(*stream, !kMarkerDisableFlush, true, releaseFlags, batch_flush);
|
||||
}
|
||||
return hipSuccess;
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
hipError_t Event::enqueueRecordCommand(hipStream_t stream, amd::Command* command, bool record) {
|
||||
command->enqueue();
|
||||
if (event_ == &command->event()) return hipSuccess;
|
||||
@@ -251,11 +247,13 @@ hipError_t Event::enqueueRecordCommand(hipStream_t stream, amd::Command* command
|
||||
return hipSuccess;
|
||||
}
|
||||
|
||||
hipError_t Event::addMarker(hipStream_t stream, amd::Command* command, bool record) {
|
||||
// ================================================================================================
|
||||
hipError_t Event::addMarker(hipStream_t stream, amd::Command* command,
|
||||
bool record, bool batch_flush) {
|
||||
hip::Stream* hip_stream = hip::getStream(stream);
|
||||
// Keep the lock always at the beginning of this to avoid a race. SWDEV-277847
|
||||
amd::ScopedLock lock(lock_);
|
||||
hipError_t status = recordCommand(command, hip_stream);
|
||||
hipError_t status = recordCommand(command, hip_stream, 0, batch_flush);
|
||||
if (status != hipSuccess) {
|
||||
return hipSuccess;
|
||||
}
|
||||
@@ -415,7 +413,7 @@ hipError_t hipEventRecord_common(hipEvent_t event, hipStream_t stream) {
|
||||
if (g_devices[e->deviceId()]->devices()[0] != &hip_stream->device()) {
|
||||
return hipErrorInvalidHandle;
|
||||
}
|
||||
status = e->addMarker(stream, nullptr, true);
|
||||
status = e->addMarker(stream, nullptr, true, !hip::Event::kBatchFlush);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -81,10 +81,11 @@ typedef struct ihipIpcEventShmem_s {
|
||||
class EventMarker : public amd::Marker {
|
||||
public:
|
||||
EventMarker(amd::HostQueue& stream, bool disableFlush, bool markerTs = false,
|
||||
int32_t scope = amd::Device::kCacheStateInvalid)
|
||||
int32_t scope = amd::Device::kCacheStateInvalid, bool batch_flush = true)
|
||||
: amd::Marker(stream, disableFlush) {
|
||||
profilingInfo_.enabled_ = true;
|
||||
profilingInfo_.marker_ts_ = markerTs;
|
||||
profilingInfo_.batch_flush_ = batch_flush;
|
||||
profilingInfo_.clear();
|
||||
setEventScope(scope);
|
||||
}
|
||||
@@ -101,6 +102,8 @@ class Event {
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr static bool kBatchFlush = true; //!< Flushes CPU command batch in direct dispatch mode
|
||||
|
||||
Event(uint32_t flags) : flags_(flags), lock_(true) /* hipEvent_t lock*/,
|
||||
event_(nullptr), unrecorded_(false), stream_(nullptr) {
|
||||
// No need to init event_ here as addMarker does that
|
||||
@@ -123,9 +126,10 @@ class Event {
|
||||
virtual hipError_t streamWait(hipStream_t stream, uint flags);
|
||||
|
||||
virtual hipError_t recordCommand(amd::Command*& command, amd::HostQueue* stream,
|
||||
uint32_t flags = 0);
|
||||
uint32_t flags = 0, bool batch_flush = true);
|
||||
virtual hipError_t enqueueRecordCommand(hipStream_t stream, amd::Command* command, bool record);
|
||||
hipError_t addMarker(hipStream_t stream, amd::Command* command, bool record);
|
||||
hipError_t addMarker(hipStream_t stream, amd::Command* command,
|
||||
bool record, bool batch_flush = true);
|
||||
|
||||
void BindCommand(amd::Command& command, bool record) {
|
||||
amd::ScopedLock lock(lock_);
|
||||
@@ -217,7 +221,8 @@ class IPCEvent : public Event {
|
||||
hipError_t enqueueStreamWaitCommand(hipStream_t stream, amd::Command* command);
|
||||
hipError_t streamWait(hipStream_t stream, uint flags);
|
||||
|
||||
hipError_t recordCommand(amd::Command*& command, amd::HostQueue* queue, uint32_t flags = 0);
|
||||
hipError_t recordCommand(amd::Command*& command, amd::HostQueue* queue,
|
||||
uint32_t flags = 0, bool batch_flush = true) override;
|
||||
hipError_t enqueueRecordCommand(hipStream_t stream, amd::Command* command, bool record);
|
||||
};
|
||||
|
||||
|
||||
@@ -139,16 +139,19 @@ hipError_t IPCEvent::streamWait(hipStream_t stream, uint flags) {
|
||||
return hipSuccess;
|
||||
}
|
||||
|
||||
hipError_t IPCEvent::recordCommand(amd::Command*& command, amd::HostQueue* stream, uint32_t flags) {
|
||||
// ================================================================================================
|
||||
hipError_t IPCEvent::recordCommand(amd::Command*& command, amd::HostQueue* stream,
|
||||
uint32_t flags, bool batch_flush) {
|
||||
bool unrecorded = isUnRecorded();
|
||||
if (unrecorded) {
|
||||
command = new amd::Marker(*stream, kMarkerDisableFlush);
|
||||
} else {
|
||||
return Event::recordCommand(command, stream);
|
||||
return Event::recordCommand(command, stream, batch_flush);
|
||||
}
|
||||
return hipSuccess;
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
hipError_t IPCEvent::enqueueRecordCommand(hipStream_t stream, amd::Command* command, bool record) {
|
||||
bool unrecorded = isUnRecorded();
|
||||
if (unrecorded) {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "hip_event.hpp"
|
||||
#include "thread/monitor.hpp"
|
||||
#include "hip_prof_api.h"
|
||||
#include <atomic>
|
||||
|
||||
namespace hip {
|
||||
|
||||
@@ -358,11 +359,15 @@ hipError_t hipStreamSynchronize_common(hipStream_t stream) {
|
||||
}
|
||||
}
|
||||
bool wait = (stream == nullptr || stream == hipStreamLegacy) ? true : false;
|
||||
constexpr bool kDontWaitForCpu = false;
|
||||
|
||||
auto hip_stream = hip::getStream(stream, wait);
|
||||
bool wait_for_cpu = false;
|
||||
// Force blocking wait if requested. That allows to avoid a build up of unreleased CPU commands
|
||||
if (DEBUG_HIP_BLOCK_SYNC != 0) {
|
||||
static std::atomic<uint64_t> flush = 0;
|
||||
wait_for_cpu = ((++flush % DEBUG_HIP_BLOCK_SYNC) == 0) ? true : false;
|
||||
}
|
||||
// Wait for the current host queue
|
||||
hip_stream->finish(kDontWaitForCpu);
|
||||
hip_stream->finish(wait_for_cpu);
|
||||
if (stream == nullptr) {
|
||||
// null stream will sync with other streams.
|
||||
ReleaseGraphExec(hip_stream->DeviceId());
|
||||
|
||||
Reference in New Issue
Block a user