SWDEV-184709 - support hipLaunchCooperativeKernel()

- Add validation checks for cooperative launch to pass Cuda test

Change-Id: Ie296f0c3f113909d9a357879db3b2a833ab314c5
This commit is contained in:
German Andryeyev
2020-04-03 12:13:12 -04:00
orang tua 16ac35c4d5
melakukan 5efb3f26c0
3 mengubah file dengan 128 tambahan dan 52 penghapusan
+18 -3
Melihat File
@@ -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_) {
+81 -49
Melihat File
@@ -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<int>(device->info().localMemSize_ / total_used_lds);
int lds_occupancy = static_cast<int>(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);
}
}
+29
Melihat File
@@ -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);
}