Files
TheRock/rocm-libraries/shared/rocroller/lib/source/CodeGen/WaitCount.cpp
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

585 lines
17 KiB
C++

// Copyright Advanced Micro Devices, Inc., or its affiliates.
// SPDX-License-Identifier: MIT
#include <rocRoller/CodeGen/WaitCount.hpp>
#include "rocRoller/GPUArchitecture/GPUArchitectureLibrary.hpp"
#include "rocRoller/GPUArchitecture/GPUArchitectureTarget.hpp"
#include <rocRoller/CodeGen/Instruction.hpp>
#include <rocRoller/Utilities/Settings.hpp>
#include <rocRoller/Utilities/String.hpp>
namespace rocRoller
{
WaitCount::WaitCount(GPUArchitecture const& arch, std::string const& message)
{
m_isSplitCounter = arch.HasCapability(GPUCapability::HasSplitWaitCounters);
m_hasVSCnt = arch.HasCapability(GPUCapability::SeparateVscnt);
m_hasEXPCnt = arch.HasCapability(GPUCapability::HasExpcnt);
m_hasTensorCnt = arch.HasCapability(GPUCapability::HasTensorcnt);
if(message.length() > 0)
{
m_comments = {message};
}
}
WaitCount::WaitCount(GPUArchitecture const& arch,
int loadcnt,
int storecnt,
int vscnt,
int dscnt,
int kmcnt,
int expcnt,
int tensorcnt)
: m_loadcnt(loadcnt)
, m_storecnt(storecnt)
, m_vscnt(vscnt)
, m_dscnt(dscnt)
, m_kmcnt(kmcnt)
, m_expcnt(expcnt)
, m_tensorcnt(tensorcnt)
, m_isSplitCounter(arch.HasCapability(GPUCapability::HasSplitWaitCounters))
, m_hasVSCnt(arch.HasCapability(GPUCapability::SeparateVscnt))
, m_hasEXPCnt(arch.HasCapability(GPUCapability::HasExpcnt))
, m_hasTensorCnt(arch.HasCapability(GPUCapability::HasTensorcnt))
{
}
WaitCount::WaitCount(GPUArchitecture const& arch, GPUWaitQueue queue, int count)
: m_loadcnt(-1)
, m_storecnt(-1)
, m_vscnt(-1)
, m_dscnt(-1)
, m_kmcnt(-1)
, m_expcnt(-1)
, m_tensorcnt(-1)
, m_isSplitCounter(arch.HasCapability(GPUCapability::HasSplitWaitCounters))
, m_hasVSCnt(arch.HasCapability(GPUCapability::SeparateVscnt))
, m_hasEXPCnt(arch.HasCapability(GPUCapability::HasExpcnt))
, m_hasTensorCnt(arch.HasCapability(GPUCapability::HasTensorcnt))
{
switch(queue)
{
case GPUWaitQueue::LoadQueue:
m_loadcnt = count;
break;
case GPUWaitQueue::StoreQueue:
m_storecnt = count;
break;
case GPUWaitQueue::DSQueue:
m_dscnt = count;
break;
case GPUWaitQueue::KMQueue:
m_kmcnt = count;
break;
case GPUWaitQueue::EXPQueue:
m_expcnt = count;
break;
case GPUWaitQueue::VSQueue:
m_vscnt = count;
break;
case GPUWaitQueue::TensorQueue:
m_tensorcnt = count;
break;
case GPUWaitQueue::None:
case GPUWaitQueue::Count:
Throw<FatalError>("Invalid GPUWaitQueue!");
break;
}
}
WaitCount::WaitCount(GPUArchitecture const& arch,
EnumBitset<GPUWaitQueueType> queuesToSync,
std::string const& message)
: m_queuesToSync(queuesToSync)
, m_comments({message})
{
}
WaitCount WaitCount::LoadCnt(GPUArchitecture const& arch, int value, std::string const& message)
{
WaitCount rv{arch, message};
rv.m_loadcnt = value;
return rv;
}
WaitCount
WaitCount::StoreCnt(GPUArchitecture const& arch, int value, std::string const& message)
{
WaitCount rv{arch, message};
rv.m_storecnt = value;
return rv;
}
WaitCount WaitCount::VSCnt(GPUArchitecture const& arch, int value, std::string const& message)
{
WaitCount rv{arch, message};
rv.m_vscnt = value;
return rv;
}
WaitCount WaitCount::DSCnt(GPUArchitecture const& arch, int value, std::string const& message)
{
WaitCount rv{arch, message};
rv.m_dscnt = value;
return rv;
}
WaitCount WaitCount::KMCnt(GPUArchitecture const& arch, int value, std::string const& message)
{
WaitCount rv{arch, message};
rv.m_kmcnt = value;
return rv;
}
WaitCount WaitCount::EXPCnt(GPUArchitecture const& arch, int value, std::string const& message)
{
WaitCount rv{arch, message};
rv.m_expcnt = value;
return rv;
}
WaitCount
WaitCount::TensorCnt(GPUArchitecture const& arch, int value, std::string const& message)
{
WaitCount rv{arch, message};
rv.m_tensorcnt = value;
return rv;
}
WaitCount WaitCount::Zero(GPUArchitecture const& architecture, std::string const& message)
{
WaitCount rv{architecture, message};
rv.m_loadcnt = 0;
rv.m_storecnt = 0;
if(architecture.HasCapability(GPUCapability::SeparateVscnt))
{
rv.m_vscnt = 0;
}
rv.m_dscnt = 0;
rv.m_kmcnt = 0;
if(architecture.HasCapability(GPUCapability::HasExpcnt))
{
rv.m_expcnt = 0;
}
if(architecture.HasCapability(GPUCapability::HasTensorcnt))
{
rv.m_tensorcnt = 0;
}
return rv;
}
WaitCount WaitCount::Max(GPUArchitecture const& architecture, std::string const& message)
{
WaitCount rv{architecture, message};
if(architecture.HasCapability(GPUCapability::MaxVmcnt))
{
rv.m_loadcnt = architecture.GetCapability(GPUCapability::MaxVmcnt);
rv.m_storecnt = architecture.GetCapability(GPUCapability::MaxVmcnt);
}
if(architecture.HasCapability(GPUCapability::MaxLgkmcnt))
{
rv.m_dscnt = architecture.GetCapability(GPUCapability::MaxLgkmcnt);
rv.m_kmcnt = architecture.GetCapability(GPUCapability::MaxLgkmcnt);
}
if(architecture.HasCapability(GPUCapability::HasExpcnt)
&& architecture.HasCapability(GPUCapability::MaxExpcnt))
{
rv.m_expcnt = architecture.GetCapability(GPUCapability::MaxExpcnt);
}
if(architecture.HasCapability(GPUCapability::HasTensorcnt)
&& architecture.HasCapability(GPUCapability::MaxTensorcnt))
{
rv.m_tensorcnt = architecture.GetCapability(GPUCapability::MaxTensorcnt);
}
return rv;
}
WaitCount WaitCount::SyncQueue(GPUArchitecture const& arch,
GPUWaitQueueType queue,
std::string const& message)
{
return SyncQueues(arch, EnumBitset<GPUWaitQueueType>{queue}, message);
}
WaitCount WaitCount::SyncQueues(GPUArchitecture const& arch,
EnumBitset<GPUWaitQueueType> queues,
std::string const& message)
{
return WaitCount(arch, queues, message);
}
EnumBitset<GPUWaitQueueType> const& WaitCount::queuesToSync() const
{
return m_queuesToSync;
}
int WaitCount::CombineValues(int lhs, int rhs)
{
if(lhs < 0)
{
return rhs;
}
if(rhs < 0)
{
return lhs;
}
return std::min(lhs, rhs);
}
WaitCount& WaitCount::combine(WaitCount const& other)
{
m_loadcnt = CombineValues(m_loadcnt, other.m_loadcnt);
m_storecnt = CombineValues(m_storecnt, other.m_storecnt);
m_vscnt = CombineValues(m_vscnt, other.m_vscnt);
m_dscnt = CombineValues(m_dscnt, other.m_dscnt);
m_kmcnt = CombineValues(m_kmcnt, other.m_kmcnt);
m_expcnt = CombineValues(m_expcnt, other.m_expcnt);
m_tensorcnt = CombineValues(m_tensorcnt, other.m_tensorcnt);
m_isSplitCounter = other.m_isSplitCounter;
m_hasVSCnt = other.m_hasVSCnt;
m_hasEXPCnt = other.m_hasEXPCnt;
m_hasTensorCnt = other.m_hasTensorCnt;
m_comments.insert(m_comments.end(), other.m_comments.begin(), other.m_comments.end());
m_queuesToSync |= other.m_queuesToSync;
return *this;
}
int WaitCount::loadcnt() const
{
return m_loadcnt;
}
int WaitCount::storecnt() const
{
return m_storecnt;
}
int WaitCount::vmcnt() const
{
return WaitCount::CombineValues(m_loadcnt, m_storecnt);
}
int WaitCount::vscnt() const
{
return m_vscnt;
}
int WaitCount::dscnt() const
{
return m_dscnt;
}
int WaitCount::kmcnt() const
{
return m_kmcnt;
}
int WaitCount::expcnt() const
{
return m_expcnt;
}
int WaitCount::tensorcnt() const
{
return m_tensorcnt;
}
int WaitCount::getCount(GPUWaitQueue queue) const
{
switch(queue)
{
case GPUWaitQueue::LoadQueue:
return m_loadcnt;
case GPUWaitQueue::StoreQueue:
return m_storecnt;
case GPUWaitQueue::DSQueue:
return m_dscnt;
case GPUWaitQueue::KMQueue:
return m_kmcnt;
case GPUWaitQueue::EXPQueue:
return m_expcnt;
case GPUWaitQueue::VSQueue:
return m_vscnt;
case GPUWaitQueue::TensorQueue:
return m_tensorcnt;
default:
return -1;
}
}
void WaitCount::setLoadcnt(int value)
{
m_loadcnt = value;
}
void WaitCount::setStorecnt(int value)
{
m_storecnt = value;
}
void WaitCount::setVscnt(int value)
{
m_vscnt = value;
}
void WaitCount::setDScnt(int value)
{
m_dscnt = value;
}
void WaitCount::setKMcnt(int value)
{
m_kmcnt = value;
}
void WaitCount::setExpcnt(int value)
{
m_expcnt = value;
}
void WaitCount::setTensorcnt(int value)
{
m_tensorcnt = value;
}
WaitCount& WaitCount::combineLoadcnt(int value)
{
m_loadcnt = CombineValues(m_loadcnt, value);
return *this;
}
WaitCount& WaitCount::combineStorecnt(int value)
{
m_storecnt = CombineValues(m_storecnt, value);
return *this;
}
WaitCount& WaitCount::combineVscnt(int value)
{
m_vscnt = CombineValues(m_vscnt, value);
return *this;
}
WaitCount& WaitCount::combineDScnt(int value)
{
m_dscnt = CombineValues(m_dscnt, value);
return *this;
}
WaitCount& WaitCount::combineKMcnt(int value)
{
m_kmcnt = CombineValues(m_kmcnt, value);
return *this;
}
WaitCount& WaitCount::combineExpcnt(int value)
{
m_expcnt = CombineValues(m_expcnt, value);
return *this;
}
WaitCount& WaitCount::combineTensorcnt(int value)
{
m_tensorcnt = CombineValues(m_tensorcnt, value);
return *this;
}
std::vector<std::string> const& WaitCount::comments() const
{
return m_comments;
}
void WaitCount::addComment(std::string const& comment)
{
m_comments.emplace_back(comment);
}
void WaitCount::addComment(std::string&& comment)
{
m_comments.emplace_back(std::move(comment));
}
WaitCount WaitCount::getAsSaturatedWaitCount(GPUArchitecture const& arch) const
{
int loadcnt = m_loadcnt;
int storecnt = m_storecnt;
int vscnt = m_vscnt;
int dscnt = m_dscnt;
int kmcnt = m_kmcnt;
int expcnt = m_expcnt;
int tensorcnt = m_tensorcnt;
if(arch.HasCapability(GPUCapability::MaxVmcnt))
{
loadcnt = std::min(loadcnt, arch.GetCapability(GPUCapability::MaxVmcnt));
storecnt = std::min(storecnt, arch.GetCapability(GPUCapability::MaxVmcnt));
}
if(arch.HasCapability(GPUCapability::MaxLgkmcnt))
{
kmcnt = std::min(kmcnt, arch.GetCapability(GPUCapability::MaxLgkmcnt));
dscnt = std::min(dscnt, arch.GetCapability(GPUCapability::MaxLgkmcnt));
}
if(arch.HasCapability(GPUCapability::MaxExpcnt))
{
expcnt = std::min(expcnt, arch.GetCapability(GPUCapability::MaxExpcnt));
}
if(arch.HasCapability(GPUCapability::MaxTensorcnt))
{
tensorcnt = std::min(tensorcnt, arch.GetCapability(GPUCapability::MaxTensorcnt));
}
return WaitCount(arch, loadcnt, storecnt, vscnt, dscnt, kmcnt, expcnt, tensorcnt);
}
void WaitCount::toStream(std::ostream& os, LogLevel level) const
{
auto commentIter = level > LogLevel::Terse ? m_comments.begin() : m_comments.end();
if(m_loadcnt >= 0 || m_storecnt >= 0 || m_kmcnt >= 0 || m_dscnt >= 0 || m_expcnt >= 0
|| m_tensorcnt >= 0)
{
if(m_isSplitCounter)
{
if(m_loadcnt >= 0)
{
os << "s_wait_loadcnt " << m_loadcnt << std::endl;
}
if(m_storecnt >= 0)
{
os << "s_wait_storecnt " << m_storecnt << std::endl;
}
if(m_kmcnt >= 0)
{
os << "s_wait_kmcnt " << m_kmcnt << std::endl;
}
if(m_dscnt >= 0)
{
os << "s_wait_dscnt " << m_dscnt << std::endl;
}
if(m_expcnt >= 0)
{
AssertFatal(m_hasEXPCnt,
"EXPCnt is not a valid counter in target architecture");
os << "s_wait_expcnt " << m_expcnt << std::endl;
}
if(m_tensorcnt >= 0)
{
AssertFatal(m_hasTensorCnt,
"TensorCnt is not a valid counter in target architecture");
os << "s_wait_tensorcnt " << m_tensorcnt << std::endl;
}
}
else
{
os << "s_waitcnt";
if(vmcnt() >= 0)
{
os << " vmcnt(" << vmcnt() << ")";
}
if(m_kmcnt >= 0 || m_dscnt >= 0)
{
auto lgkmcnt = WaitCount::CombineValues(m_kmcnt, m_dscnt);
os << " lgkmcnt(" << lgkmcnt << ")";
}
if(m_expcnt >= 0)
{
AssertFatal(m_hasEXPCnt,
"EXPCnt is not a valid counter in target architecture");
os << " expcnt(" << m_expcnt << ")";
}
}
if(commentIter != m_comments.end())
{
for(auto const& line : EscapeComment(*commentIter))
os << line;
commentIter++;
}
os << "\n";
}
if(m_vscnt >= 0)
{
AssertFatal(m_hasVSCnt, "VSCnt is not a valid counter in target architecture");
os << "s_waitcnt_vscnt " << m_vscnt;
if(commentIter != m_comments.end())
{
for(auto const& line : EscapeComment(*commentIter))
os << line;
commentIter++;
}
os << "\n";
}
if(level > LogLevel::Debug)
{
auto fieldComment = fmt::format(
"m_loadcnt({}) m_storecnt({}) m_vscnt({}) m_dscnt({}) m_kmcnt({}) m_expcnt({})",
m_loadcnt,
m_storecnt,
m_vscnt,
m_dscnt,
m_kmcnt,
m_expcnt);
if(m_queuesToSync.any())
{
fieldComment
+= fmt::format(" m_queuesToSync({})", rocRoller::toString(m_queuesToSync));
}
for(auto const& line : EscapeComment(fieldComment))
os << line;
os << "\n";
}
if(commentIter != m_comments.end())
{
for(; commentIter != m_comments.end(); commentIter++)
{
for(auto const& line : EscapeComment(*commentIter))
os << line;
}
os << "\n";
}
}
std::string WaitCount::toString(LogLevel level) const
{
std::ostringstream oss;
toStream(oss, level);
return oss.str();
}
std::ostream& operator<<(std::ostream& stream, WaitCount const& wait)
{
auto logLevel = Settings::getInstance()->get(Settings::LogLvl);
wait.toStream(stream, logLevel);
return stream;
}
}