source: CIVL/examples/cuda/matMult1.cu@ 4e86cdd

1.23 2.0 main test-branch
Last change on this file since 4e86cdd was 3ff27cf, checked in by Manchun Zheng <zmanchun@…>, 11 years ago

updated examples since $assert/$assume has been changed to functions; fixed the model builder for the new side-effect remover.

git-svn-id: svn://vsl.cis.udel.edu/civl/trunk@2085 fb995dde-84ed-4084-dfe6-e5aef3e2452c

  • Property mode set to 100644
File size: 8.9 KB
Line 
1#ifdef _CIVL
2#include <civlc.cvh>
3#endif
4/***********************************************************************
5* FILENAME: MM.cu
6* Matrix Multiplication
7* Matrix operands have row-major order.
8*
9* C = A * B
10* Multiplies two square matrices (NxN * NxN).
11* Matrix values have type double.
12*
13* A simple CUDA program has a basic workflow:
14* 1) Initialize matrix operands as double-precision arrays on host (CPU).
15* 2) Copy operands from host memory to GPU memory.
16* 3) Apply matrix operaton to operands on GPU
17* 4) Copy result from GPU memory to host memory.
18*
19*
20* CUDA C Programming Guide Version 4.2 (3.2.3, p.22):
21* http://developer.download.nvidia.com/compute/DevZone/docs/html/C/doc/CUDA_C_Programming_Guide.pdf
22*
23* MM with linearized matrix operands:
24* http://www.hpcwire.com/hpcwire/2008-10-08/compilers_and_more_programming_gpus_today.html
25*
26*************************************************************************/
27// online source: https://www.rcac.purdue.edu/userinfo/resources/carter/compile/MM.cu
28
29#include <stdio.h>
30#include <stdlib.h>
31#include "cuda.h"
32
33#ifdef _CIVL
34$input int N;
35$input int TILE_WIDTH;
36#else
37#define N 1024 /* size of square matrix */
38#define TILE_WIDTH 16
39#endif
40
41
42/* MM kernel using global (not shared) memory. */
43__global__
44void myMM_global (const double * const A, const double * const B, double *C, int width) {
45
46 /* Get row and column from block and thread IDs */
47 int row = (blockDim.y*blockIdx.y) + threadIdx.y;
48 int col = (blockDim.x*blockIdx.x) + threadIdx.x;
49
50 /* Initialize result of one element which one thread computes. */
51 double result=0.0;
52
53 /* Compute one element of the matrix product. */
54 for (int i = 0; i < width; ++i)
55 result += A[row*width + i] * B[i*width + col];
56
57 /* Store the result of one matrix element in matrix C. */
58 C[row * width + col] = result;
59}
60
61
62/* MM kernel using shared memory. */
63__global__
64void myMM_shared (const double * const A, const double * const B, double* C, int width) {
65 __shared__ double A_shared[TILE_WIDTH][TILE_WIDTH];
66 __shared__ double B_shared[TILE_WIDTH][TILE_WIDTH];
67
68 int bx = blockIdx.x; int by = blockIdx.y;
69 int tx = threadIdx.x; int ty = threadIdx.y;
70
71 /* Identify the row and column of the C element to work on. */
72 int row = by * TILE_WIDTH + ty;
73 int col = bx * TILE_WIDTH + tx;
74
75 double result = 0.0;
76
77 /* Loop over the A and B tiles required to compute the C element. */
78 for (int phase = 0; phase < width/TILE_WIDTH; ++phase) {
79 /* Shared effort: loading of A and B tiles into shared memory. */
80 A_shared[ty][tx] = A[row*width + (phase*TILE_WIDTH + tx)];
81 B_shared[ty][tx] = B[col + (phase*TILE_WIDTH + ty)*width];
82 __syncthreads();
83
84 for (int k = 0; k < TILE_WIDTH; ++k)
85 result += A_shared[ty][k] * B_shared[k][tx];
86 __syncthreads();
87
88 }
89 C[row*width+col] = result;
90}
91
92
93/************************************************************************/
94/************************************************************************/
95/************************************************************************/
96
97
98int main (int argc, char** argv) {
99
100#ifdef _CIVL
101 $assume(argc == 2);
102 $assume(atoi(argv[1]) == 0);
103#endif
104
105 /* Set device based on input from command line */
106 if (argc > 1) {
107 if (cudaSetDevice(atoi(argv[1])) != cudaSuccess) {
108 int num_devices;
109 cudaGetDeviceCount(&num_devices);
110 fprintf(stderr, "Error initializing device %s,\
111 device value must be 0-%d\n", argv[1], (num_devices-1));
112 return 0;
113 }
114 } else {
115 fprintf(stderr, "Usage: %s gpu_device\n", argv[0]);
116 return 0;
117 }
118
119 /* Declare CPU arrays. */
120#ifdef _CIVL
121 $input double A[N*N];
122 $input double B[N*N];
123#else
124 double A[N*N],B[N*N];
125#endif
126 double C[N*N]; /* linearized CPU double arrays */
127 int r,c;
128
129 /* Declare GPU arrays. */
130 double *G_A,*G_B,*G_C; /* linearized GPU double arrays */
131 size_t size_a,size_b,size_c; /* size of linearized array in bytes */
132 size_a = size_b = size_c = N*N;
133
134 /* Setup a clock. */
135 cudaEvent_t start, stop;
136 float CPU_elapsedtime, GPU_global_elapsedtime, GPU_shared_elapsedtime;
137 cudaEventCreate(&start);
138 cudaEventCreate(&stop);
139
140
141
142
143 /* 1) Initialize matrix operands as double-precision arrays on host (CPU). */
144#ifndef _CIVL
145 for (r=0;r<N;++r)
146 for (c=0;c<N;++c) {
147 A[r*N+c] = 1.0;
148 B[r*N+c] = 1.0;
149 }
150#endif
151
152
153/*-----------------------------------------------------------------------*/
154
155 /* MM on a CPU. */
156 cudaEventRecord(start,0);
157 for (int r = 0; r < N; ++r )
158 for (int c = 0; c < N; ++c )
159 for (int k = 0; k < N; ++k )
160 C[r*N+c] += A[r*N+c] * B[k*N+c];
161 cudaEventRecord(stop,0);
162 cudaEventSynchronize(stop);
163 cudaEventElapsedTime(&CPU_elapsedtime,start,stop);
164 printf(" speedup\n");
165 printf(" -------\n");
166 printf("Elapsed time in CPU: %7.1f milliseconds\n", CPU_elapsedtime);
167/*-----------------------------------------------------------------------*/
168
169 /* MM on Global Memory of GPGPU. */
170 cudaEventRecord(start,0);
171
172 /* 2) Copy operands from CPU memory to GPGPU memory. */
173 cudaMalloc((void**)&G_A,size_a*sizeof(double)); /* alloc A in GPGPU */
174 cudaMalloc((void**)&G_B,size_b*sizeof(double)); /* alloc B in GPGPU */
175 cudaMalloc((void**)&G_C,size_c*sizeof(double)); /* alloc C in GPGPU */
176 cudaMemcpy(G_A,A,size_a*sizeof(double),cudaMemcpyHostToDevice);
177 cudaMemcpy(G_B,B,size_b*sizeof(double),cudaMemcpyHostToDevice);
178
179 /* 3) Apply matrix operation to operands on GPGPU */
180 /* There is no partial final block in this example. */
181 dim3 block = {TILE_WIDTH,TILE_WIDTH,1}; /* using a 2D block: 16,16,1 */
182 dim3 grid = {N/TILE_WIDTH,N/TILE_WIDTH,1}; /* as many 16x16-thread blocks as needed: */
183 myMM_global<<< grid,block >>>(G_A,G_B,G_C,N); /* grid(16,16,1) */
184
185 /* 4) Copy result from GPGPU memory to CPU memory. */
186 cudaMemcpy(C,G_C,size_c*sizeof(double),cudaMemcpyDeviceToHost);
187
188 /* Deallocate memory on GPGPU. */
189 cudaFree(G_A);
190 cudaFree(G_B);
191 cudaFree(G_C);
192
193 cudaEventRecord(stop,0);
194 cudaEventSynchronize(stop);
195 cudaEventElapsedTime(&GPU_global_elapsedtime,start,stop);
196 printf("Elapsed time in GPU (global memory): %7.1f milliseconds %5.1f\n",
197 GPU_global_elapsedtime,CPU_elapsedtime/GPU_global_elapsedtime);
198//*
199 printf("\nGLOBAL MEMORY:\n");
200 for (r=0;r<N;++r)
201 for (c=0;c<N;++c) {
202 printf("%2d,%2d %g\n", r,c,C[r*N+c]);
203 }
204//*/
205/*-----------------------------------------------------------------------*/
206
207 /* MM on Shared Memory of GPGPU. */
208 cudaEventRecord(start,0);
209
210 /* 2) Copy operands from CPU memory to GPGPU memory. */
211 cudaMalloc((void**)&G_A,size_a*sizeof(double)); /* alloc A in GPGPU */
212 cudaMalloc((void**)&G_B,size_b*sizeof(double)); /* alloc B in GPGPU */
213 cudaMalloc((void**)&G_C,size_c*sizeof(double)); /* alloc C in GPGPU */
214 cudaMemcpy(G_A,A,size_a*sizeof(double),cudaMemcpyHostToDevice);
215 cudaMemcpy(G_B,B,size_b*sizeof(double),cudaMemcpyHostToDevice);
216
217 /* 3) Apply matrix operation to operands on GPGPU */
218 /* There is not partial final block in this example. */
219 /* Use the same grid and block from the previous case. */
220 myMM_shared<<< grid,block >>>(G_A,G_B,G_C,N);
221
222 /* 4) Copy result from GPGPU memory to CPU memory. */
223 cudaMemcpy(C,G_C,size_c*sizeof(double),cudaMemcpyDeviceToHost);
224
225 /* Deallocate memory on GPGPU. */
226 cudaFree(G_A);
227 cudaFree(G_B);
228 cudaFree(G_C);
229
230 cudaEventRecord(stop,0);
231 cudaEventSynchronize(stop);
232 cudaEventElapsedTime(&GPU_shared_elapsedtime,start,stop);
233 printf("Elapsed time in GPU (shared memory): %7.1f milliseconds %5.1f\n",
234 GPU_shared_elapsedtime,CPU_elapsedtime/GPU_shared_elapsedtime);
235//*
236 printf("\nSHARED MEMORY:\n");
237 for (r=0;r<N;++r)
238 for (c=0;c<N;++c) {
239 printf("%2d,%2d %g\n", r,c,C[r*N+c]);
240 }
241//*/
242/*-----------------------------------------------------------------------*/
243
244 /* Deallocate the clock. */
245 cudaEventDestroy(start);
246 cudaEventDestroy(stop);
247
248 return 0;
249}
250
Note: See TracBrowser for help on using the repository browser.