diff --git a/rocclr/runtime/device/gpu/gpuwavelimiter.cpp b/rocclr/runtime/device/gpu/gpuwavelimiter.cpp index db568d787a..d75005056c 100644 --- a/rocclr/runtime/device/gpu/gpuwavelimiter.cpp +++ b/rocclr/runtime/device/gpu/gpuwavelimiter.cpp @@ -14,21 +14,10 @@ namespace gpu { uint WaveLimiter::MaxWave; uint WaveLimiter::WarmUpCount; -uint WaveLimiter::AdaptCount; uint WaveLimiter::RunCount; -uint WaveLimiter::AbandonThresh; -uint WaveLimiter::DscThresh; - -void WaveLimiter::clearData() { - waves_ = MaxWave; - countAll_ = 0; - clear(measure_); - clear(reference_); - clear(trial_); - clear(ratio_); - discontinuous_ = false; - dataCount_ = 0; -} +uint WLAlgorithmSmooth::AdaptCount; +uint WLAlgorithmSmooth::AbandonThresh; +uint WLAlgorithmSmooth::DscThresh; WaveLimiter::WaveLimiter( Kernel* owner, @@ -42,21 +31,11 @@ WaveLimiter::WaveLimiter( auto hwInfo = gpuDev->hwInfo(); setIfNotDefault(SIMDPerSH_, GPU_WAVE_LIMIT_CU_PER_SH, attrib.numberOfCUsperShaderArray * hwInfo->simdPerCU_); - MaxWave = GPU_WAVE_LIMIT_MAX_WAVE; WarmUpCount = GPU_WAVE_LIMIT_WARMUP; - AdaptCount = 2 * MaxWave + 1; RunCount = GPU_WAVE_LIMIT_RUN * MaxWave; - AbandonThresh = GPU_WAVE_LIMIT_ABANDON; - DscThresh = GPU_WAVE_LIMIT_DSC_THRESH; state_ = WARMUP; - dynRunCount_ = RunCount; - measure_.resize(MaxWave + 1); - reference_.resize(MaxWave + 1); - trial_.resize(MaxWave + 1); - ratio_.resize(MaxWave + 1); - clearData(); if (!flagIsDefault(GPU_WAVE_LIMIT_TRACE)) { traceStream_.open(std::string(GPU_WAVE_LIMIT_TRACE) + owner_->name() + ".txt"); @@ -79,7 +58,37 @@ uint WaveLimiter::getWavesPerSH(){ return waves_ * SIMDPerSH_; } -void WaveLimiter::updateData(ulong time) { +WLAlgorithmSmooth::WLAlgorithmSmooth(Kernel* owner, uint seqNum, bool enable, bool enableDump): + WaveLimiter(owner, seqNum, enable, enableDump) { + AdaptCount = 2 * MaxWave + 1; + AbandonThresh = GPU_WAVE_LIMIT_ABANDON; + DscThresh = GPU_WAVE_LIMIT_DSC_THRESH; + + dynRunCount_ = RunCount; + measure_.resize(MaxWave + 1); + reference_.resize(MaxWave + 1); + trial_.resize(MaxWave + 1); + ratio_.resize(MaxWave + 1); + + clearData(); +} + +WLAlgorithmSmooth::~WLAlgorithmSmooth() { + +} + +void WLAlgorithmSmooth::clearData() { + waves_ = MaxWave; + countAll_ = 0; + clear(measure_); + clear(reference_); + clear(trial_); + clear(ratio_); + discontinuous_ = false; + dataCount_ = 0; +} + +void WLAlgorithmSmooth::updateData(ulong time) { auto count = dataCount_ - 1; assert(count < 2 * MaxWave + 1); assert(time > 0); @@ -108,7 +117,7 @@ void WaveLimiter::updateData(ulong time) { outputTrace(); } -void WaveLimiter::outputTrace() { +void WLAlgorithmSmooth::outputTrace() { if (!traceStream_.is_open()) { return; } @@ -122,7 +131,8 @@ void WaveLimiter::outputTrace() { traceStream_ << "\n\n"; } -void WaveLimiter::callback(ulong duration) { + +void WLAlgorithmSmooth::callback(ulong duration) { dumper_.addData(duration, currWaves_, static_cast(state_)); if (!enable_) { @@ -207,11 +217,79 @@ void WaveLimiter::DataDumper::addData(ulong time, uint wave, char state) { state_.push_back(state); } +WLAlgorithmAvrg::WLAlgorithmAvrg(Kernel* owner, uint seqNum, bool enable, bool enableDump): + WaveLimiter(owner, seqNum, enable, enableDump) { + + measure_.resize(MaxWave + 1); + clear(measure_); + countAll_ = 0; +} + +WLAlgorithmAvrg::~WLAlgorithmAvrg() { + +} + +void WLAlgorithmAvrg::outputTrace() { + if (!traceStream_.is_open()) { + return; + } + + traceStream_ << "[WaveLimiter] " << owner_->name() << " state=" << state_ + << " currWaves=" << currWaves_ << " waves=" << waves_ + << " bestWave=" << bestWave_ << '\n'; + output(traceStream_, "\n measure = ", measure_); + traceStream_ << "\n\n"; +} + + +void WLAlgorithmAvrg::callback(ulong duration) { + dumper_.addData(duration, currWaves_, static_cast(state_)); + + if (!enable_) { + return; + } + + countAll_++; + + switch (state_) { + case WARMUP: + state_ = ADAPT; + case ADAPT: + measure_[waves_] += duration; + if (countAll_ <= MaxWave * 5) { + waves_--; + if (waves_ == 0) { + waves_ = MaxWave; + } + } + else { + bestWave_ = MaxWave; + for (uint i=1; i(&owner_->dev()); + auto attrib = gpuDev->getAttribs(); + auto hwInfo = gpuDev->hwInfo(); + unsigned simdPerSH = 0; + setIfNotDefault(simdPerSH, GPU_WAVE_LIMIT_CU_PER_SH, + attrib.numberOfCUsperShaderArray * hwInfo->simdPerCU_); + fixed_ = GPU_WAVES_PER_SIMD * simdPerSH; } WaveLimiterManager::~WaveLimiterManager() { @@ -248,7 +326,7 @@ amd::ProfilingCallback* WaveLimiterManager::getProfilingCallback( return loc->second; } - auto limiter = new WaveLimiter(owner_, limiters_.size(), enable_, + auto limiter = new WLAlgorithmSmooth(owner_, limiters_.size(), enable_, enableDump_); if (limiter == NULL) { enable_ = false; diff --git a/rocclr/runtime/device/gpu/gpuwavelimiter.hpp b/rocclr/runtime/device/gpu/gpuwavelimiter.hpp index 49c25adddf..b8f2d6ce6a 100644 --- a/rocclr/runtime/device/gpu/gpuwavelimiter.hpp +++ b/rocclr/runtime/device/gpu/gpuwavelimiter.hpp @@ -27,7 +27,7 @@ public: //! Get waves per shader array to be used for kernel execution. uint getWavesPerSH(); -private: +protected: enum StateKind { WARMUP, ADAPT, RUN }; @@ -51,42 +51,26 @@ private: }; std::vector measure_; - std::vector reference_; - std::vector trial_; - std::vector ratio_; - bool discontinuous_; // Measured data is discontinuous - bool enable_; uint SIMDPerSH_; // Number of SIMDs per SH uint waves_; // Waves per SIMD to be set uint bestWave_; // Optimal waves per SIMD uint countAll_; // Number of kernel executions - uint dynRunCount_; StateKind state_; Kernel *owner_; DataDumper dumper_; std::ofstream traceStream_; uint currWaves_; // Current waves per SIMD - uint dataCount_; static uint MaxWave; // Maximum number of waves per SIMD static uint WarmUpCount; // Number of kernel executions for warm up - static uint AdaptCount; // Number of kernel executions for adapting static uint RunCount; // Number of kernel executions for normal run - static uint AbandonThresh; // Threshold to abandon adaptation - static uint DscThresh; // Threshold for identifying discontinuities //! Call back from Event::recordProfilingInfo to get execution time. - virtual void callback(ulong duration); - - //! Update measurement data and optimal waves/simd with execution time. - void updateData(ulong time); + virtual void callback(ulong duration)=0; //! Output trace of measurement/adaptation. - void outputTrace(); - - //! Clear measurement data for the next adaptation. - void clearData(); + virtual void outputTrace()=0; template void clear(T& A) { for (auto &I : A) { @@ -102,6 +86,47 @@ private: } }; +class WLAlgorithmSmooth: public WaveLimiter { +public: + explicit WLAlgorithmSmooth(Kernel* owner, uint seqNum, bool enable, bool enableDump); + virtual ~WLAlgorithmSmooth(); +private: + std::vector reference_; + std::vector trial_; + std::vector ratio_; + bool discontinuous_; // Measured data is discontinuous + uint dynRunCount_; + uint dataCount_; + + static uint AdaptCount; // Number of kernel executions for adapting + static uint AbandonThresh; // Threshold to abandon adaptation + static uint DscThresh; // Threshold for identifying discontinuities + + //! Update measurement data and optimal waves/simd with execution time. + void updateData(ulong time); + + //! Clear measurement data for the next adaptation. + void clearData(); + + //! Call back from Event::recordProfilingInfo to get execution time. + void callback(ulong duration); + + //! Output trace of measurement/adaptation. + void outputTrace(); +}; + +class WLAlgorithmAvrg: public WaveLimiter { +public: + explicit WLAlgorithmAvrg(Kernel* owner, uint seqNum, bool enable, bool enableDump); + virtual ~WLAlgorithmAvrg(); +private: + //! Call back from Event::recordProfilingInfo to get execution time. + void callback(ulong duration); + + //! Output trace of measurement/adaptation. + void outputTrace(); +}; + // Create wave limiter for each virtual device for a kernel and manages the wave limiters. class WaveLimiterManager { public: