Files
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

409 lines
22 KiB
C++

// Copyright Advanced Micro Devices, Inc., or its affiliates.
// SPDX-License-Identifier: MIT
#include <rocRoller/Scheduling/Costs/LinearWeightedCost.hpp>
#include <rocRoller/Serialization/YAML.hpp>
#include <rocRoller/Utilities/Settings.hpp>
#include <rocRoller/GPUArchitecture/GPUInstructionInfo.hpp>
namespace rocRoller
{
template <typename IO>
struct Serialization::
MappingTraits<Scheduling::Weights, IO, rocRoller::Serialization::EmptyContext>
{
static const bool flow = false;
using iot = IOTraits<IO>;
static void mapping(IO& io, Scheduling::Weights& weights)
{
// The YAML files from Python now have a `type` field that denotes
// which subset of the weights is included; this is irrelevant in
// C++.
std::string type;
iot::mapOptional(io, "type", type);
iot::mapOptional(io, "nops", weights.nops);
iot::mapOptional(io, "vmcnt", weights.vmcnt);
iot::mapOptional(io, "lgkmcnt", weights.lgkmcnt);
iot::mapOptional(io, "vectorQueueSat", weights.vectorQueueSat);
iot::mapOptional(io, "vmQueueLen", weights.vmQueueLen);
iot::mapOptional(io, "ldsQueueSat", weights.ldsQueueSat);
iot::mapOptional(io, "lgkmQueueLen", weights.lgkmQueueLen);
iot::mapOptional(io, "stallCycles", weights.stallCycles);
iot::mapOptional(io, "newSGPRs", weights.newSGPRs);
iot::mapOptional(io, "newVGPRs", weights.newVGPRs);
iot::mapOptional(io, "highWaterMarkSGPRs", weights.highWaterMarkSGPRs);
iot::mapOptional(io, "highWaterMarkVGPRs", weights.highWaterMarkVGPRs);
iot::mapOptional(io, "notMFMA", weights.notMFMA);
iot::mapOptional(io, "isMFMA", weights.isMFMA);
iot::mapOptional(io, "fractionOfSGPRs", weights.fractionOfSGPRs);
iot::mapOptional(io, "fractionOfVGPRs", weights.fractionOfVGPRs);
iot::mapOptional(io, "outOfRegisters", weights.outOfRegisters);
iot::mapOptional(io, "zeroFreeBarriers", weights.zeroFreeBarriers);
iot::mapOptional(io, "isSMEM", weights.isSMEM);
iot::mapOptional(io, "isSControl", weights.isSControl);
iot::mapOptional(io, "isSALU", weights.isSALU);
iot::mapOptional(io, "isVMEMRead", weights.isVMEMRead);
iot::mapOptional(io, "isVMEMWrite", weights.isVMEMWrite);
iot::mapOptional(io, "isLDSRead", weights.isLDSRead);
iot::mapOptional(io, "isLDSWrite", weights.isLDSWrite);
iot::mapOptional(io, "isVALU", weights.isVALU);
iot::mapOptional(io, "isACCVGPRWrite", weights.isACCVGPRWrite);
iot::mapOptional(io, "isACCVGPRRead", weights.isACCVGPRRead);
iot::mapOptional(io, "vmemCycles", weights.vmemCycles);
iot::mapOptional(io, "vmemQueueSize", weights.vmemQueueSize);
iot::mapOptional(io, "dsmemCycles", weights.dsmemCycles);
iot::mapOptional(io, "dsmemQueueSize", weights.dsmemQueueSize);
}
static void mapping(IO& io, Scheduling::Weights& weights, EmptyContext& ctx)
{
mapping(io, weights);
}
};
namespace Scheduling
{
constexpr Weights GFX950_SIMPLIFIED_WEIGHTS_STREAMK = {
.nops = 10000.0,
.stallCycles = 1000.0,
.isSALU = 154.26834112288643,
.isVALU = 96.5815329589789,
.outOfRegisters = 1000000000.0,
.zeroFreeBarriers = true,
.vmemCycles = 410,
.vmemQueueSize = 3,
.dsmemCycles = 94,
.dsmemQueueSize = 1,
};
constexpr Weights GFX950_SIMPLIFIED_WEIGHTS = {
.nops = 131.82052000047628,
.stallCycles = 1000.0,
.isSALU = 1073.9946584081224,
.isVALU = 96.7974133366133,
.outOfRegisters = 1000000000.0,
.zeroFreeBarriers = false,
.vmemCycles = 149,
.vmemQueueSize = 3,
.dsmemCycles = 46,
.dsmemQueueSize = 2,
};
constexpr Weights GFX950_WEIGHTS = {.nops = 1001.4279088984798,
.vmcnt = 526.093932290615,
.lgkmcnt = 885.6074246484375,
.vmQueueLen = 35,
.vectorQueueSat = 1435.1211330900899,
.ldsQueueSat = 134.22254126254612,
.lgkmQueueLen = 35,
.stallCycles = 1000.0,
.notMFMA = 10986.395913365237,
.isMFMA = 81.12435660463446,
.isSMEM = 199.72403310006476,
.isSControl = 137.84120970739187,
.isSALU = 30.872084606099698,
.isVMEMRead = 85.9588364354184,
.isVMEMWrite = 251.36047887498077,
.isLDSRead = 48.2195248263684,
.isLDSWrite = 84.55911735600286,
.isVALU = 89.04421879077165,
.isACCVGPRWrite = 71.32846565329866,
.isACCVGPRRead = 58.89401902273831,
.newSGPRs = 94.44006642730224,
.newVGPRs = 49.879984390857786,
.highWaterMarkSGPRs = 265.4234682031597,
.highWaterMarkVGPRs = 113.2530825463529,
.fractionOfSGPRs = 45.527998466975674,
.fractionOfVGPRs = 258.19016732766454,
.outOfRegisters = 1000000000.0,
.zeroFreeBarriers = true,
.vmemCycles = 480,
.vmemQueueSize = 3,
.dsmemCycles = 95,
.dsmemQueueSize = 3};
constexpr Weights GFX942_WEIGHTS = {.nops = 194.43894526982916,
.vmcnt = 71.87967451224605,
.lgkmcnt = 57.99317255314543,
.vmQueueLen = 6,
.vectorQueueSat = 194.99142473663127,
.ldsQueueSat = 70.66603652975317,
.lgkmQueueLen = 5,
.stallCycles = 1000.0,
.notMFMA = 33.41526718654649,
.isMFMA = 291.18776903110466,
.isSMEM = 12.84171818450304,
.isSControl = 110.20159698039858,
.isSALU = 159.1603833670879,
.isVMEMRead = 187.42330152238435,
.isVMEMWrite = 122.30683584898141,
.isLDSRead = 35.02310763944675,
.isLDSWrite = 103.59301022907425,
.isVALU = 81.08374289168657,
.isACCVGPRWrite = 113.173666431442,
.isACCVGPRRead = 605.5787621618031,
.newSGPRs = 182.32244316409327,
.newVGPRs = 97.53552053492548,
.highWaterMarkSGPRs = 167.9777964063783,
.highWaterMarkVGPRs = 132.954375228908,
.fractionOfSGPRs = 73.89647742758,
.fractionOfVGPRs = 195.11069104040754,
.outOfRegisters = 1000000000.0,
.zeroFreeBarriers = true};
constexpr Weights GFX90A_WEIGHTS = {.nops = 102.16064235921411,
.vmcnt = 175.18015151123478,
.lgkmcnt = 57.42789675890664,
.vmQueueLen = 4,
.vectorQueueSat = 28.444961163165864,
.ldsQueueSat = 514.0030224624215,
.lgkmQueueLen = 8,
.stallCycles = 1000.0,
.notMFMA = 1126.0097472441112,
.isMFMA = 2064.675633601412,
.isSMEM = 51.73435897493539,
.isSControl = 52.20563014565612,
.isSALU = 187.61842343063546,
.isVMEMRead = 132.51539911592974,
.isVMEMWrite = 211.778830039103,
.isLDSRead = 305.80350680401983,
.isLDSWrite = 374.8770913083329,
.isVALU = 34.88704839783154,
.isACCVGPRWrite = 66.94359848246074,
.isACCVGPRRead = 518.2179267123564,
.newSGPRs = 93.71800320620157,
.newVGPRs = 199.44918165517117,
.highWaterMarkSGPRs = 96.88502683536836,
.highWaterMarkVGPRs = 53.526584801082066,
.fractionOfSGPRs = 12042.440418691136,
.fractionOfVGPRs = 95.71453942518029,
.outOfRegisters = 1000000000.0,
.zeroFreeBarriers = true};
constexpr Weights GFX908_WEIGHTS = {.nops = 620.4481910898397,
.vmcnt = 203.68521471982095,
.lgkmcnt = 318.37307256604777,
.vmQueueLen = 12,
.vectorQueueSat = 35.208369484081274,
.ldsQueueSat = 26.945053555005625,
.lgkmQueueLen = 15,
.stallCycles = 1000.0,
.notMFMA = 117.91373534215671,
.isMFMA = 59.46037213518759,
.isSMEM = 82.61122691405645,
.isSControl = 159.0019357312576,
.isSALU = 86.74764292348273,
.isVMEMRead = 161.7542358360216,
.isVMEMWrite = 128.64699076145752,
.isLDSRead = 144.1002026966658,
.isLDSWrite = 66.83668795251201,
.isVALU = 204.34498440996558,
.isACCVGPRWrite = 59.743294671257594,
.isACCVGPRRead = 90.37656910299161,
.newSGPRs = 4626.184607642332,
.newVGPRs = 73.03434870351303,
.highWaterMarkSGPRs = 162.64312780347115,
.highWaterMarkVGPRs = 21.300679968689767,
.fractionOfSGPRs = 105.34086248489358,
.fractionOfVGPRs = 308.3901444061333,
.outOfRegisters = 1000000000.0,
.zeroFreeBarriers = true};
static_assert(Component::Component<LinearWeightedCost>);
LinearWeightedCost::LinearWeightedCost(ContextPtr ctx, CostFunction fn)
: Cost{ctx}
, m_weights(loadWeights(ctx, fn))
{
}
Weights LinearWeightedCost::loadWeights(ContextPtr ctx, CostFunction fn) const
{
auto settingsFile = Settings::getInstance()->get(Settings::SchedulerWeights);
if(!settingsFile.empty())
{
try
{
return Serialization::readYAMLFile<Weights>(settingsFile);
}
catch(const std::exception& e)
{
Throw<FatalError>(e.what(),
" parsing linear weighted costs file `",
settingsFile,
"` specified by ",
Settings::SchedulerWeights.help());
}
}
else
{
auto const& arch = ctx->targetArchitecture().target();
if(fn == CostFunction::LinearWeightedSimple)
{
if(!arch.isCDNA4GPU())
Log::warn("Architecture {} not tested for simplifed weights.",
arch.toString());
return GFX950_SIMPLIFIED_WEIGHTS;
}
if(fn == CostFunction::LinearWeightedSimpleStreamK)
{
if(!arch.isCDNA4GPU())
Log::warn("Architecture {} not tested for simplifed weights.",
arch.toString());
return GFX950_SIMPLIFIED_WEIGHTS_STREAMK;
}
if(arch.isCDNA1GPU())
return GFX908_WEIGHTS;
else if(arch.isCDNA2GPU())
return GFX90A_WEIGHTS;
else if(arch.isCDNA3GPU())
return GFX942_WEIGHTS;
else if(arch.isCDNA4GPU())
return GFX950_WEIGHTS;
else
{
Log::warn("Unsupported architecture {} for linear weighted cost; defaulting to "
"GFX90A weights",
arch.toString());
return GFX90A_WEIGHTS;
}
}
}
Weights const& LinearWeightedCost::getWeights() const
{
return m_weights;
}
bool LinearWeightedCost::Match(Argument arg)
{
auto [costFn, ctx] = arg;
return costFn == CostFunction::LinearWeighted
|| costFn == CostFunction::LinearWeightedSimple
|| costFn == CostFunction::LinearWeightedSimpleStreamK;
}
std::shared_ptr<Cost> LinearWeightedCost::Build(Argument arg)
{
if(!Match(arg))
return nullptr;
auto [costFn, ctx] = arg;
return std::make_shared<LinearWeightedCost>(ctx, costFn);
}
std::string LinearWeightedCost::name() const
{
return Name;
}
float LinearWeightedCost::cost(Instruction const& inst,
InstructionStatus const& status) const
{
auto nops = static_cast<float>(status.nops);
auto const& arch = m_ctx.lock()->targetArchitecture();
auto maxVmcnt = arch.GetCapability(GPUCapability::MaxVmcnt);
auto maxLgkmcnt = arch.GetCapability(GPUCapability::MaxLgkmcnt);
float vmcnt = 0;
if(status.waitCount.loadcnt() >= 0 || status.waitCount.storecnt() >= 0)
{
auto loadcnt = status.waitCount.loadcnt();
auto storecnt = status.waitCount.storecnt();
auto cnt = WaitCount::CombineValues(loadcnt, storecnt);
vmcnt = 1 + maxVmcnt - cnt;
}
float lgkmcnt = 0;
if(status.waitCount.kmcnt() >= 0 || status.waitCount.dscnt() >= 0)
{
auto kmcnt = status.waitCount.kmcnt();
auto dscnt = status.waitCount.dscnt();
auto cnt = WaitCount::CombineValues(kmcnt, dscnt);
lgkmcnt = 1 + maxLgkmcnt - cnt;
}
int vmQueueLen
= status.waitLengths.at(static_cast<size_t>(GPUWaitQueueType::LoadQueue))
+ status.waitLengths.at(static_cast<size_t>(GPUWaitQueueType::StoreQueue));
float vectorQueueSat = std::max(vmQueueLen - m_weights.vmQueueLen, 0);
int kmQueueLen
= status.waitLengths.at(static_cast<size_t>(GPUWaitQueueType::SMemQueue))
+ status.waitLengths.at(static_cast<size_t>(GPUWaitQueueType::DSQueue));
float ldsQueueSat = std::max(kmQueueLen - m_weights.lgkmQueueLen, 0);
float newSGPRs = status.allocatedRegisters.at(Register::Type::Scalar);
float newVGPRs = status.allocatedRegisters.at(Register::Type::Vector);
float highWaterMarkSGPRs
= status.highWaterMarkRegistersDelta.at(Register::Type::Scalar);
float highWaterMarkVGPRs
= status.highWaterMarkRegistersDelta.at(Register::Type::Vector);
float notMFMA = inst.getOpCode().find("mfma") == std::string::npos ? 1.0f : 0.0f;
float fractionOfSGPRs = status.allocatedRegisters.at(Register::Type::Scalar);
float remainingSGPRs = status.remainingRegisters.at(Register::Type::Scalar);
if(remainingSGPRs > 0)
fractionOfSGPRs /= remainingSGPRs;
float fractionOfVGPRs = status.allocatedRegisters.at(Register::Type::Vector);
float remainingVGPRs = status.remainingRegisters.at(Register::Type::Vector);
if(remainingVGPRs > 0)
fractionOfVGPRs /= remainingVGPRs;
float outOfRegisters = status.outOfRegisters.count();
const auto& gpu = arch.target();
const auto& barrierLiteral = gpu.isRDNA4GPU() ? "s_barrier_wait" : "s_barrier";
if(m_weights.zeroFreeBarriers && inst.getOpCode().starts_with(barrierLiteral)
&& status.waitCount == WaitCount())
return 0;
return m_weights.nops * nops //
+ m_weights.vmcnt * vmcnt //
+ m_weights.lgkmcnt * lgkmcnt //
+ m_weights.vectorQueueSat * vectorQueueSat //
+ m_weights.ldsQueueSat * ldsQueueSat //
+ m_weights.stallCycles * status.stallCycles //
+ m_weights.newSGPRs * newSGPRs //
+ m_weights.newVGPRs * newVGPRs //
+ m_weights.highWaterMarkSGPRs * highWaterMarkSGPRs //
+ m_weights.highWaterMarkVGPRs * highWaterMarkVGPRs //
+ m_weights.notMFMA * notMFMA //
//+ m_weights.isMFMA * (1.0f - notMFMA) //
+ m_weights.fractionOfSGPRs * fractionOfSGPRs //
+ m_weights.fractionOfVGPRs * fractionOfVGPRs //
+ m_weights.outOfRegisters * outOfRegisters //
+ m_weights.isSMEM * GPUInstructionInfo::isSMEM(inst.getOpCode()) //
+ m_weights.isSControl * GPUInstructionInfo::isSControl(inst.getOpCode()) //
+ m_weights.isSALU * GPUInstructionInfo::isSALU(inst.getOpCode()) //
+ m_weights.isVMEMRead * GPUInstructionInfo::isVMEMRead(inst.getOpCode()) //
+ m_weights.isVMEMWrite * GPUInstructionInfo::isVMEMWrite(inst.getOpCode()) //
+ m_weights.isLDSRead * GPUInstructionInfo::isLDSRead(inst.getOpCode()) //
+ m_weights.isLDSWrite * GPUInstructionInfo::isLDSWrite(inst.getOpCode()) //
+ m_weights.isVALU * GPUInstructionInfo::isVALU(inst.getOpCode()) //
+ m_weights.isACCVGPRWrite
* GPUInstructionInfo::isACCVGPRWrite(inst.getOpCode()) //
+ m_weights.isACCVGPRRead
* GPUInstructionInfo::isACCVGPRRead(inst.getOpCode()) //
;
}
}
}