首页 > 其他 > 详细

GPU share memory 的应用 (主要内容转载)

时间:2015-10-08 23:07:00      阅读:306      评论:0      收藏:0      [点我收藏+]

链接http://www.aiuxian.com/article/p-2042151.html

同一个block的threads使用shared memory space 要比global memory快很多,所以只要有机会就把global memory整成shared memory。

例子:matrixmultiply

main()程序

 1 // Matrices are stored in row-major order:
 2 // M(row, col) = *(M.elements + row * M.width + col)
 3 typedef struct {
 4     int width;
 5     int height;
 6     float* elements;
 7 } Matrix;
 8 
 9 // Thread block size
10 #define BLOCK_SIZE 16
11 
12 // Forward declaration of the matrix multiplication kernel
13 __global__ void MatMulKernel(const Matrix, const Matrix, Matrix);
14 
15 // Matrix multiplication - Host code
16 // Matrix dimensions are assumed to be multiples of BLOCK_SIZE
17 void MatMul(const Matrix A, const Matrix B, Matrix C)
18 {
19     // Load A and B to device memory
20     Matrix d_A;
21     d_A.width = A.width; d_A.height = A.height;
22     size_t size = A.width * A.height * sizeof(float);
23     cudaMalloc(&d_A.elements, size);
24     cudaMemcpy(d_A.elements, A.elements, size,
25     cudaMemcpyHostToDevice);
26     Matrix d_B;
27     d_B.width = B.width; d_B.height = B.height;
28     size = B.width * B.height * sizeof(float);
29     cudaMalloc(&d_B.elements, size);
30     cudaMemcpy(d_B.elements, B.elements, size,
31     cudaMemcpyHostToDevice);
32 
33     // Allocate C in device memory
34     Matrix d_C;
35     d_C.width = C.width; d_C.height = C.height;
36     size = C.width * C.height * sizeof(float);
37     cudaMalloc(&d_C.elements, size);
38 
39     // Invoke kernel
40     dim3 dimBlock(BLOCK_SIZE, BLOCK_SIZE);
41     dim3 dimGrid(B.width / dimBlock.x, A.height / dimBlock.y);
42     MatMulKernel<<<dimGrid, dimBlock>>>(d_A, d_B, d_C);
43 
44     // Read C from device memory
45     cudaMemcpy(C.elements, Cd.elements, size,
46     cudaMemcpyDeviceToHost);
47     }
48 
49     // Free device memory
50     cudaFree(d_A.elements);
51     cudaFree(d_B.elements);
52     cudaFree(d_C.elements);
53 }

使用Global memory

55 // Matrix multiplication kernel called by MatMul()
56 __global__ void MatMulKernel(Matrix A, Matrix B, Matrix C)
57 {
58     // Each thread computes one element of C
59     // by accumulating results into Cvalue
60     float Cvalue = 0;
61     int row = blockIdx.y * blockDim.y + threadIdx.y;
62     int col = blockIdx.x * blockDim.x + threadIdx.x;
63     for (int e = 0; e < A.width; ++e)
64     Cvalue += A.elements[row * A.width + e]* B.elements[e * B.width + col];
65     C.elements[row * C.width + col] = Cvalue;
66 }

使用share memory

每个thread block负责计算一个子矩阵Csub, 其中每个thread负责计算Csub中的一个元素。如下图所示。为了将fit设备资源,A,B都分割成很多block_size维的方形matrix,Csub将这些方形matrix的乘积求和而得。每次计算一个乘积时,先将两个对应方形矩阵从global memory 载入 shared memory,然后每个thread计算乘积的一个元素,再由每个thread将这些product加和,存入一个register,最后一次性写入global memory。计算时注意同步。

技术分享

 1 __global__ void MatMulKernel(Matrix A, Matrix B, Matrix C)
 2 {
 3     // Block row and column
 4     int blockRow = blockIdx.y;
 5     int blockCol = blockIdx.x;
 6 
 7     // Each thread block computes one sub-matrix Csub of C
 8     Matrix Csub = GetSubMatrix(C, blockRow, blockCol); //仅仅得到global memory的地址
 9 
10     // Each thread computes one element of Csub by accumulating results into Cvalue
11 
12     float Cvalue = 0;
13 
14     // Thread row and column within Csub
15     int row = threadIdx.y;
16     int col = threadIdx.x;
17 
18     // Loop over all the sub-matrices of A and B that are
19     // required to compute Csub
20     // Multiply each pair of sub-matrices together
21     // and accumulate the results
22 
23     for (int m = 0; m < (A.width / BLOCK_SIZE); ++m) {
24 
25         // Get sub-matrix Asub of A
26         Matrix Asub = GetSubMatrix(A, blockRow, m);//仅仅得到global memory的地址
27         // Get sub-matrix Bsub of B
28         Matrix Bsub = GetSubMatrix(B, m, blockCol);//仅仅得到global memory的地址
29 
30         // Shared memory used to store Asub and Bsub respectively
31         __shared__ float As[BLOCK_SIZE][BLOCK_SIZE];
32         __shared__ float Bs[BLOCK_SIZE][BLOCK_SIZE];
33 
34         // Load Asub and Bsub from device memory to shared memory  // load 数据一次 
35         // Each thread loads one element of each sub-matrix
36         As[row][col] = GetElement(Asub, row, col);
37         Bs[row][col] = GetElement(Bsub, row, col);
38 
39         // Synchronize to make sure the sub-matrices are loaded
40         // before starting the computation
41         __syncthreads();
42 
43         // Multiply Asub and Bsub together
44         for (int e = 0; e < BLOCK_SIZE; ++e)
45             Cvalue += As[row][e] * Bs[e][col];
46 
47         // Synchronize to make sure that the preceding
48         // computation is done before loading two new
49         // sub-matrices of A and B in the next iteration
50         __syncthreads();
51     }
52 
53     // Write Csub to device memory
54     // Each thread writes one element
55     SetElement(Csub, row, col, Cvalue);
56 }

注意:

1、使用global memory, A中的每个元素从global memory 读入N次;使用share memory,A中的每个元素从global memory 仅读入 N/BLOCK_SIZE次;

2、thread中的变量,如果没有声明__share__或者__constant__则表示放在thread自己的register中,如果register不够,则放在L1 cache 或者 local memory中。其他threads是不能访问的。

3、如果在变量前加__share__表示将数据放在share memory中,好处,如果一个数据被同一个block中的thread多次访问,放在share memory中,每次从share memory中取数据,比每次去global memory中取数据快很多。

4、例子的share memory的使用如下:

   (1、将As[][]声明为share memory变量,放在share memory;

   (2、每个thread从global memory load 一个元素放到As[][]中,即放到share memory;

   (3、同步。确保As[][]的所有数据都到达share memory,因为下一步是计算,必须确保所有元素都已到达share memory,否则不正确;

   (4、同一个block的所有threads开始计算;

   (5、同步。因为下一步是重新load 另一块As[][],会覆盖当前As[][]的数据。

5、share memory 可以减少多次从 global memory load数据。记住:share memory的数据计算的时候,还是需要load 到register中,从share memory到register的距离明显比global memory到register的时间少!!

 

GPU share memory 的应用 (主要内容转载)

原文:http://www.cnblogs.com/xingzifei/p/4862533.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!