From 5efb3f26c047ebd1804a6616142b8f456181ec44 Mon Sep 17 00:00:00 2001 From: German Andryeyev Date: Fri, 3 Apr 2020 12:13:12 -0400 Subject: [PATCH] SWDEV-184709 - support hipLaunchCooperativeKernel() - Add validation checks for cooperative launch to pass Cuda test Change-Id: Ie296f0c3f113909d9a357879db3b2a833ab314c5 --- hipamd/vdi/hip_module.cpp | 21 +++++- hipamd/vdi/hip_platform.cpp | 130 ++++++++++++++++++++++-------------- hipamd/vdi/hip_platform.hpp | 29 ++++++++ 3 files changed, 128 insertions(+), 52 deletions(-) create mode 100644 hipamd/vdi/hip_platform.hpp diff --git a/hipamd/vdi/hip_module.cpp b/hipamd/vdi/hip_module.cpp index a7822b315e..75639b39f4 100755 --- a/hipamd/vdi/hip_module.cpp +++ b/hipamd/vdi/hip_module.cpp @@ -25,6 +25,7 @@ #include "hip_internal.hpp" #include "platform/program.hpp" #include "hip_event.hpp" +#include "hip_platform.hpp" hipError_t ihipModuleLoadData(hipModule_t *module, const void *image); @@ -294,9 +295,23 @@ hipError_t ihipModuleLaunchKernel(hipFunction_t f, amd::HostQueue* queue = hip::getQueue(hStream); const amd::Device& device = queue->vdev()->device(); - if ((params & amd::NDRangeKernelCommand::CooperativeGroups) && - !device.info().cooperativeGroups_) { - return hipErrorLaunchFailure; + // Make sure dispatch doesn't exceed max workgroup size limit + if (blockDimX * blockDimY * blockDimZ > device.info().maxWorkGroupSize_) { + return hipErrorInvalidConfiguration; + } + + if (params & amd::NDRangeKernelCommand::CooperativeGroups) { + if (!device.info().cooperativeGroups_) { + return hipErrorLaunchFailure; + } + int num_blocks = 0; + int num_grids = 0; + int block_size = blockDimX * blockDimY * blockDimZ; + hip_impl::ihipOccupancyMaxActiveBlocksPerMultiprocessor( + &num_blocks, &num_grids, device, f, block_size, sharedMemBytes, true); + if (((gridDimX * gridDimY * gridDimZ) / block_size) > num_grids) { + return hipErrorCooperativeLaunchTooLarge; + } } if ((params & amd::NDRangeKernelCommand::CooperativeMultiDeviceGroups) && !device.info().cooperativeMultiDeviceGroups_) { diff --git a/hipamd/vdi/hip_platform.cpp b/hipamd/vdi/hip_platform.cpp index 9c18476e38..b3998d4e95 100755 --- a/hipamd/vdi/hip_platform.cpp +++ b/hipamd/vdi/hip_platform.cpp @@ -704,7 +704,7 @@ hipError_t ihipCreateGlobalVarObj(const char* name, hipModule_t hmod, amd::Memor HIP_RETURN(hipErrorInvalidDeviceFunction); } /* Find the global Symbols */ - if(!dev_program->createGlobalVarObj(amd_mem_obj, dptr, bytes, name)) { + if (!dev_program->createGlobalVarObj(amd_mem_obj, dptr, bytes, name)) { HIP_RETURN(hipErrorInvalidSymbol); } @@ -713,52 +713,46 @@ hipError_t ihipCreateGlobalVarObj(const char* name, hipModule_t hmod, amd::Memor namespace hip_impl { -hipError_t ihipOccupancyMaxActiveBlocksPerMultiprocessor(int* numBlocks, int* numGrids, - hipFunction_t f, int blockSize, - size_t dynamicSMemSize, bool bCalcPotentialBlkSz) +hipError_t ihipOccupancyMaxActiveBlocksPerMultiprocessor( + int* numBlocks, int* numGrids, + const amd::Device& device, hipFunction_t func, int blockSize, + size_t dynamicSMemSize, bool bCalcPotentialBlkSz) { - HIP_INIT_API(NONE, f, blockSize, dynamicSMemSize, bCalcPotentialBlkSz); - if(numBlocks == nullptr){HIP_RETURN(hipErrorInvalidValue);} - int deviceId = ihipGetDevice(); - // FIXME: Function may not be a device function and may have been obtaiend via - // hipModuleGetFunction and thus not in the functions_ map. Check the map - // else interpret as a hip::Function for now. - hipFunction_t func = PlatformState::instance().getFunc(f, deviceId); - if (func == nullptr) { - func = f; - } hip::Function* function = hip::Function::asFunction(func); - if (function == nullptr) { - HIP_RETURN(hipErrorInvalidDeviceFunction); - } - amd::Kernel* kernel = function->function_; - if (!kernel) { - HIP_RETURN(hipErrorOutOfMemory); - } - amd::Device* device = hip::getCurrentDevice()->devices()[0]; - const device::Kernel::WorkGroupInfo* wrkGrpInfo = kernel->getDeviceKernel(*device)->workGroupInfo(); + const amd::Kernel& kernel = *function->function_; + + const device::Kernel::WorkGroupInfo* wrkGrpInfo = kernel.getDeviceKernel(device)->workGroupInfo(); if (blockSize == 0) { if (bCalcPotentialBlkSz == false){ - HIP_RETURN(hipErrorInvalidValue); + return hipErrorInvalidValue; } else { - blockSize = device->info().maxWorkGroupSize_; // maxwavefrontperblock + blockSize = device.info().maxWorkGroupSize_; // maxwavefrontperblock } } + + // Make sure the requested block size is smaller than max supported + if (blockSize > device.info().maxWorkGroupSize_) { + numBlocks = 0; + numGrids = 0; + return hipSuccess; + } + // Find threads accupancy per CU => simd_per_cu * GPR usage constexpr size_t MaxWavesPerSimd = 8; // Limited by SPI 32 per CU, hence 8 per SIMD size_t VgprWaves = MaxWavesPerSimd; if (wrkGrpInfo->usedVGPRs_ > 0) { VgprWaves = wrkGrpInfo->availableVGPRs_ / amd::alignUp(wrkGrpInfo->usedVGPRs_, 4); } + size_t GprWaves = VgprWaves; if (wrkGrpInfo->usedSGPRs_ > 0) { - const size_t maxSGPRs = (device->info().gfxipVersion_ < 800) ? 512 : 800; + const size_t maxSGPRs = (device.info().gfxipVersion_ < 800) ? 512 : 800; size_t SgprWaves = maxSGPRs / amd::alignUp(wrkGrpInfo->usedSGPRs_, 16); GprWaves = std::min(VgprWaves, SgprWaves); } - size_t alu_accupancy = device->info().simdPerCU_ * std::min(MaxWavesPerSimd, GprWaves); + size_t alu_accupancy = device.info().simdPerCU_ * std::min(MaxWavesPerSimd, GprWaves); alu_accupancy *= wrkGrpInfo->wavefrontSize_; // Calculate blocks occupancy per CU *numBlocks = alu_accupancy / amd::alignUp(blockSize, wrkGrpInfo->wavefrontSize_); @@ -766,17 +760,15 @@ hipError_t ihipOccupancyMaxActiveBlocksPerMultiprocessor(int* numBlocks, int* nu size_t total_used_lds = wrkGrpInfo->usedLDSSize_ + dynamicSMemSize; if (total_used_lds != 0) { // Calculate LDS occupancy per CU. lds_per_cu / (static_lsd + dynamic_lds) - int lds_occupancy = static_cast(device->info().localMemSize_ / total_used_lds); + int lds_occupancy = static_cast(device.info().localMemSize_ / total_used_lds); *numBlocks = std::min(*numBlocks, lds_occupancy); } - if (bCalcPotentialBlkSz){ - if (numGrids == nullptr){ - HIP_RETURN(hipErrorInvalidValue); - } - *numGrids = *numBlocks * device->info().numRTCUs_; + + if (bCalcPotentialBlkSz) { + *numGrids = *numBlocks * device.info().numRTCUs_; } - HIP_RETURN(hipSuccess); + return hipSuccess; } } @@ -786,14 +778,28 @@ hipError_t hipOccupancyMaxPotentialBlockSize(uint32_t* gridSize, uint32_t* block hipFunction_t f, size_t dynSharedMemPerBlk, uint32_t blockSizeLimit) { - int numGrids = 0; - int numBlocks = 0; - hipError_t Ret = hip_impl::ihipOccupancyMaxActiveBlocksPerMultiprocessor(&numBlocks, &numGrids, f, 0, dynSharedMemPerBlk,true); - if (Ret == hipSuccess){ - *blockSize = numBlocks; - *gridSize = numGrids; + HIP_INIT_API(hipOccupancyMaxPotentialBlockSize, f, dynSharedMemPerBlk, blockSizeLimit); + + if ((gridSize == nullptr) || (blockSize == nullptr)) { + return HIP_RETURN(hipErrorInvalidValue); } - HIP_RETURN(Ret); + + hipFunction_t func = PlatformState::instance().getFunc(f, ihipGetDevice()); + if (func == nullptr) { + func = f; + } + + const amd::Device& device = *hip::getCurrentDevice()->devices()[0]; + + int num_grids = 0; + int num_blocks = 0; + hipError_t ret = hip_impl::ihipOccupancyMaxActiveBlocksPerMultiprocessor( + &num_blocks, &num_grids, device, func, 0, dynSharedMemPerBlk,true); + if (ret == hipSuccess) { + *blockSize = num_blocks; + *gridSize = num_grids; + } + HIP_RETURN(ret); } // FIXME: Need to replace `uint32_t` with `int` finally. @@ -802,10 +808,23 @@ hipError_t hipOccupancyMaxActiveBlocksPerMultiprocessor(uint32_t* numBlocks, uint32_t blockSize, size_t dynamicSMemSize) { - int NB; - hipError_t Ret = hip_impl::ihipOccupancyMaxActiveBlocksPerMultiprocessor(&NB, nullptr, f, blockSize, dynamicSMemSize, false); - *numBlocks = NB; - HIP_RETURN(Ret); + HIP_INIT_API(hipOccupancyMaxActiveBlocksPerMultiprocessor, f, blockSize, dynamicSMemSize); + if (numBlocks == nullptr) { + return HIP_RETURN(hipErrorInvalidValue); + } + + hipFunction_t func = PlatformState::instance().getFunc(f, ihipGetDevice()); + if (func == nullptr) { + func = f; + } + + const amd::Device& device = *hip::getCurrentDevice()->devices()[0]; + + int num_blocks = 0; + hipError_t ret = hip_impl::ihipOccupancyMaxActiveBlocksPerMultiprocessor( + &num_blocks, nullptr, device, func, blockSize, dynamicSMemSize, false); + *numBlocks = num_blocks; + HIP_RETURN(ret); } // FIXME: Need to replace `uint32_t` with `int` finally. @@ -815,10 +834,23 @@ hipError_t hipOccupancyMaxActiveBlocksPerMultiprocessorWithFlags(uint32_t* numBl size_t dynamicSMemSize, unsigned int flags) { - int NB; - hipError_t Ret = hip_impl::ihipOccupancyMaxActiveBlocksPerMultiprocessor(&NB, nullptr, f, blockSize, dynamicSMemSize, false); - *numBlocks = NB; - HIP_RETURN(Ret); + HIP_INIT_API(hipOccupancyMaxActiveBlocksPerMultiprocessorWithFlags, f, blockSize, dynamicSMemSize, flags); + if (numBlocks == nullptr) { + return HIP_RETURN(hipErrorInvalidValue); + } + + hipFunction_t func = PlatformState::instance().getFunc(f, ihipGetDevice()); + if (func == nullptr) { + func = f; + } + + const amd::Device& device = *hip::getCurrentDevice()->devices()[0]; + + int num_blocks = 0; + hipError_t ret = hip_impl::ihipOccupancyMaxActiveBlocksPerMultiprocessor( + &num_blocks, nullptr, device, func, blockSize, dynamicSMemSize, false); + *numBlocks = num_blocks; + HIP_RETURN(ret); } } diff --git a/hipamd/vdi/hip_platform.hpp b/hipamd/vdi/hip_platform.hpp new file mode 100644 index 0000000000..8e5eaa191f --- /dev/null +++ b/hipamd/vdi/hip_platform.hpp @@ -0,0 +1,29 @@ +/* Copyright (c) 2015-present Advanced Micro Devices, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. */ +#pragma once + +#include "device/device.hpp" + +namespace hip_impl { +hipError_t ihipOccupancyMaxActiveBlocksPerMultiprocessor( + int* numBlocks, int* numGrids, + const amd::Device& device, hipFunction_t func, int blockSize, + size_t dynamicSMemSize, bool bCalcPotentialBlkSz); +} \ No newline at end of file