Yukarıdaki cevaplar, blok boyutunun performansı nasıl etkileyebileceğine işaret ediyor ve doluluk maksimizasyonuna dayalı seçimi için ortak bir buluşsal yöntem öneriyor. Sağlamak isteyen olmadan blok boyutunu seçmek için kriterini, bunu görmek, (şimdi Release Candidate sürümünde) CUDA 6.5 doluluk hesaplamalar ve fırlatma yapılandırmasında yardımına birçok yeni çalışma zamanı işlevleri içerir söz değerinde olacaktır
CUDA Pro İpucu: Occupancy API, Başlatma Yapılandırmasını Basitleştirir
Yararlı işlevlerden biri cudaOccupancyMaxPotentialBlockSize
, maksimum doluluk oranına ulaşan bir blok boyutunu sezgisel olarak hesaplamaktır. Bu işlev tarafından sağlanan değerler daha sonra başlatma parametrelerinin manuel optimizasyonunun başlangıç noktası olarak kullanılabilir. Aşağıda küçük bir örnek var.
#include <stdio.h>
/************************/
/* TEST KERNEL FUNCTION */
/************************/
__global__ void MyKernel(int *a, int *b, int *c, int N)
{
int idx = threadIdx.x + blockIdx.x * blockDim.x;
if (idx < N) { c[idx] = a[idx] + b[idx]; }
}
/********/
/* MAIN */
/********/
void main()
{
const int N = 1000000;
int blockSize; // The launch configurator returned block size
int minGridSize; // The minimum grid size needed to achieve the maximum occupancy for a full device launch
int gridSize; // The actual grid size needed, based on input size
int* h_vec1 = (int*) malloc(N*sizeof(int));
int* h_vec2 = (int*) malloc(N*sizeof(int));
int* h_vec3 = (int*) malloc(N*sizeof(int));
int* h_vec4 = (int*) malloc(N*sizeof(int));
int* d_vec1; cudaMalloc((void**)&d_vec1, N*sizeof(int));
int* d_vec2; cudaMalloc((void**)&d_vec2, N*sizeof(int));
int* d_vec3; cudaMalloc((void**)&d_vec3, N*sizeof(int));
for (int i=0; i<N; i++) {
h_vec1[i] = 10;
h_vec2[i] = 20;
h_vec4[i] = h_vec1[i] + h_vec2[i];
}
cudaMemcpy(d_vec1, h_vec1, N*sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(d_vec2, h_vec2, N*sizeof(int), cudaMemcpyHostToDevice);
float time;
cudaEvent_t start, stop;
cudaEventCreate(&start);
cudaEventCreate(&stop);
cudaEventRecord(start, 0);
cudaOccupancyMaxPotentialBlockSize(&minGridSize, &blockSize, MyKernel, 0, N);
// Round up according to array size
gridSize = (N + blockSize - 1) / blockSize;
cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&time, start, stop);
printf("Occupancy calculator elapsed time: %3.3f ms \n", time);
cudaEventRecord(start, 0);
MyKernel<<<gridSize, blockSize>>>(d_vec1, d_vec2, d_vec3, N);
cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&time, start, stop);
printf("Kernel elapsed time: %3.3f ms \n", time);
printf("Blocksize %i\n", blockSize);
cudaMemcpy(h_vec3, d_vec3, N*sizeof(int), cudaMemcpyDeviceToHost);
for (int i=0; i<N; i++) {
if (h_vec3[i] != h_vec4[i]) { printf("Error at i = %i! Host = %i; Device = %i\n", i, h_vec4[i], h_vec3[i]); return; };
}
printf("Test passed\n");
}
DÜZENLE
cudaOccupancyMaxPotentialBlockSize
Tanımlanan cuda_runtime.h
aşağıdaki gibi dosya ve tanımlanır:
template<class T>
__inline__ __host__ CUDART_DEVICE cudaError_t cudaOccupancyMaxPotentialBlockSize(
int *minGridSize,
int *blockSize,
T func,
size_t dynamicSMemSize = 0,
int blockSizeLimit = 0)
{
return cudaOccupancyMaxPotentialBlockSizeVariableSMem(minGridSize, blockSize, func, __cudaOccupancyB2DHelper(dynamicSMemSize), blockSizeLimit);
}
Parametrelerin anlamları aşağıdaki gibidir
minGridSize = Suggested min grid size to achieve a full machine launch.
blockSize = Suggested block size to achieve maximum occupancy.
func = Kernel function.
dynamicSMemSize = Size of dynamically allocated shared memory. Of course, it is known at runtime before any kernel launch. The size of the statically allocated shared memory is not needed as it is inferred by the properties of func.
blockSizeLimit = Maximum size for each block. In the case of 1D kernels, it can coincide with the number of input elements.
CUDA 6.5'ten itibaren, API tarafından önerilen 1D blok boyutundan birinin kendi 2D / 3D blok boyutlarını hesaplaması gerektiğine dikkat edin.
Ayrıca CUDA sürücü API'sinin doluluk hesaplaması için işlevsel olarak eşdeğer API'ler içerdiğine dikkat edin, bu nedenle cuOccupancyMaxPotentialBlockSize
sürücü API kodunda yukarıdaki örnekte çalışma zamanı API'si için gösterilen şekilde kullanılması mümkündür .