Files
TheRock/rocm-libraries/shared/rocroller/lib/source/ExecutableKernel.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

270 lines
12 KiB
C++

// Copyright Advanced Micro Devices, Inc., or its affiliates.
// SPDX-License-Identifier: MIT
#include <vector>
#ifdef ROCROLLER_USE_HIP
#include <hip/hip_ext.h>
#include <hip/hip_runtime.h>
#endif /* ROCROLLER_USE_HIP */
#include <rocRoller/Utilities/Error.hpp>
#include <rocRoller/Utilities/Settings.hpp>
#include <rocRoller/Assemblers/Assembler.hpp>
#include <rocRoller/Context.hpp>
#include <rocRoller/ExecutableKernel.hpp>
#include <rocRoller/Utilities/HipUtils.hpp>
#include <rocRoller/WorkgroupClusters_detail.hpp>
namespace rocRoller
{
// Values using HIP datatypes are stored in hip_data
// to avoid including HIP headers within ExecutableKernel.hpp
struct ExecutableKernel::HIPData
{
hipModule_t hipModule;
hipFunction_t function;
~HIPData()
{
if(hipModule)
{
hipError_t error = hipModuleUnload(hipModule);
if(error != hipSuccess)
{
std::ostringstream msg;
msg << "HIP failure at hipModuleUnload (~HIPData()): "
<< hipGetErrorString(error) << std::endl;
Log::error(msg.str());
}
}
}
};
ExecutableKernel::ExecutableKernel(GPUArchitectureTarget target)
: m_kernelLoaded(false)
, m_hipData(std::make_shared<HIPData>())
, m_target(target)
{
}
hipFunction_t ExecutableKernel::getHipFunction() const
{
return m_hipData->function;
}
void ExecutableKernel::loadKernel(std::string const& instructions,
const GPUArchitectureTarget& target,
std::string const& kernelName)
{
auto assembler = Assembler::Get();
std::vector<char> kernelObject
= assembler->assembleMachineCode(instructions, target, kernelName);
if(instructions.size())
{
HIP_CHECK(hipModuleLoadData(&(m_hipData->hipModule), kernelObject.data()));
HIP_CHECK(hipModuleGetFunction(
&(m_hipData->function), m_hipData->hipModule, kernelName.c_str()));
m_kernelLoaded = true;
m_kernelName = kernelName;
}
}
void ExecutableKernel::loadKernelFromFile(std::string const& fileName,
std::string const& kernelName,
const GPUArchitectureTarget& target)
{
std::string machineCode;
std::ifstream assemblyFile(fileName, std::ios::in | std::ios::binary);
if(assemblyFile)
{
machineCode.assign(std::istreambuf_iterator<char>(assemblyFile),
std::istreambuf_iterator<char>());
Log::debug("Alernate kernel read from: {}", fileName);
}
else
{
Log::debug("Error reading alternate kernel from: {}", fileName);
}
AssertFatal(assemblyFile, "Error reading alternate kernel.", ShowValue(fileName));
loadKernel(machineCode, target, kernelName);
}
void ExecutableKernel::loadKernelFromCodeObjectFile(std::string const& fileName,
std::string const& kernelName,
const GPUArchitectureTarget& target)
{
Log::debug("ExecutableKernel::loadKernelFromCodeObjectFile: fileName {} kernelName {}",
fileName,
kernelName);
auto kernelObject = readFile(fileName);
HIP_CHECK(hipModuleLoadData(&(m_hipData->hipModule), kernelObject.data()));
HIP_CHECK(
hipModuleGetFunction(&(m_hipData->function), m_hipData->hipModule, kernelName.c_str()),
ShowValue(kernelName));
m_kernelLoaded = true;
m_kernelName = kernelName;
}
void ExecutableKernel::executeKernel(const KernelArguments& args,
const KernelInvocation& invocation,
std::shared_ptr<HIPTimer> timer,
int iteration)
{
executeKernel(args, invocation, timer, iteration, timer->stream());
}
void ExecutableKernel::executeKernel(const KernelArguments& args,
const KernelInvocation& invocation,
hipStream_t stream)
{
executeKernel(args, invocation, nullptr, 0, stream);
}
void ExecutableKernel::executeKernel(const KernelArguments& args,
const KernelInvocation& invocation,
std::shared_ptr<HIPTimer> timer,
int iteration,
hipStream_t stream)
{
// TODO: implement formatter for container and library types
Log::debug(fmt::format("Launching kernel {}: Workgroup: [{}, {}, {}], Workitems: [{}, {}, "
"{}]\nKernel arguments: {}\n",
m_kernelName,
invocation.workgroupSize[0],
invocation.workgroupSize[1],
invocation.workgroupSize[2],
invocation.workitemCount[0],
invocation.workitemCount[1],
invocation.workitemCount[2],
args.toString()));
if(!kernelLoaded())
throw std::runtime_error("Attempting to execute a kernel before it is loaded");
size_t argsSize = args.size();
void* hipLaunchParams[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER,
const_cast<void*>(args.data()),
HIP_LAUNCH_PARAM_BUFFER_SIZE,
&argsSize,
HIP_LAUNCH_PARAM_END};
int idx = -1, currDeviceAsicRevisionId = -1;
HIP_CHECK(hipGetDevice(&idx));
HIP_CHECK(
hipDeviceGetAttribute(&currDeviceAsicRevisionId, hipDeviceAttributeAsicRevision, idx));
if(m_target.gfx == GPUArchitectureGFX::GFX1250)
{
if(currDeviceAsicRevisionId == 2)
{
int newRevId = Settings::Get(Settings::GFX1250AsicRevisionId);
Log::warn("Overriding current device asic revision id from {} to {}",
currDeviceAsicRevisionId,
newRevId);
currDeviceAsicRevisionId = newRevId;
}
AssertFatal(m_target.asicRevisionId == currDeviceAsicRevisionId,
"The kernel and current device must have the same target revision id.",
ShowValue(m_target.asicRevisionId),
ShowValue(currDeviceAsicRevisionId));
}
if(timer)
HIP_TIC(timer, iteration);
if(invocation.workgroupClusterSize)
{
#ifdef ROCROLLER_HAS_HIP_WORKGROUP_CLUSTERS
auto const workgroupClusterSize = *invocation.workgroupClusterSize;
auto const numWorkgroupsX = invocation.workitemCount[0] / invocation.workgroupSize[0];
auto const numWorkgroupsY = invocation.workitemCount[1] / invocation.workgroupSize[1];
auto const numWorkgroupsZ = invocation.workitemCount[2] / invocation.workgroupSize[2];
// TODO Can/should we validate earlier? (i.e. not immediately before launch)
AssertFatal(WorkgroupClustersDetail::IsValidWorkgroupClusterSize(
workgroupClusterSize, {numWorkgroupsX, numWorkgroupsY, numWorkgroupsZ}),
fmt::format("Invalid cluster size: [{},{},{}].\n"
"The number of workgroups [{},{},{}] in each dimension must "
"be divisible by the cluster size in that dimension.\n"
"Valid cluster sizes:{}",
workgroupClusterSize[0],
workgroupClusterSize[1],
workgroupClusterSize[2],
numWorkgroupsX,
numWorkgroupsY,
numWorkgroupsZ,
[=]() {
std::string s;
auto const valid
= WorkgroupClustersDetail::ValidWorkgroupClusterSizes(
{numWorkgroupsX, numWorkgroupsY, numWorkgroupsZ});
for(const auto& v : valid)
s += fmt::format(" [{},{},{}]", v[0], v[1], v[2]);
return s;
}()));
hipLaunchAttribute attribute[1];
HIP_LAUNCH_CONFIG config = {0};
config.gridDimX = numWorkgroupsX;
config.gridDimY = numWorkgroupsY;
config.gridDimZ = numWorkgroupsZ;
config.blockDimX = invocation.workgroupSize[0];
config.blockDimY = invocation.workgroupSize[1];
config.blockDimZ = invocation.workgroupSize[2];
attribute[0].id = hipLaunchAttributeClusterDimension;
attribute[0].val.clusterDim.x = workgroupClusterSize[0];
attribute[0].val.clusterDim.y = workgroupClusterSize[1];
attribute[0].val.clusterDim.z = workgroupClusterSize[2];
config.attrs = attribute;
config.numAttrs = 1;
config.sharedMemBytes = invocation.sharedMemBytes;
Log::debug("Launching kernel {} with Clusters: [{}, {}, {}]",
m_kernelName,
workgroupClusterSize[0],
workgroupClusterSize[1],
workgroupClusterSize[2]);
const HIP_LAUNCH_CONFIG* pConfig = &config;
HIP_CHECK(hipDrvLaunchKernelEx(
pConfig, m_hipData->function, nullptr, (void**)&hipLaunchParams));
#else
Throw<FatalError>(
"Workgroup cluster launch requested but the installed ROCm/HIP version does not "
"support hipLaunchAttributeClusterDimension. "
"Please upgrade to a ROCm version that includes workgroup cluster support.");
#endif /* ROCROLLER_HAS_HIP_WORKGROUP_CLUSTERS */
}
else
{
HIP_CHECK(hipExtModuleLaunchKernel(m_hipData->function,
invocation.workitemCount[0],
invocation.workitemCount[1],
invocation.workitemCount[2],
invocation.workgroupSize[0],
invocation.workgroupSize[1],
invocation.workgroupSize[2],
invocation.sharedMemBytes,
stream,
nullptr,
(void**)&hipLaunchParams,
nullptr, // event
nullptr // event
));
}
if(timer)
HIP_TOC(timer, iteration);
}
}