• 多核和多处理器平台的区别
  • 作用的区别
  • 架构的区别
  • 软硬件的内在模型
  • 应用的语义
  • CUDA的存储操作
  • 同步
  • CUDA平台


在之前介绍了OpenMP的多核编程,这一节主要讲得就是CUDA的多处理器编程。

多核和多处理器平台的区别

作用的区别

gpu多核并行计算技术 gpu单核与多核区别_18-645

多核平台的指令以及控制更加复杂,可以在单个周期实现很简单的操作。优化的时候是针对单个的线程,是对线性代码模型的加速。

多处理器更多的资源是在计算部分,实现的是减轻单个处理器的负载。

架构的区别

处理单个数据的能力CPU更强,在最大线程数量、带宽、每个cycle可以处理浮点计算个数来看,GPU更强。

gpu多核并行计算技术 gpu单核与多核区别_18-645_02

什么时候用GPU比较合适呢?当然就是在并行很多的时候采用比较合适。在共享内存很多的时候使用的话,效率会比较低。

软硬件的内在模型

在这里主要是对CUDA做了一些介绍,然后这里的话是谈到了如果想要发挥CUDA的作用,那么必须了解其硬件特性,才能更好发挥其作用。

nVidia的硬件架构:

gpu多核并行计算技术 gpu单核与多核区别_manycore_03

这里面谈到了CUDA的编程模型。语法和C很像。不过定义了主机和从机两部分的代码。主机一般就是CPU、从机就是GPU。主机发送数据到了从机,从机根据kernel编译的指令执行得到数据后返回给主机。

在CUDA的编程模型里面,首先是grid。grid就是比如一个main函数,里面调用了好几个不同的kernel,然后在执行的时候,每个就会生成一个grid。然grid是针对软件而言的,硬件上称之为streaming multiprocessor(SM),然后每个SM内部又有thread block,然后thread block里面又有好几个threads。每个SM之间是相互独立的。每个thread block能够容纳的最大线程数量是一定的。比如现在的gtx1080就是1024个线程。

在软件层面,有一个叫做warp的概念。就是把一些线程集合在一起,方便软件层面的使用。

gpu多核并行计算技术 gpu单核与多核区别_manycore_04

应用的语义

接下来具体介绍CUDA的语法:

__global__ void vcos( int n, float* x, float* y ) { 
    int ix = blockIdx.x*blockDim.x + threadIdx.x; 
    y[ix] = cos( x[ix] );
}

int main() { 
    float *host_x, *host_y; float *dev_x, *dev_y; int n = 1024;
    // CPU的DRAM分配
    host_x = (float*)malloc( n*sizeof(float) ); 
    host_y = (float*)malloc( n*sizeof(float) );
    // GPU的DRAM上分配  
    cudaMalloc( &dev_x, n*sizeof(float) ); 
    cudaMalloc( &dev_y, n*sizeof(float) );

    /* TODO: fill host_x[i] with data here */
    // 数据拷贝 
    cudaMemcpy( dev_x, host_x, n*sizeof(float), cudaMemcpyHostToDevice );

    /* launch 1 thread per vector-element, 256 threads per block */ 
    bk = (int)( n / 256 ); 
    vcos<<<bk,256>>>( n, dev_x, dev_y );

    cudaMemcpy( host_y, dev_y, n*sizeof(float), cudaMemcpyDeviceToHost ); 
    /* host_y now contains cos(x) data */

    return( 0 );
}

CUDA的存储操作

cudaMalloc(void ** pointer, size_t nbytes) 
cudaMemset(void * pointer, int value, size_t count) 
cudaFree(void* pointer)

存储拷贝:

cudaMemcpy( !void *dst, void *src, size_t nbytes, 
enum cudaMemcpyKind direction);

direction specifies locations (host or device) of src and dst
Blocks CPU thread:  returns after the copy is completed 
Doesn’t start copying until previous CUDA calls complete enum cudaMemcpyKind 

cudaMemcpyHostToDevice 
cudaMemcpyDeviceToHost 
cudaMemcpyDeviceToDevice
cudaMemcpyPeer

CUDA的函数类型:有global、device、host三种。

gpu多核并行计算技术 gpu单核与多核区别_CUDA_05

对于CUDA的kernel调用的时候,各个参数的含义:

gpu多核并行计算技术 gpu单核与多核区别_cmu_06

同步

在循环中至少两次访问同一个变量,那么就很有可能发生数据冲突。

举个例子:

gpu多核并行计算技术 gpu单核与多核区别_cmu_07

比如在计算out[9]的值,然后out[10]在访问它。

那么如何修改呢?

gpu多核并行计算技术 gpu单核与多核区别_gpu多核并行计算技术_08

然后在这里,使用的只是block的local memory的同步,还有更大的同步。比如gpu上的global memory的同步,以及整个cpu gpu系统的数据同步。

gpu多核并行计算技术 gpu单核与多核区别_gpu多核并行计算技术_09

然后分别使用以下的函数实现:

gpu多核并行计算技术 gpu单核与多核区别_manycore_10

接着是原子操作(原子操作就是读的时候不限制,写的时候建立临界区的操作。比单纯使用critic function更快)

gpu多核并行计算技术 gpu单核与多核区别_manycore_11

CUDA平台

CUDA的代码是怎么在GPU上执行的呢?

整个模型如下:

gpu多核并行计算技术 gpu单核与多核区别_manycore_12

CUDA和C/C++代码在一起,通过NVCC编译器,生成CPU执行的指令和GPU执行的指令,然后发送到不同的设备上执行。

相对GPU的并行编程,涉及CUDA有更多了解,看【1】【2】

参考链接:
【1】GPU的书籍: programming massive parallel processors.