Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ CUDA中不同块和线程的性能优化_C++_C_Cuda - Fatal编程技术网

C++ CUDA中不同块和线程的性能优化

C++ CUDA中不同块和线程的性能优化,c++,c,cuda,C++,C,Cuda,我编写了一个程序来计算直方图,其中每个字符字节的256个值都被计算: #include "cuda_runtime.h" #include "device_launch_parameters.h" #include "..\..\common\book.h" #include <stdio.h> #include <cuda.h> #include <conio.h> #define SIZE (100*1024*1024) __global__ voi

我编写了一个程序来计算直方图,其中每个字符字节的256个值都被计算:

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include "..\..\common\book.h"
#include <stdio.h> 
#include <cuda.h>
#include <conio.h>

#define SIZE (100*1024*1024)

__global__ void histo_kernel(unsigned char *buffer, long size, unsigned int *histo){

__shared__ unsigned int temp[256];
temp[threadIdx.x] = 0;
__syncthreads();

int i = threadIdx.x + blockIdx.x * blockDim.x;
int offset = blockDim.x * gridDim.x;

while (i < size) {
    atomicAdd(&temp[buffer[i]], 1);
    i += offset;}

__syncthreads();
atomicAdd(&(histo[threadIdx.x]), temp[threadIdx.x]);
}

int main()
{


unsigned char *buffer = (unsigned char*)big_random_block(SIZE);

cudaEvent_t start, stop;
cudaEventCreate(&start);
cudaEventCreate(&stop);
cudaEventRecord(start, 0);

unsigned char *dev_buffer;
unsigned int *dev_histo;
cudaMalloc((void**)&dev_buffer, SIZE);
cudaMemcpy(dev_buffer, buffer, SIZE, cudaMemcpyHostToDevice);

cudaMalloc((void**)&dev_histo, 256 * sizeof(long));
cudaMemset(dev_histo, 0, 256 * sizeof(int));

cudaDeviceProp prop;
cudaGetDeviceProperties(&prop, 0);
int blocks = prop.multiProcessorCount; 

histo_kernel << <blocks * 256 , 256>> >(dev_buffer, SIZE, dev_histo);

unsigned int histo[256];
cudaMemcpy(&histo, dev_histo, 256 * sizeof(int), cudaMemcpyDeviceToHost);

cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);
float elapsed_time;
cudaEventElapsedTime(&elapsed_time, start, stop);
printf("Time to generate: %f ms\n", elapsed_time);

long sum = 0;
for (int i = 0; i < 256; i++)
    sum += histo[i];

printf("The sum is %ld", sum);

cudaFree(dev_buffer);
cudaFree(dev_histo);
free(buffer);

getch();
return 0;
#包括“cuda_runtime.h”
#包括“设备启动参数.h”
#包括“.\..\common\book.h”
#包括
#包括
#包括
#定义大小(100*1024*1024)
__全局无效历史内核(无符号字符*缓冲区,长大小,无符号整数*历史){
__共享的无符号整数温度[256];
温度[threadIdx.x]=0;
__同步线程();
int i=threadIdx.x+blockIdx.x*blockDim.x;
int offset=blockDim.x*gridDim.x;
而(i(开发缓冲区、大小、开发历史);
无符号整数历史[256];
cudaMemcpy(历史与发展,历史与发展,256*sizeof(int),cudamemcpydevicetoost);
cudaEventRecord(停止,0);
CUDAEVENTS同步(停止);
浮动时间;
CudaEventReleasedTime(已用时间、开始、停止和结束时间);
printf(“生成时间:%f ms\n”,已用时间);
长和=0;
对于(int i=0;i<256;i++)
总和+=历史[i];
printf(“总和为%ld”,总和);
cudaFree(开发缓冲区);
cudaFree(发展历史);
自由(缓冲);
getch();
返回0;
}

我在《CUDA示例》一书中读到过,根据经验,以多处理机数量两倍的块数启动内核是最理想的解决方案。然而,当我以8倍的块数启动它时,运行时间就缩短了

我运行内核时使用了:1.与多处理器数量相同的块,2.是多处理器数量的两倍的块,3.是4倍的块,依此类推

使用(1),我得到的运行时间是112ms 用(2)我得到的运行时间是73毫秒 我得到的运行时间是52毫秒 有趣的是,在块的数量是多处理器数量的8倍之后,运行时间没有显著变化。就像块是多处理器数量的8倍、256倍和1024倍一样


这怎么解释呢?

这种行为很典型。GPU是一个延迟隐藏机器。为了隐藏延迟,当它遇到暂停时,它需要额外的可用新工作。通过给GPU提供大量的块和线程,您可以最大限度地增加可用的额外工作量

一旦您给了它足够的工作来尽可能地隐藏延迟,给它额外的工作并没有帮助。机器饱和了。然而,有额外的工作可用通常也不会造成太大的损害。与块和线程相关的开销很少

通过示例在CUDA中阅读的任何内容可能在特定情况下是正确的,但要启动的正确块数等于多处理器数的两倍肯定不是正确的。更好的目标(通常)是每个多处理器4-8个块

当涉及到块和线程时,通常越多越好,而拥有任意多的块和线程实际上很少会导致性能显著下降。这与典型的CPU线程编程相反,例如,在CPU线程编程中,当超过内核计数时,拥有大量OMP线程可能会导致性能显著降低


当您调整代码以获得最后10%的性能时,您将看到人们将他们启动的块数量限制为SMs数量的4-8倍,并构建他们的线程块以在数据集上循环。但在大多数情况下,这通常只会带来几%的性能改进。作为一个合理的CUDA编程起点,至少要针对上万个线程和数百个块。一个经过仔细调整的代码可能会用更少的块和线程使机器饱和,但在这一点上它将变得依赖于GPU。正如我已经说过的,拥有数百万个线程和数千个块几乎不会对性能造成太大的损害。

这种行为是典型的。GPU是一个延迟隐藏机器。为了隐藏延迟,当它遇到暂停时,它需要额外的可用新工作。通过给GPU提供大量的块和线程,您可以最大限度地增加可用的额外工作量

一旦您给了它足够的工作来尽可能地隐藏延迟,给它额外的工作并没有帮助。机器饱和了。然而,有额外的工作可用通常也不会造成太大的损害。与块和线程相关的开销很少

通过示例在CUDA中阅读的任何内容可能在特定情况下是正确的,但要启动的正确块数等于多处理器数的两倍肯定不是正确的。更好的目标(通常)是每个多处理器4-8个块

当涉及到块和线程时,通常越多越好,而拥有任意多的块和线程实际上很少会导致性能显著下降。这与典型的CPU线程编程相反,例如,在CPU线程编程中,当超过内核计数时,拥有大量OMP线程可能会导致性能显著降低

当您为性能的最后10%调整代码时,您将看到人们限制块的数量