SWDEV-325938 - Add missing queries for occupancy (#2995)

New C++ interfaces:
hipOccupancyMaxPotentialBlockSizeVariableSMem() and
hipOccupancyMaxPotentialBlockSizeVariableSMemWithFlags()

Change-Id: Ifae9d6b94b159e59cbf616f180028abb18a96527


[ROCm/hip commit: 6d4c13adc2]
Этот коммит содержится в:
ROCm CI Service Account
2022-10-14 10:08:03 +05:30
коммит произвёл GitHub
родитель bc393c41c7
Коммит 410d2fcd45
+142
Просмотреть файл
@@ -6775,6 +6775,148 @@ inline hipError_t hipOccupancyMaxActiveBlocksPerMultiprocessorWithFlags(
return hipOccupancyMaxActiveBlocksPerMultiprocessorWithFlags(
numBlocks, reinterpret_cast<const void*>(f), blockSize, dynSharedMemPerBlk, flags);
}
/**
* @brief Returns grid and block size that achieves maximum potential occupancy for a device function
*
* Returns in \p *min_grid_size and \p *block_size a suggested grid /
* block size pair that achieves the best potential occupancy
* (i.e. the maximum number of active warps on the current device with the smallest number
* of blocks for a particular function).
*
* @param [out] min_grid_size minimum grid size needed to achieve the best potential occupancy
* @param [out] block_size block size required for the best potential occupancy
* @param [in] func device function symbol
* @param [in] block_size_to_dynamic_smem_size - a unary function/functor that takes block size,
* and returns the size, in bytes, of dynamic shared memory needed for a block
* @param [in] block_size_limit the maximum block size \p func is designed to work with. 0 means no limit.
* @param [in] flags reserved
*
* @return #hipSuccess, #hipErrorInvalidDevice, #hipErrorInvalidDeviceFunction, #hipErrorInvalidValue,
* #hipErrorUnknown
*/
template<typename UnaryFunction, class T>
static hipError_t __host__ inline hipOccupancyMaxPotentialBlockSizeVariableSMemWithFlags(
int* min_grid_size,
int* block_size,
T func,
UnaryFunction block_size_to_dynamic_smem_size,
int block_size_limit = 0,
unsigned int flags = 0) {
if (min_grid_size == nullptr || block_size == nullptr ||
reinterpret_cast<const void*>(func) == nullptr) {
return hipErrorInvalidValue;
}
int dev;
hipError_t status;
if ((status = hipGetDevice(&dev)) != hipSuccess) {
return status;
}
int max_threads_per_cu;
if ((status = hipDeviceGetAttribute(&max_threads_per_cu,
hipDeviceAttributeMaxThreadsPerMultiProcessor, dev)) != hipSuccess) {
return status;
}
int warp_size;
if ((status = hipDeviceGetAttribute(&warp_size,
hipDeviceAttributeWarpSize, dev)) != hipSuccess) {
return status;
}
int max_cu_count;
if ((status = hipDeviceGetAttribute(&max_cu_count,
hipDeviceAttributeMultiprocessorCount, dev)) != hipSuccess) {
return status;
}
struct hipFuncAttributes attr;
if ((status = hipFuncGetAttributes(&attr, reinterpret_cast<const void*>(func))) != hipSuccess) {
return status;
}
// Initial limits for the execution
const int func_max_threads_per_block = attr.maxThreadsPerBlock;
if (block_size_limit == 0) {
block_size_limit = func_max_threads_per_block;
}
if (func_max_threads_per_block < block_size_limit) {
block_size_limit = func_max_threads_per_block;
}
const int block_size_limit_aligned =
((block_size_limit + (warp_size - 1)) / warp_size) * warp_size;
// For maximum search
int max_threads = 0;
int max_block_size{};
int max_num_blocks{};
for (int block_size_check_aligned = block_size_limit_aligned;
block_size_check_aligned > 0;
block_size_check_aligned -= warp_size) {
// Make sure the logic uses the requested limit and not aligned
int block_size_check = (block_size_limit < block_size_check_aligned) ?
block_size_limit : block_size_check_aligned;
size_t dyn_smem_size = block_size_to_dynamic_smem_size(block_size_check);
int optimal_blocks;
if ((status = hipOccupancyMaxActiveBlocksPerMultiprocessorWithFlags(
&optimal_blocks, func, block_size_check, dyn_smem_size, flags)) != hipSuccess) {
return status;
}
int total_threads = block_size_check * optimal_blocks;
if (total_threads > max_threads) {
max_block_size = block_size_check;
max_num_blocks = optimal_blocks;
max_threads = total_threads;
}
// Break if the logic reached possible maximum
if (max_threads_per_cu == max_threads) {
break;
}
}
// Grid size is the number of blocks per CU * CU count
*min_grid_size = max_num_blocks * max_cu_count;
*block_size = max_block_size;
return status;
}
/**
* @brief Returns grid and block size that achieves maximum potential occupancy for a device function
*
* Returns in \p *min_grid_size and \p *block_size a suggested grid /
* block size pair that achieves the best potential occupancy
* (i.e. the maximum number of active warps on the current device with the smallest number
* of blocks for a particular function).
*
* @param [out] min_grid_size minimum grid size needed to achieve the best potential occupancy
* @param [out] block_size block size required for the best potential occupancy
* @param [in] func device function symbol
* @param [in] block_size_to_dynamic_smem_size - a unary function/functor that takes block size,
* and returns the size, in bytes, of dynamic shared memory needed for a block
* @param [in] block_size_limit the maximum block size \p func is designed to work with. 0 means no limit.
*
* @return #hipSuccess, #hipErrorInvalidDevice, #hipErrorInvalidDeviceFunction, #hipErrorInvalidValue,
* #hipErrorUnknown
*/
template<typename UnaryFunction, class T>
static hipError_t __host__ inline hipOccupancyMaxPotentialBlockSizeVariableSMem(
int* min_grid_size,
int* block_size,
T func,
UnaryFunction block_size_to_dynamic_smem_size,
int block_size_limit = 0)
{
return hipOccupancyMaxPotentialBlockSizeVariableSMemWithFlags(min_grid_size, block_size, func,
block_size_to_dynamic_smem_size, block_size_limit);
}
template <typename F>
inline hipError_t hipOccupancyMaxPotentialBlockSize(int* gridSize, int* blockSize,
F kernel, size_t dynSharedMemPerBlk, uint32_t blockSizeLimit) {