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

681 lines
25 KiB
C++

// Copyright Advanced Micro Devices, Inc., or its affiliates.
// SPDX-License-Identifier: MIT
#include <algorithm>
#include <rocRoller/CommandSolution.hpp>
#include <rocRoller/AssemblyKernel.hpp>
#include <rocRoller/ExecutableKernel.hpp>
#include <rocRoller/ExpressionTransformations.hpp>
#include <rocRoller/KernelArguments.hpp>
#include <rocRoller/KernelGraph/KernelGraph.hpp>
#include <rocRoller/KernelGraph/Transforms/All.hpp>
#include <rocRoller/KernelOptions_detail.hpp>
#include <rocRoller/Operations/Command.hpp>
#include <rocRoller/Utilities/Settings.hpp>
#include <rocRoller/Utilities/Timer.hpp>
namespace rocRoller
{
std::string CommandParameters::toString() const
{
std::ostringstream msg;
msg << ShowValue(allowAmbiguousMemoryNodes);
msg << ShowValue(enableLongDwordInstructions);
msg << ShowValue(transposeMemoryAccess);
msg << ShowValue(packMultipleElementsInto1VGPR);
msg << ShowValue(unrollK);
msg << ShowValue(fuseLoops);
msg << ShowValue(tailLoops);
msg << ShowValue(prefetch);
msg << ShowValue(prefetchInFlight);
msg << ShowValue(prefetchLDSFactor);
msg << ShowValue(prefetchMixMemOps);
msg << ShowValue(streamK);
msg << "loopOverOutputTilesDimensions: ";
streamJoin(msg, loopOverOutputTilesDimensions, ", ");
msg << std::endl;
msg << ShowValue(loopOverOutputTilesTopLoop);
msg << "loopOverOutputTilesCoordSizes: ";
streamJoin(msg, loopOverOutputTilesCoordSizes, ", ");
msg << std::endl;
msg << ShowValue(loopOverOutputTilesIteratedTiles);
msg << "dimInfo: " << std::endl;
for(auto const& [tag, dim] : m_dimInfo)
msg << " " << tag << ": " << dim << std::endl;
if(m_workgroupSize)
{
msg << "workgroupSize: ";
streamJoin(msg, *m_workgroupSize, ", ");
msg << std::endl;
}
if(m_wavefrontCounts)
{
auto const& [a, b] = *m_wavefrontCounts;
msg << "wavefrontCounts: [" << a << ", " << b << "]" << std::endl;
}
msg << ShowValue(m_kernelDimension);
msg << "waveTilesPerWavefront: [";
streamJoin(msg, m_waveTilesPerWavefront, ", ");
msg << "]" << std::endl;
msg << ShowValue(m_splitStoreTileIntoWaveBlocks);
return msg.str();
}
CommandParameters::CommandParameters()
: m_waveTilesPerWavefront({1, 1})
{
transposeMemoryAccess.set(LayoutType::ROW_MAJOR, true);
transposeMemoryAccess.set(LayoutType::COLUMN_MAJOR, false);
}
void CommandParameters::setDimensionInfo(Operations::OperationTag tag,
KernelGraph::CoordinateGraph::Dimension dim)
{
m_dimInfo[tag] = dim;
}
std::map<Operations::OperationTag, KernelGraph::CoordinateGraph::Dimension>
CommandParameters::getDimensionInfo() const
{
return m_dimInfo;
}
int CommandParameters::getManualKernelDimension() const
{
return m_kernelDimension;
}
void CommandParameters::setManualKernelDimension(int dim)
{
m_kernelDimension = dim;
}
void CommandParameters::setManualWorkgroupSize(std::array<unsigned int, 3> const& v)
{
m_workgroupSize = v;
}
void CommandParameters::setManualWorkgroupClusterSize(std::array<unsigned int, 3> const& v)
{
m_workgroupClusterSize = v;
}
std::optional<std::array<unsigned int, 3>> CommandParameters::getManualWorkgroupSize() const
{
return m_workgroupSize;
}
std::optional<std::array<unsigned int, 3>>
CommandParameters::getManualWorkgroupClusterSize() const
{
return m_workgroupClusterSize;
}
void CommandParameters::setManualWavefrontCount(std::pair<uint, uint> wavefrontCounts)
{
m_wavefrontCounts = wavefrontCounts;
}
std::optional<std::pair<uint, uint>> CommandParameters::getManualWavefrontCounts() const
{
return m_wavefrontCounts;
}
void CommandLaunchParameters::setManualWorkitemCount(
std::array<Expression::ExpressionPtr, 3> const& v)
{
m_workitemCount = v;
}
std::optional<std::array<Expression::ExpressionPtr, 3>>
CommandLaunchParameters::getManualWorkitemCount() const
{
return m_workitemCount;
}
void CommandParameters::setWaveTilesPerWavefront(unsigned int x, unsigned int y)
{
m_waveTilesPerWavefront[0] = x;
m_waveTilesPerWavefront[1] = y;
}
std::vector<unsigned int> CommandParameters::getWaveTilesPerWavefront() const
{
return m_waveTilesPerWavefront;
}
void CommandParameters::setSplitStoreTileIntoWaveBlocks(bool x)
{
m_splitStoreTileIntoWaveBlocks = x;
}
bool CommandParameters::getSplitStoreTileIntoWaveBlocks() const
{
return m_splitStoreTileIntoWaveBlocks;
}
KernelArguments CommandKernel::getKernelArguments(RuntimeArguments const& args)
{
TIMER(t, "CommandKernel::getKernelArguments");
bool log = Log::getLogger()->should_log(LogLevel::Debug);
KernelArguments rv(log);
auto const& argStructs = m_context->kernel()->arguments();
rv.reserve(m_context->kernel()->argumentSize(), argStructs.size());
for(auto& arg : argStructs)
{
auto value = Expression::evaluate(arg.getExpression(), args);
if(variableType(value) != arg.getVariableType())
{
throw std::runtime_error(concatenate("Evaluated argument type ",
variableType(value),
" doesn't match expected type ",
arg.getVariableType(),
", Expression: ",
toString(arg.getExpression()),
", name: ",
arg.getName()));
}
rv.append(arg.getName(), value);
}
return rv;
}
KernelInvocation CommandKernel::getKernelInvocation(RuntimeArguments const& args)
{
TIMER(t, "CommandKernel::getKernelInvocation");
KernelInvocation rv;
rv.workgroupSize = m_context->kernel()->workgroupSize();
auto const& workitems = m_context->kernel()->workitemCount();
if(workitems[0])
rv.workitemCount[0] = getUnsignedInt(evaluate(workitems[0], args));
if(workitems[1])
rv.workitemCount[1] = getUnsignedInt(evaluate(workitems[1], args));
if(workitems[2])
rv.workitemCount[2] = getUnsignedInt(evaluate(workitems[2], args));
auto const& sharedMem = m_context->kernel()->dynamicSharedMemBytes();
if(sharedMem)
rv.sharedMemBytes = getUnsignedInt(evaluate(sharedMem, args));
rv.workgroupClusterSize = m_context->kernel()->workgroupClusterSize();
return rv;
}
void CommandKernel::setContext(ContextPtr context)
{
m_context = context;
}
CommandKernel::CommandKernel(CommandPtr command, std::string kernelName)
: m_command(command)
, m_name(kernelName)
{
}
KernelGraph::KernelGraphPtr CommandKernel::getKernelGraph() const
{
return m_kernelGraph;
}
CommandPtr CommandKernel::getCommand() const
{
return m_command;
}
hipFunction_t CommandKernel::getHipFunction() const
{
return m_executableKernel->getHipFunction();
}
std::string CommandKernel::getInstructions() const
{
return m_context->instructions()->toString();
}
std::string CommandKernel::getKernelName() const
{
return m_name;
}
Generator<Instruction> commandComments(CommandPtr command)
{
co_yield Instruction::Comment(command->toString());
co_yield Instruction::Comment(command->argInfo());
}
CommandArgumentPtr findArgumentByName(CommandPtr const command, std::string const& argName)
{
auto const& arguments = command->getArguments();
auto it = std::ranges::find_if(arguments, [&](auto x) { return x->name() == argName; });
if(it == arguments.end())
return nullptr;
return *it;
}
void CommandKernel::generateKernelGraph()
{
TIMER(t, "CommandKernel::generateKernelGraph");
AssertFatal(m_context);
KernelGraph::ConstraintStatus check;
if(!m_commandParameters)
m_commandParameters = std::make_shared<CommandParameters>();
// TODO: Determine the correct kernel dimensions
if(m_commandParameters->getManualKernelDimension() > 0)
m_context->kernel()->setKernelDimensions(
m_commandParameters->getManualKernelDimension());
else
m_context->kernel()->setKernelDimensions(1);
// TODO: Determine the correct work group size
if(m_commandParameters->getManualWorkgroupSize())
m_context->kernel()->setWorkgroupSize(*m_commandParameters->getManualWorkgroupSize());
else
{
unsigned int wfs = m_context->targetArchitecture().GetCapability(
GPUCapability::DefaultWavefrontSize);
m_context->kernel()->setWorkgroupSize({wfs, 1, 1});
}
if(m_commandParameters->getManualWorkgroupClusterSize())
{
m_context->kernel()->setWorkgroupClusterSize(
*m_commandParameters->getManualWorkgroupClusterSize());
}
auto zero = std::make_shared<Expression::Expression>(0u);
m_context->kernel()->setDynamicSharedMemBytes(zero);
auto kernelGraph = KernelGraph::translate(m_command, m_commandParameters);
if(Settings::getInstance()->get(Settings::LogGraphs))
Log::debug("CommandKernel::generateKernel: post translate: {}",
kernelGraph.toDOT(false, "CommandKernel::generateKernel: post translate"));
if(Settings::getInstance()->get(Settings::EnforceGraphConstraints))
{
check = kernelGraph.checkConstraints();
AssertFatal(
check.satisfied,
concatenate("CommandKernel::generateKernel: post translate:\n", check.explanation));
}
std::vector<KernelGraph::GraphTransformPtr> transforms;
bool applyScheduleMultiplyAndLDS = m_commandParameters->prefetch
&& m_commandParameters->prefetchMixMemOps
&& m_commandParameters->prefetchLDSFactor == 1;
// UpdateParameters should go before IdentifyParallelDimensions so the User.size expression
// that it sets is updated in IdentifyParallelDimensions
transforms.push_back(std::make_shared<KernelGraph::UpdateParameters>(m_commandParameters));
transforms.push_back(std::make_shared<KernelGraph::IdentifyParallelDimensions>());
transforms.push_back(std::make_shared<KernelGraph::OrderMemory>(
!m_commandParameters->allowAmbiguousMemoryNodes));
transforms.push_back(std::make_shared<KernelGraph::AddLDS>(m_commandParameters, m_context));
transforms.push_back(std::make_shared<KernelGraph::LowerLinear>(m_context));
transforms.push_back(
std::make_shared<KernelGraph::LowerTile>(m_commandParameters, m_context));
transforms.push_back(
std::make_shared<KernelGraph::LowerTensorContraction>(m_commandParameters, m_context));
transforms.push_back(std::make_shared<KernelGraph::Simplify>());
transforms.push_back(
std::make_shared<KernelGraph::AddLDSPadding>(m_context, m_commandParameters));
transforms.push_back(std::make_shared<KernelGraph::ConstantPropagation>());
transforms.push_back(std::make_shared<KernelGraph::FuseExpressions>());
if(m_commandParameters->workgroupMappingDim.has_value())
{
auto wgmArg = findArgumentByName(m_command, rocRoller::WGM);
AssertFatal(wgmArg != nullptr,
"Can not find WGM Command argument required for workgroup mapping.");
transforms.push_back(std::make_shared<KernelGraph::RemapOutputTiles>(
m_commandParameters->workgroupMappingDim,
std::make_shared<Expression::Expression>(wgmArg)));
}
if(m_commandParameters->streamK)
{
auto numWGsArg = findArgumentByName(m_command, rocRoller::NUMWGS);
AssertFatal(numWGsArg != nullptr,
"Can not find numWGs Command argument required for StreamK kernels.");
transforms.push_back(std::make_shared<KernelGraph::AddStreamK>(
m_context,
m_commandParameters,
rocRoller::XLOOP,
rocRoller::KLOOP,
std::make_shared<Expression::Expression>(numWGsArg)));
}
else if(!m_commandParameters->loopOverOutputTilesDimensions.empty())
{
transforms.push_back(std::make_shared<KernelGraph::LoopOverTileNumbers>(
m_commandParameters->loopOverOutputTilesDimensions,
m_commandParameters->loopOverOutputTilesCoordSizes,
m_commandParameters->loopOverOutputTilesIteratedTiles,
m_commandParameters->loopOverOutputTilesTopLoop,
m_context));
}
transforms.push_back(std::make_shared<KernelGraph::ConnectWorkgroups>(m_context));
transforms.push_back(std::make_shared<KernelGraph::WorkgroupRemapXCC>(
m_context, m_commandParameters->workgroupRemapXCC));
transforms.push_back(
std::make_shared<KernelGraph::UnrollLoops>(m_commandParameters, m_context));
if(m_commandParameters->fuseLoops)
{
transforms.push_back(std::make_shared<KernelGraph::FuseLoops>());
}
transforms.push_back(std::make_shared<KernelGraph::RemoveDuplicates>());
transforms.push_back(std::make_shared<KernelGraph::OrderEpilogueBlocks>());
// TODO: Investigate why Simplify cannot be called BEFORE RemoveDuplicates and OrderEpilogueBlocks
transforms.push_back(std::make_shared<KernelGraph::Simplify>());
transforms.push_back(std::make_shared<KernelGraph::CleanLoops>());
transforms.push_back(
std::make_shared<KernelGraph::SwizzleScale>(m_commandParameters, m_context));
transforms.push_back(
std::make_shared<KernelGraph::AddPrefetch>(m_commandParameters, m_context));
if(m_commandParameters->prefetch && m_commandParameters->prefetchScale)
{
transforms.push_back(
std::make_shared<KernelGraph::PrefetchScale>(m_commandParameters, m_context));
}
transforms.push_back(std::make_shared<KernelGraph::AddF6LDSPadding>(m_context));
transforms.push_back(
std::make_shared<KernelGraph::AddDirect2LDS>(m_context, m_commandParameters));
transforms.push_back(std::make_shared<KernelGraph::AddTDMToLDS>(m_context));
transforms.push_back(std::make_shared<KernelGraph::Simplify>());
transforms.push_back(std::make_shared<KernelGraph::AddPRNG>(m_context));
transforms.push_back(
std::make_shared<KernelGraph::UpdateWavefrontParameters>(m_commandParameters));
transforms.push_back(
std::make_shared<KernelGraph::AssignIndexExpressions>(m_context, m_command));
transforms.push_back(std::make_shared<KernelGraph::LoadPacked>(m_context));
transforms.push_back(std::make_shared<KernelGraph::AddConvert>(m_context));
//
// TODO: Turn on this transformation by default when SGPR issue gets resolved
//
if(m_context->kernelOptions()->removeSetCoordinate)
{
transforms.push_back(std::make_shared<KernelGraph::RemoveSetCoordinate>());
transforms.push_back(std::make_shared<KernelGraph::Simplify>());
}
transforms.push_back(std::make_shared<KernelGraph::NopExtraScopes>());
transforms.push_back(std::make_shared<KernelGraph::InlineInits>());
transforms.push_back(std::make_shared<KernelGraph::InlineIncrements>());
if(applyScheduleMultiplyAndLDS)
transforms.push_back(std::make_shared<KernelGraph::RemoveImplicitScheduling>());
transforms.push_back(std::make_shared<KernelGraph::OrderMultiplyNodes>());
transforms.push_back(std::make_shared<KernelGraph::Simplify>());
if(applyScheduleMultiplyAndLDS)
transforms.push_back(std::make_shared<KernelGraph::ScheduleMultiplyAndLDS>());
transforms.push_back(std::make_shared<KernelGraph::Simplify>());
transforms.push_back(std::make_shared<KernelGraph::OrderExchangeNodes>());
transforms.push_back(std::make_shared<KernelGraph::AliasDataFlowTags>());
transforms.push_back(std::make_shared<KernelGraph::AddLDSBarriers>());
transforms.push_back(std::make_shared<KernelGraph::AddDeallocateDataFlow>());
transforms.push_back(std::make_shared<KernelGraph::CleanArguments>(m_context, m_command));
transforms.push_back(std::make_shared<KernelGraph::AddDeallocateArguments>(m_context));
transforms.push_back(std::make_shared<KernelGraph::MergeAdjacentDeallocates>());
transforms.push_back(std::make_shared<KernelGraph::Simplify>());
transforms.push_back(std::make_shared<KernelGraph::SortArguments>(m_context));
transforms.push_back(std::make_shared<KernelGraph::SetWorkitemCount>(m_context));
transforms.push_back(std::make_shared<KernelGraph::ModelAddresses>(m_context));
for(auto const& t : transforms)
{
kernelGraph = kernelGraph.transform(t);
}
m_kernelGraph = std::make_shared<KernelGraph::KernelGraph>(kernelGraph);
}
Generator<Instruction> kernelInstructions(ContextPtr context,
CommandPtr command,
KernelGraph::KernelGraphPtr kernelGraph)
{
co_yield commandComments(command);
co_yield context->kernel()->preamble();
co_yield context->kernel()->prolog();
co_yield KernelGraph::generate(*kernelGraph, context->kernel());
co_yield context->kernel()->postamble();
co_yield context->kernel()->amdgpu_metadata();
}
void CommandKernel::generateKernelSource()
{
TIMER(t, "CommandKernel::generateKernelSource");
m_context->kernel()->setKernelGraphMeta(m_kernelGraph);
m_context->kernel()->setCommandMeta(m_command);
for(auto inst : kernelInstructions(m_context, m_command, m_kernelGraph))
m_context->schedule(inst);
}
std::vector<char> CommandKernel::assembleKernel()
{
TIMER(t, "CommandKernel::assembleKernel");
return m_context->instructions()->assemble();
}
void CommandKernel::loadKernel()
{
TIMER(t, "CommandKernel::loadKernel");
if(!m_executableKernel)
m_executableKernel = m_context->instructions()->getExecutableKernel();
}
void CommandKernel::generateKernel()
{
TIMER(t, "CommandKernel::generateKernel");
if(m_command)
{
generateKernelGraph();
generateKernelSource();
}
else
{
// Probably from a unit test. The context should contain
// scheduled instructions already.
}
}
void CommandKernel::addPredicate(Expression::ExpressionPtr expression)
{
m_predicates.push_back(expression);
}
bool CommandKernel::matchesPredicates(RuntimeArguments const& args, LogLevel level) const
{
bool retVal = true;
for(auto predicate : m_predicates)
{
try
{
if(!std::get<bool>(Expression::evaluate(predicate, args)))
{
retVal = false;
std::string comment;
if(!(comment = Expression::getComment(predicate)).empty())
{
Log::log(level, "Predicate mismatch for {}: {}", m_name, comment);
}
else
{
Log::log(level,
"Predicate {} for {} is false.",
Expression::toString(predicate),
m_name);
}
}
}
catch(std::bad_variant_access err)
{
Throw<FatalError>(
"Predicate ", Expression::toString(predicate), " does not evaluate to a bool");
}
}
return retVal;
}
void CommandKernel::setCommandParameters(CommandParametersPtr commandParams)
{
m_commandParameters = commandParams;
}
CommandParametersPtr CommandKernel::getCommandParameters() const
{
return m_commandParameters;
}
//
// 2024-11-05: This is only used in a few tests. Please see the
// note in Command::createWorkItemCount.
//
void CommandKernel::setLaunchParameters(CommandLaunchParametersPtr launch)
{
m_launchParameters = launch;
}
void CommandKernel::launchKernel(RuntimeArguments const& args,
std::shared_ptr<HIPTimer> timer,
int iteration)
{
launchKernel(args, timer, iteration, timer ? timer->stream() : 0);
}
void CommandKernel::launchKernel(RuntimeArguments const& args, hipStream_t stream)
{
launchKernel(args, nullptr, 0, stream);
}
void CommandKernel::launchKernel(RuntimeArguments const& args,
std::shared_ptr<HIPTimer> timer,
int iteration,
hipStream_t stream)
{
TIMER(t, "CommandKernel::launchKernel");
AssertFatal(m_context, "Unable to launch kernel: CommandKernel must have a Context.");
AssertFatal(m_context->kernel(),
"Unable to launch kernel: Context must have an AssemblyKernel.");
AssertFatal(matchesPredicates(args, LogLevel::Error),
"Unable to launch kernel: all CommandKernel predicates must match.");
if(m_launchParameters)
{
if(m_launchParameters->getManualWorkitemCount())
m_context->kernel()->setWorkitemCount(
*m_launchParameters->getManualWorkitemCount());
}
auto kargs = getKernelArguments(args);
auto inv = getKernelInvocation(args);
loadKernel();
if(timer)
m_executableKernel->executeKernel(kargs, inv, timer, iteration);
else
m_executableKernel->executeKernel(kargs, inv, stream);
}
void CommandKernel::loadKernelFromAssembly(const std::string& fileName,
const std::string& kernelName)
{
AssertFatal(m_context);
AssertFatal(m_context->kernel());
m_executableKernel
= std::make_shared<ExecutableKernel>(m_context->targetArchitecture().target());
m_executableKernel->loadKernelFromFile(
fileName, kernelName, m_context->targetArchitecture().target());
}
AssemblyKernelPtr CommandKernel::loadKernelFromCodeObject(const std::string& fileName,
const std::string& kernelName)
{
AssertFatal(m_context);
m_executableKernel
= std::make_shared<ExecutableKernel>(m_context->targetArchitecture().target());
m_executableKernel->loadKernelFromCodeObjectFile(
fileName, kernelName, m_context->targetArchitecture().target());
// XXX Instead of adding `setKernel`, should the context load from a code object?
auto kernels = AssemblyKernels::fromELF(fileName).kernels;
auto kernel = kernels.at(0);
auto kernelPtr = std::make_shared<AssemblyKernel>(kernel);
m_context->setKernel(kernelPtr);
return kernelPtr;
}
ContextPtr CommandKernel::getContext()
{
return m_context;
}
size_t CommandKernel::scratchSpaceRequired(Operations::ScratchPolicy policy,
RuntimeArguments const& args) const
{
auto amount = m_context->getScratchAmount(policy);
auto times = evaluationTimes(amount);
AssertFatal(times[Expression::EvaluationTime::Translate]
|| times[Expression::EvaluationTime::KernelLaunch],
"Unable to evaluate the scratch space required",
ShowValue(toString(amount)));
return getUnsignedInt(evaluate(amount, args));
}
std::array<unsigned int, 3> const& CommandKernel::getWorkgroupSize() const
{
return m_context->kernel()->workgroupSize();
}
}