source: CIVL/examples/cuda/newCudaMockup.cvl@ 66ea4f9

1.23 2.0 acw/focus-triggers main test-branch
Last change on this file since 66ea4f9 was 66ea4f9, checked in by Alex Wilton <awilton@…>, 3 years ago

cuda mockup no longer has any ample sets

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

  • Property mode set to 100644
File size: 18.7 KB
RevLine 
[29eb398]1/**
2 * TODO:
3 * - implement cudaMemset and cudaMemsetAsync
4 * - flesh out basic structure of cuda kernel:
5 * - spawn gridDim blocks
6 * - spawn blockDim threads
7 * Alternatively, spawn blockDim warps and then spawn warp's threads
8 * - wait for blocks to finish
9 * - Add in block-level barriers and a __syncthreads() nested function that uses the barrier.
10 * - Add in data race checking support and implement atomicAdd for integers
[874f9d1]11 * - Handle dependencies at atomic blocks (replace some with local blocks if possible)
[29eb398]12 */
13
[30cb1de]14#include <concurrency.cvh>
[6dd0322]15#include <comm.cvh>
[30cb1de]16#include <stdlib.h>
[874f9d1]17#include <stdio.h>
[30cb1de]18#include <stdbool.h>
19#include <string.h>
[66ea4f9]20#pragma CIVL ACSL
[30cb1de]21
[6dd0322]22///////////
23// Types //
24///////////
25
[109d05e]26enum cudaError {
27 cudaSuccess
28};
29typedef enum cudaError cudaError_t;
30
31typedef enum cudaMemcpyKind {
32 cudaMemcpyHostToHost,
33 cudaMemcpyHostToDevice,
34 cudaMemcpyDeviceToHost,
35 cudaMemcpyDeviceToDevice,
36 cudaMemcpyDefault
37} cudaMemcpyKind;
38
[30cb1de]39typedef struct {
40 unsigned int x, y, z;
41} dim3;
42
43/* used to represent a location in a three dimensional grid
44 */
45typedef struct {
46 unsigned int x, y, z;
47} uint3;
48
49typedef struct $cuda_op_state* $cuda_op_state_t;
50struct $cuda_op_state {
[109d05e]51 _Bool start;
[e76acca]52 $proc op;
[30cb1de]53};
[109d05e]54
[30cb1de]55typedef struct $cuda_op_state_node* $cuda_op_state_node_t;
56struct $cuda_op_state_node {
[e76acca]57 $cuda_op_state_t opState;
58 $cuda_op_state_node_t next;
[30cb1de]59};
[109d05e]60
[30cb1de]61typedef struct cudaStream* cudaStream_t;
62typedef struct $cuda_stream_node* $cuda_stream_node_t;
63struct cudaStream {
[e76acca]64 $cuda_op_state_node_t head;
65 $cuda_op_state_node_t tail;
[109d05e]66 int numOps;
67 $cuda_stream_node_t containingNode;
68 _Bool alive;
[30cb1de]69};
[109d05e]70
[30cb1de]71struct $cuda_stream_node {
72 cudaStream_t stream;
[109d05e]73 $cuda_stream_node_t prev;
74 $cuda_stream_node_t next;
[30cb1de]75};
[109d05e]76
77typedef struct $cuda_context {
[30cb1de]78 $cuda_stream_node_t head; //list of streams
[109d05e]79 int numStreams;
80} $cuda_context;
81
[0ffc6c8]82typedef struct $cuda_memcpy_data {
83 void* dst;
84 const void* src;
85 size_t count;
86 cudaMemcpyKind kind;
87} $cuda_memcpy_data;
88
89typedef struct $cuda_kernel_1_data {
90 dim3 gridDim;
91 dim3 blockDim;
92 size_t $cudaMemSize;
93 cudaStream_t $cudaStream;
94 const float* A;
95 const float* B;
96 float* C;
97 int numElements;
98} $cuda_kernel_1_data;
99
[6dd0322]100//////////////////////
101// Global Variables //
102//////////////////////
103
104$gcomm $cuda_gcomm = $gcomm_create($here, 2);
105const int $CUDA_PLACE_HOST = 0;
106const int $CUDA_PLACE_DEVICE = 1;
[0ffc6c8]107$comm $cuda_host_comm = $comm_create($here, $cuda_gcomm, $CUDA_PLACE_HOST);
[6dd0322]108
109/**
110 * Tags used for message-passing between host and device
111 */
[0ffc6c8]112
113enum $cuda_tag {
114 // Predefined tags
115 $CUDA_TAG_TEARDOWN,
116 $CUDA_TAG_SCOPE_REQUEST,
117 $CUDA_TAG_cudaFree,
118 $CUDA_TAG_cudaMemcpy,
119 $CUDA_TAG_cudaMemcpyAsync,
120 // Generated tags (by transformer)
121 $CUDA_TAG_LAUNCH_kernel_1
122};
[6dd0322]123
124////////////////////////////////////////////
125// CUDA API Functions (For Host-use Only) //
126////////////////////////////////////////////
127
[0ffc6c8]128/*
[6dd0322]129cudaError_t cudaMalloc(void** devPtr, size_t size) {
130 $comm_enqueue($cuda_host_comm, $message_pack($CUDA_PLACE_HOST, $CUDA_PLACE_DEVICE, $CUDA_TAG_cudaMalloc, &size, sizeof(size_t)));
131 $message response = $comm_dequeue($cuda_host_comm, $CUDA_PLACE_DEVICE, $CUDA_TAG_cudaMalloc);
132 $message_unpack(response, devPtr, sizeof(void*));
[0ffc6c8]133
134 return cudaSuccess;
[6dd0322]135}
[0ffc6c8]136*/
[6dd0322]137
[0ffc6c8]138$scope $cuda_host_request_device_scope() {
139 $comm_enqueue($cuda_host_comm, $message_pack($CUDA_PLACE_HOST, $CUDA_PLACE_DEVICE, $CUDA_TAG_SCOPE_REQUEST, NULL, 0));
140 $message response = $comm_dequeue($cuda_host_comm, $CUDA_PLACE_DEVICE, $CUDA_TAG_SCOPE_REQUEST);
141 $scope result;
142 $message_unpack(response, &result, sizeof($scope));
[6dd0322]143
[0ffc6c8]144 return result;
145}
146
147cudaError_t cudaFree(void* devPtr) {
148 $comm_enqueue($cuda_host_comm, $message_pack($CUDA_PLACE_HOST, $CUDA_PLACE_DEVICE, $CUDA_TAG_cudaFree, &devPtr, sizeof(void*)));
149 $comm_dequeue($cuda_host_comm, $CUDA_PLACE_DEVICE, $CUDA_TAG_cudaFree);
150
151 return cudaSuccess;
152}
153
154void $cuda_helper_host_memcpy(void* dst, const void* src, size_t count, cudaMemcpyKind kind, _Bool async) {
155 if (kind == cudaMemcpyHostToHost) {
[6dd0322]156 memcpy(dst, src, count);
157 } else {
[0ffc6c8]158 $cuda_memcpy_data args;
[6dd0322]159 args.dst = dst;
160 args.src = src;
161 args.count = count;
162 args.kind = kind;
[0ffc6c8]163
164 int tag = async ? $CUDA_TAG_cudaMemcpyAsync : $CUDA_TAG_cudaMemcpy;
165
166 $comm_enqueue($cuda_host_comm, $message_pack($CUDA_PLACE_HOST, $CUDA_PLACE_DEVICE, tag, &args, sizeof($cuda_memcpy_data)));
167 $comm_dequeue($cuda_host_comm, $CUDA_PLACE_DEVICE, tag);
[6dd0322]168 }
[0ffc6c8]169}
170
171cudaError_t cudaMemcpy(void* dst, const void* src, size_t count, cudaMemcpyKind kind) {
172 $cuda_helper_host_memcpy(dst, src, count, kind, false);
[6dd0322]173 return cudaSuccess;
[109d05e]174}
175
[0ffc6c8]176cudaError_t cudaMemcpyAsync(void* dst, const void* src, size_t count,
177 cudaMemcpyKind kind, cudaStream_t stream) {
178 $cuda_helper_host_memcpy(dst, src, count, kind, true);
179 return cudaSuccess;
[109d05e]180}
181
[30cb1de]182/**
183 * TODO:
184 * - test
185 * - atomic?
186 */
[0ffc6c8]187/*
[109d05e]188cudaError_t cudaStreamCreate(cudaStream_t * pStream) {
189 // Create new stream node in linked list
190 $cuda_stream_node_t newHead = $create_new_stream_node();
191 newHead->next = $cuda_global_context.head;
192 $cuda_global_context.head->prev = newHead;
193
194 // Update cuda context's head to be the new node we created
195 $cuda_global_context.head = newHead;
196 $cuda_global_context.numStreams++;
197
[30cb1de]198 return cudaSuccess;
[109d05e]199}
[0ffc6c8]200*/
[109d05e]201
[30cb1de]202/**
203 * TODO:
204 * - test
205 * - atomic?
206 */
[0ffc6c8]207/*
[109d05e]208cudaError_t cudaStreamSynchronize(cudaStream_t stream) {
209 stream = $default_stream_if_null(stream);
210 $assert(stream->alive, "Attempt to synchronize with a destroyed stream");
211 $when(stream->head == NULL) return cudaSuccess;
212}
[0ffc6c8]213*/
[109d05e]214
215// TODO: atomic
[0ffc6c8]216/*
[109d05e]217cudaError_t cudaStreamDestroy(cudaStream_t stream) {
218 $assert(stream != NULL && stream != $cuda_default_stream, "Attempt to destroy default stream");
[30cb1de]219 $assert(stream->alive, "Attempt to destroy an already destroyed stream");
[109d05e]220 $destroy_stream_node(stream->containingNode);
221 return cudaSuccess;
222}
[0ffc6c8]223*/
[109d05e]224
[0ffc6c8]225/*
[109d05e]226cudaError_t cudaDeviceSynchronize() {
[30cb1de]227 $proc* opsToWaitOn;
[109d05e]228 int numOps = 0;
229
230 $atomic {
[30cb1de]231 opsToWaitOn = ($proc*) malloc(sizeof($proc) * $cuda_global_context.numStreams);
232
[109d05e]233 for ($cuda_stream_node_t node = $cuda_global_context.head;
[30cb1de]234 node != NULL;
235 node = node->next) {
236 if (node->stream->tail != NULL) {
237 opsToWaitOn[numOps] = node->stream->tail->opState->op;
238 numOps++;
239 }
240 }
241 }
[e76acca]242 $waitall(opsToWaitOn, numOps);
[109d05e]243
[30cb1de]244 return cudaSuccess;
[109d05e]245}
[0ffc6c8]246*/
247
248void $cuda_host_launch_kernel_1(dim3 gridDim, dim3 blockDim, size_t $cudaMemSize, cudaStream_t $cudaStream,
249 const float* A, const float* B, float* C, int numElements) {
250 $cuda_kernel_1_data args;
251 args.gridDim = gridDim;
252 args.blockDim = blockDim;
253 args.$cudaMemSize = $cudaMemSize;
254 args.$cudaStream = $cudaStream;
255 args.A = A;
256 args.B = B;
257 args.C = C;
258 args.numElements = numElements;
259
260 $comm_enqueue($cuda_host_comm, $message_pack($CUDA_PLACE_HOST, $CUDA_PLACE_DEVICE, $CUDA_TAG_LAUNCH_kernel_1, &args, sizeof($cuda_kernel_1_data)));
261 $comm_dequeue($cuda_host_comm, $CUDA_PLACE_DEVICE, $CUDA_TAG_LAUNCH_kernel_1);
[109d05e]262}
263
[66ea4f9]264//////////////
265// CUDA Ops //
266//////////////
267/*
268struct $_cuda_op_state_h {
269 $cuda_op_state_t opState;
270};
271typedef struct $_cuda_op_state_h * $cuda_op_state_h;
272*/
273
274/*
275 * Enqueues the calling $proc as a new cuda operation onto stream. Then blocks until the cuda operation is allowed to execute.
276 *
277 * Reasoning behind using enqueuedFlag:
278 * + Enforces in the interface more explicitly that device proc shouldn't continue until new op state is created and properly filled out (including the $proc field)
279 * + Keeps symmetry since this method means the op does both enqueueing and dequeueing. The alternative technique would have device enqueuing and op dequeuing.
280 * + Reduces dependencies since device proc will not be manipulating the streams nor have direct access to the newly created op state.
281 * + Keeps responsibility of device proc strictly to interpreting messages, spawning appropriate ops and sending message.
282 */
283/*@ depends_on \access(stream);
284 @ assigns stream;
285 @ reads \nothing;
286 @*/
287$atomic_f $proc $stream_enqueue($scope $cuda_scope, cudaStream_t stream, $message opParams, void(*opProc)($message, $cuda_op_state_t, cudaStream_t)) {
288 $assert(stream->alive, "Attempt to enqueue a CUDA operation onto a destroyed stream");
289
290 $cuda_op_state_t newOpState = ($cuda_op_state_t) $malloc($cuda_scope, sizeof(struct $cuda_op_state));
291 newOpState->start = false;
292 newOpState->op = $spawn opProc(opParams, newOpState, stream);
293
294 $cuda_op_state_node_t newOpStateNode = ($cuda_op_state_node_t) $malloc($cuda_scope, sizeof(struct $cuda_op_state_node));
295 newOpStateNode->opState = newOpState;
296 newOpStateNode->next = NULL;
297
298 if (stream->tail == NULL) {
299 stream->head = newOpStateNode;
300 stream->tail = newOpStateNode;
301 newOpState->start = true;
302 } else {
303 stream->tail->next = newOpStateNode;
304 stream->tail = newOpStateNode;
305 }
306 stream->numOps++;
307
308 //$cuda_op_state_h result = ($cuda_op_state_h) $malloc($cuda_scope, sizeof(struct $_cuda_op_state_h));
309 //result->opState = newOpState;
310 return newOpState->op;
311}
312
313/*@ depends_on \nothing;
314 @ assigns \nothing;
315 @ reads \nothing;
316 @*/
317$atomic_f void $stream_dequeue(cudaStream_t stream) {
318 //stream = $default_stream_if_null(stream);
319 $assert(stream->head != NULL, "Attempt to dequeue an empty stream");
320
321 if (stream->head == stream->tail) {
322 stream->tail = NULL;
323 }
324
325 $cuda_op_state_node_t oldHead = stream->head;
326 stream->head = oldHead->next;
327 if (stream->head != NULL) {
328 stream->head->opState->start = true;
329 }
330
331 stream->numOps--;
332 free(oldHead->opState);
333 free(oldHead);
334 //free(opHandle);
335}
336
337void $cuda_memcpy_proc($message m, $cuda_op_state_t opState, cudaStream_t stream) {
338
339 $when(opState->start);
340 $cuda_memcpy_data args;
341 $message_unpack(m, &args, sizeof($cuda_memcpy_data));
342
343 if (args.kind == cudaMemcpyHostToDevice || cudaMemcpyDeviceToDevice) {
344 args.dst = $reveal(args.dst);
345 }
346 if (args.kind == cudaMemcpyDeviceToHost || cudaMemcpyDeviceToDevice) {
347 args.src = $reveal(args.src);
348 }
349 memcpy(args.dst, args.src, args.count);
350
351 $stream_dequeue(stream);
352}
353
354// Helper function
355 int $dim3_index(dim3 size, uint3 location) {
356 return location.x + size.x * (location.y + size.y * location.z);
357 }
358
359 // Helper function
360 int $cuda_kernel_index (dim3 gDim, dim3 bDim, uint3 bIdx, uint3 tIdx) {
361 return $dim3_index(gDim, bIdx) * (bDim.x * bDim.y * bDim.z) + $dim3_index(bDim, tIdx);
362 }
363
364void $cuda_run_and_wait_on_procs(dim3 dim, void spawningFunction(uint3)) {
365 //TODO: calculate length and index, replace this function in the kernel
366 $local_start();
367 int length = dim.x * dim.y * dim.z;
368 $proc proc_array[length];
369 $range rx = 0 .. dim.x - 1;
370 $range ry = 0 .. dim.y - 1;
371 $range rz = 0 .. dim.z - 1;
372 $domain(3) dom = ($domain(3)){rx, ry, rz};
373 $for(int x,y,z : dom){
374 uint3 id = { x, y, z };
375 int index = $dim3_index(dim, id);
376 proc_array[index] = $spawn spawningFunction(id);
377 }
378 $local_end();
379 $waitall(proc_array,length);
380}
381
382// Generated from kernel_1 definition
383void $cuda_kernel_1(dim3 gridDim, dim3 blockDim, size_t _cuda_mem_size,
384 const float *A, const float *B, float *C, int numElements) {
385 void _cuda_block(uint3 blockIdx) {
386 int numThreads = (blockDim.x * blockDim.y) * blockDim.z;
387 $scope _block_root = $here;
388 $gbarrier _cuda_block_barrier = $gbarrier_create($here, blockDim.x * blockDim.y * blockDim.z);
389 void _cuda_thread(uint3 threadIdx) {
390 int _cuda_tid = $dim3_index(blockDim, threadIdx);
391 int _cuda_kid = $cuda_kernel_index(gridDim, blockDim, blockIdx, threadIdx);
392 $barrier _cuda_thread_barrier = $barrier_create($here, _cuda_block_barrier, _cuda_tid);
393 $local_start();
394 // Kernel definition start
395
396 int i = blockDim.x * blockIdx.x + threadIdx.x;
397
398 if (i < numElements)
399 {
400 C[i] = A[i] + B[i];
401 }
402
403 // Kernel definition end
404 $local_end();
405 $barrier_destroy(_cuda_thread_barrier);
406 }
407 $cuda_run_and_wait_on_procs(blockDim, _cuda_thread);
408 $gbarrier_destroy(_cuda_block_barrier);
409 }
410 $cuda_run_and_wait_on_procs(gridDim, _cuda_block);
411}
412
413void $cuda_kernel_1_proc ($message m, $cuda_op_state_t opState, cudaStream_t $cudaStream) {
414 $when(opState->start);
415
416 $cuda_kernel_1_data args;
417 $message_unpack(m, &args, sizeof($cuda_kernel_1_data));
418
419 $cuda_kernel_1(args.gridDim, args.blockDim, args.$cudaMemSize, $reveal(args.A), $reveal(args.B), $reveal(args.C), args.numElements);
420 $stream_dequeue($cudaStream);
421}
422
[6dd0322]423/////////////////
424// CUDA "file" //
425/////////////////
426
427void _cuda_main() {
428
429 //////////////////////
430 // Device Variables //
431 //////////////////////
432
[0ffc6c8]433 $scope $cuda_scope = $here;
434
435 $comm $cuda_device_comm = $comm_create($cuda_scope, $cuda_gcomm, 1);
[6dd0322]436 $cuda_context $cuda_global_context;
437 cudaStream_t $cuda_default_stream;
[66ea4f9]438
[6dd0322]439
[0ffc6c8]440 /////////////////////////////////
441 // Context & Stream Management //
442 /////////////////////////////////
[66ea4f9]443
[0ffc6c8]444 // Helper function to get the default stream if passed NULL, and just returns stream otherwise
445 cudaStream_t $default_stream_if_null(cudaStream_t stream) {
446 return stream == NULL ? $cuda_default_stream : stream;
447 }
448
449 $cuda_stream_node_t $create_new_stream_node() {
450 cudaStream_t newStream = (cudaStream_t) malloc(sizeof(struct cudaStream));
451 newStream->head = NULL;
452 newStream->tail = NULL;
453 newStream->numOps = 0;
454 newStream->alive = true;
455
456 $cuda_stream_node_t newHead = ($cuda_stream_node_t) malloc(sizeof(struct $cuda_stream_node));
457 newHead->stream = newStream;
458 newStream->containingNode = newHead;
459 newHead->prev = NULL;
460 newHead->next = NULL;
461
462 return newHead;
463 }
464
[66ea4f9]465 /*@ depends_on \nothing;
466 @ assigns \nothing;
467 @ reads \nothing;
468 @*/
[0ffc6c8]469 $atomic_f $proc $destroy_stream_node($cuda_stream_node_t node) {
470 $proc lastOpProc = $proc_null;
471 cudaStream_t stream = node->stream;
472
473 if (node->prev != NULL) {
474 node->prev->next = node->next;
475 }
476 if (node->next != NULL) {
477 node->next->prev = node->prev;
478 }
479 free(node);
480
481 stream->alive = false;
482 if(stream->tail != NULL)
483 lastOpProc = stream->tail->opState->op;
484
485 void $destroy_stream_when_complete($proc lastOpProc, cudaStream_t stream) {
486 $wait(lastOpProc);
487 free(stream);
488 }
489
490 return $spawn $destroy_stream_when_complete(lastOpProc, stream);
491 }
492
[6dd0322]493 ///////////////////////////////
494 // CUDA Function Definitions //
495 ///////////////////////////////
[0ffc6c8]496
[6dd0322]497 /**
498 * Only called at start of program
499 */
500 void $cuda_setup() {
501 $cuda_stream_node_t defaultStreamNode = $create_new_stream_node();
502 $cuda_default_stream = defaultStreamNode->stream;
503
504 $cuda_global_context.head = defaultStreamNode;
505 $cuda_global_context.numStreams = 1;
506 }
507
508 /**
509 * Only called at end of program
510 */
511 void $cuda_teardown() {
512 $proc destructor = $destroy_stream_node($cuda_default_stream->containingNode);
513 $wait(destructor);
[0ffc6c8]514 $comm_destroy($cuda_device_comm);
[6dd0322]515 }
516
[0ffc6c8]517 $message $cuda_free($message request) {
518 void* devPtr;
519 $message_unpack(request, &devPtr, sizeof(void*));
[cb46bb6]520 free($reveal(devPtr));
521 //free(devPtr);
[6dd0322]522
[0ffc6c8]523 return $message_pack($CUDA_PLACE_DEVICE, $CUDA_PLACE_HOST, $CUDA_TAG_cudaFree, NULL, 0);
[6dd0322]524 }
525
[0ffc6c8]526 $message $cuda_memcpy($message request, _Bool async) {
527 $cuda_memcpy_data args;
528 $message_unpack(request, &args, sizeof($cuda_memcpy_data));
[66ea4f9]529
530 $proc memcpyProc = $stream_enqueue($cuda_scope, $default_stream_if_null($cuda_default_stream), request, $cuda_memcpy_proc);
[0ffc6c8]531
532 if (!async && args.kind != cudaMemcpyDeviceToDevice) {
[6dd0322]533 $wait(memcpyProc);
534 }
[0ffc6c8]535 int tag = async ? $CUDA_TAG_cudaMemcpyAsync : $CUDA_TAG_cudaMemcpy;
[6dd0322]536
[0ffc6c8]537 return $message_pack($CUDA_PLACE_DEVICE, $CUDA_PLACE_HOST, tag, NULL, 0);
[6dd0322]538 }
539
540 ////////////////////////
541 // Kernel Definitions //
542 ////////////////////////
[0ffc6c8]543
544 $message $cuda_device_launch_kernel_1($message request) {
[66ea4f9]545 // TODO: Unpack message for passing in stream parameter
546 $stream_enqueue($cuda_scope, $default_stream_if_null($cuda_default_stream), request, $cuda_kernel_1_proc);
[0ffc6c8]547
548 return $message_pack($CUDA_PLACE_DEVICE, $CUDA_PLACE_HOST, $CUDA_TAG_LAUNCH_kernel_1, NULL, 0);
549 }
[6dd0322]550
551 /////////////////
552 // Device main //
553 /////////////////
554
555 $cuda_setup();
556
557 while (true) {
558 $message request = $comm_dequeue($cuda_device_comm, $CUDA_PLACE_HOST, $COMM_ANY_TAG);
559 $message response;
[0ffc6c8]560 const int tag = $message_tag(request);
[6dd0322]561
562 switch(tag) {
[0ffc6c8]563 case $CUDA_TAG_SCOPE_REQUEST :
564 response = $message_pack($CUDA_PLACE_DEVICE, $CUDA_PLACE_HOST, $CUDA_TAG_SCOPE_REQUEST, &$cuda_scope, sizeof($scope));
565 break;
566 case $CUDA_TAG_cudaFree :
567 response = $cuda_free(request);
[6dd0322]568 break;
569 case $CUDA_TAG_cudaMemcpy :
[0ffc6c8]570 response = $cuda_memcpy(request, false);
571 break;
572 case $CUDA_TAG_cudaMemcpyAsync :
573 response = $cuda_memcpy(request, true);
[6dd0322]574 break;
575 case $CUDA_TAG_LAUNCH_kernel_1 :
[0ffc6c8]576 response = $cuda_device_launch_kernel_1(request);
577 break;
578 case $CUDA_TAG_TEARDOWN :
579 $cuda_teardown();
580 return;
[6dd0322]581 default :
582 $assert(false, "Unknown CUDA request");
583 }
584
585 $comm_enqueue($cuda_device_comm, response);
586 }
587}
588
589///////////////
590// Host file //
591///////////////
592
[4bd0090]593$input int N;
594$assume (N > 0);
595$input float A[N];
596$input float B[N];
597
[6dd0322]598void _host_main() {
[4bd0090]599 int size = N * sizeof(float);
[874f9d1]600 int numBlocks = 2;
601 int numThreads = N%2 == 0? N/2 : (N+1)/2;
[4bd0090]602
[874f9d1]603 float* cuda_A;
[0ffc6c8]604 // cudaMalloc((void **)&cuda_A, size);
[4bd0090]605 {
[0ffc6c8]606 $scope deviceScope = $cuda_host_request_device_scope();
[cb46bb6]607 cuda_A = $hide((float*)$malloc(deviceScope, size));
608 //cuda_A = (float*)$malloc(deviceScope, size);
[4bd0090]609 }
[874f9d1]610 cudaMemcpy(cuda_A, A, size, cudaMemcpyHostToDevice);
[4bd0090]611
[874f9d1]612 float* cuda_B;
[4bd0090]613 // cudaMalloc((void **)&cuda_B, size);
[30cb1de]614 {
[0ffc6c8]615 $scope deviceScope = $cuda_host_request_device_scope();
[cb46bb6]616 cuda_B = $hide((float*)$malloc(deviceScope, size));
617 //cuda_B = (float*)$malloc(deviceScope, size);
[4bd0090]618 }
[874f9d1]619 cudaMemcpy(cuda_B, B, size, cudaMemcpyHostToDevice);
[4bd0090]620
[874f9d1]621 float* cuda_C;
[4bd0090]622 // cudaMalloc((void **)&cuda_C, size);
623 {
[0ffc6c8]624 $scope deviceScope = $cuda_host_request_device_scope();
[cb46bb6]625 cuda_C = $hide((float*)$malloc(deviceScope, size));
626 //cuda_C = (float*)$malloc(deviceScope, size);
[4bd0090]627 }
628
[0ffc6c8]629 dim3 gridDim = {numBlocks, 1, 1};
630 dim3 blockDim = {numThreads, 1, 1};
631 // kernel_1<<<gridDim, blockDim>>>(cuda_A, cuda_B, cuda_C, N);
632 $cuda_host_launch_kernel_1(gridDim, blockDim, 0, NULL, cuda_A, cuda_B, cuda_C, N);
[874f9d1]633
634 //Checking correctness
635 float* C = (float *)malloc(size);
636
637 cudaMemcpy(C, cuda_C, size, cudaMemcpyDeviceToHost);
638
639 for(int i = 0; i < N; i++)
640 $assert(C[i] == A[i] + B[i]);
641
642 free(C);
643
[7e3e7af]644 cudaFree(cuda_A);
[0ffc6c8]645 cudaFree(cuda_B);
646 cudaFree(cuda_C);
[6dd0322]647
648 // inserted by transformer
649 $comm_enqueue($cuda_host_comm, $message_pack($CUDA_PLACE_HOST, $CUDA_PLACE_DEVICE, $CUDA_TAG_TEARDOWN, NULL, 0));
[0ffc6c8]650 $comm_destroy($cuda_host_comm);
[109d05e]651}
652
653int main() {
[6dd0322]654 $proc host = $spawn _host_main();
655 $proc cuda = $spawn _cuda_main();
656 $wait(host);
657 $wait(cuda);
[0ffc6c8]658 $gcomm_destroy($cuda_gcomm, NULL);
[e76acca]659}
Note: See TracBrowser for help on using the repository browser.