nw.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. #ifdef RD_WG_SIZE_0_0
  2. #define BLOCK_SIZE RD_WG_SIZE_0_0
  3. #elif defined(RD_WG_SIZE_0)
  4. #define BLOCK_SIZE RD_WG_SIZE_0
  5. #elif defined(RD_WG_SIZE)
  6. #define BLOCK_SIZE RD_WG_SIZE
  7. #else
  8. #define BLOCK_SIZE 16
  9. #endif
  10. #define LIMIT -999
  11. #include <iostream>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <string>
  16. #include <sys/time.h>
  17. #include <unistd.h>
  18. #ifdef NV //NVIDIA
  19. #include <oclUtils.h>
  20. #else
  21. #include <CL/cl.h>
  22. #endif
  23. //global variables
  24. int blosum62[24][24] = {
  25. { 4, -1, -2, -2, 0, -1, -1, 0, -2, -1, -1, -1, -1, -2, -1, 1, 0, -3, -2, 0, -2, -1, 0, -4},
  26. {-1, 5, 0, -2, -3, 1, 0, -2, 0, -3, -2, 2, -1, -3, -2, -1, -1, -3, -2, -3, -1, 0, -1, -4},
  27. {-2, 0, 6, 1, -3, 0, 0, 0, 1, -3, -3, 0, -2, -3, -2, 1, 0, -4, -2, -3, 3, 0, -1, -4},
  28. {-2, -2, 1, 6, -3, 0, 2, -1, -1, -3, -4, -1, -3, -3, -1, 0, -1, -4, -3, -3, 4, 1, -1, -4},
  29. { 0, -3, -3, -3, 9, -3, -4, -3, -3, -1, -1, -3, -1, -2, -3, -1, -1, -2, -2, -1, -3, -3, -2, -4},
  30. {-1, 1, 0, 0, -3, 5, 2, -2, 0, -3, -2, 1, 0, -3, -1, 0, -1, -2, -1, -2, 0, 3, -1, -4},
  31. {-1, 0, 0, 2, -4, 2, 5, -2, 0, -3, -3, 1, -2, -3, -1, 0, -1, -3, -2, -2, 1, 4, -1, -4},
  32. { 0, -2, 0, -1, -3, -2, -2, 6, -2, -4, -4, -2, -3, -3, -2, 0, -2, -2, -3, -3, -1, -2, -1, -4},
  33. {-2, 0, 1, -1, -3, 0, 0, -2, 8, -3, -3, -1, -2, -1, -2, -1, -2, -2, 2, -3, 0, 0, -1, -4},
  34. {-1, -3, -3, -3, -1, -3, -3, -4, -3, 4, 2, -3, 1, 0, -3, -2, -1, -3, -1, 3, -3, -3, -1, -4},
  35. {-1, -2, -3, -4, -1, -2, -3, -4, -3, 2, 4, -2, 2, 0, -3, -2, -1, -2, -1, 1, -4, -3, -1, -4},
  36. {-1, 2, 0, -1, -3, 1, 1, -2, -1, -3, -2, 5, -1, -3, -1, 0, -1, -3, -2, -2, 0, 1, -1, -4},
  37. {-1, -1, -2, -3, -1, 0, -2, -3, -2, 1, 2, -1, 5, 0, -2, -1, -1, -1, -1, 1, -3, -1, -1, -4},
  38. {-2, -3, -3, -3, -2, -3, -3, -3, -1, 0, 0, -3, 0, 6, -4, -2, -2, 1, 3, -1, -3, -3, -1, -4},
  39. {-1, -2, -2, -1, -3, -1, -1, -2, -2, -3, -3, -1, -2, -4, 7, -1, -1, -4, -3, -2, -2, -1, -2, -4},
  40. { 1, -1, 1, 0, -1, 0, 0, 0, -1, -2, -2, 0, -1, -2, -1, 4, 1, -3, -2, -2, 0, 0, 0, -4},
  41. { 0, -1, 0, -1, -1, -1, -1, -2, -2, -1, -1, -1, -1, -2, -1, 1, 5, -2, -2, 0, -1, -1, 0, -4},
  42. {-3, -3, -4, -4, -2, -2, -3, -2, -2, -3, -2, -3, -1, 1, -4, -3, -2, 11, 2, -3, -4, -3, -2, -4},
  43. {-2, -2, -2, -3, -2, -1, -2, -3, 2, -1, -1, -2, -1, 3, -3, -2, -2, 2, 7, -1, -3, -2, -1, -4},
  44. { 0, -3, -3, -3, -1, -2, -2, -3, -3, 3, 1, -2, 1, -1, -2, -2, 0, -3, -1, 4, -3, -2, -1, -4},
  45. {-2, -1, 3, 4, -3, 0, 1, -1, 0, -3, -4, 0, -3, -3, -2, 0, -1, -4, -3, -3, 4, 1, -1, -4},
  46. {-1, 0, 0, 1, -3, 3, 4, -2, 0, -3, -3, 1, -1, -3, -1, 0, -1, -3, -2, -2, 1, 4, -1, -4},
  47. { 0, -1, -1, -1, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, 0, 0, -2, -1, -1, -1, -1, -1, -4},
  48. {-4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, 1}
  49. };
  50. // local variables
  51. static cl_context context;
  52. static cl_command_queue cmd_queue;
  53. static cl_device_type device_type;
  54. static cl_device_id * device_list;
  55. static cl_int num_devices;
  56. static int initialize(int platform_id, int device_id, int use_gpu)
  57. {
  58. cl_int result;
  59. size_t size;
  60. // modification to handle the case in which we have more than one OpenCL platform available on the system.
  61. cl_uint platformCount;
  62. // create OpenCL context
  63. clGetPlatformIDs(0, NULL, &platformCount);
  64. cl_platform_id *platforms_ids;
  65. platforms_ids = (cl_platform_id*) malloc(sizeof(cl_platform_id) * platformCount);
  66. if (clGetPlatformIDs(platformCount, platforms_ids, NULL) != CL_SUCCESS) { printf("ERROR: clGetPlatformIDs(1,*,0) failed\n"); return -1; }
  67. cl_context_properties ctxprop[] = { CL_CONTEXT_PLATFORM, (cl_context_properties)platforms_ids[platform_id], 0};
  68. device_type = use_gpu ? CL_DEVICE_TYPE_GPU : CL_DEVICE_TYPE_CPU;
  69. context = clCreateContextFromType( ctxprop, device_type, NULL, NULL, NULL );
  70. if( !context ) { printf("ERROR: clCreateContextFromType(%s) failed\n", use_gpu ? "GPU" : "CPU"); return -1; }
  71. // get the list of GPUs
  72. result = clGetContextInfo( context, CL_CONTEXT_DEVICES, 0, NULL, &size );
  73. num_devices = (int) (size / sizeof(cl_device_id));
  74. printf("num_devices = %d\n", num_devices);
  75. if( result != CL_SUCCESS || num_devices < 1 ) { printf("ERROR: clGetContextInfo() failed\n"); return -1; }
  76. device_list = new cl_device_id[num_devices];
  77. if( !device_list ) { printf("ERROR: new cl_device_id[] failed\n"); return -1; }
  78. result = clGetContextInfo( context, CL_CONTEXT_DEVICES, size, device_list, NULL );
  79. if( result != CL_SUCCESS ) { printf("ERROR: clGetContextInfo() failed\n"); return -1; }
  80. // create command queue for the first device
  81. cmd_queue = clCreateCommandQueue( context, device_list[device_id], 0, NULL );
  82. if( !cmd_queue ) { printf("ERROR: clCreateCommandQueue() failed\n"); return -1; }
  83. return 0;
  84. }
  85. static int shutdown()
  86. {
  87. // release resources
  88. if( cmd_queue ) clReleaseCommandQueue( cmd_queue );
  89. if( context ) clReleaseContext( context );
  90. if( device_list ) delete device_list;
  91. // reset all variables
  92. cmd_queue = 0;
  93. context = 0;
  94. device_list = 0;
  95. num_devices = 0;
  96. device_type = 0;
  97. return 0;
  98. }
  99. int maximum( int a,
  100. int b,
  101. int c){
  102. int k;
  103. if( a <= b )
  104. k = b;
  105. else
  106. k = a;
  107. if( k <=c )
  108. return(c);
  109. else
  110. return(k);
  111. }
  112. void usage(int argc, char **argv)
  113. {
  114. fprintf(stderr, "Usage: %s <max_rows/max_cols> <penalty> \n", argv[0]);
  115. fprintf(stderr, "\t<dimension> - x and y dimensions\n");
  116. fprintf(stderr, "\t<penalty> - penalty(positive integer)\n");
  117. fprintf(stderr, "\t<file> - filename\n");
  118. exit(1);
  119. }
  120. double gettime() {
  121. struct timeval t;
  122. gettimeofday(&t,NULL);
  123. return t.tv_sec+t.tv_usec*1e-6;
  124. }
  125. int main(int argc, char **argv){
  126. printf("WG size of kernel = %d \n", BLOCK_SIZE);
  127. int max_rows, max_cols, penalty;
  128. char * tempchar;
  129. // Rewritten parameters parsing for selecting platform and device and old
  130. // parameters
  131. // Variables to store information on platform and device to use_gpu
  132. int platform_id = 0;
  133. int device_id = 0;
  134. int use_gpu = 0;
  135. // The lengths of the two sequences should be able to divided by 16.
  136. // And at current stage max_rows needs to equal max_cols
  137. int opt;
  138. extern char *optarg;
  139. while ((opt = getopt(argc, argv, "r:c:x:t:p:d:g:")) != -1 ) {
  140. switch(opt){
  141. case 'r':
  142. max_rows = atoi(optarg);
  143. max_cols = atoi(optarg);
  144. if(max_rows%16!=0){
  145. fprintf(stderr,"The dimension values must be a multiple of 16\n");
  146. exit(1);
  147. }
  148. break;
  149. case 'c':
  150. max_rows = atoi(optarg);
  151. max_cols = atoi(optarg);
  152. if(max_cols%16!=0){
  153. fprintf(stderr,"The dimension values must be a multiple of 16\n");
  154. exit(1);
  155. }
  156. break;
  157. case 'x':
  158. penalty = atoi(optarg);
  159. break;
  160. case 't':
  161. tempchar = optarg;
  162. break;
  163. case 'p':
  164. platform_id = atoi(optarg);
  165. break;
  166. case 'd':
  167. device_id = atoi(optarg);
  168. break;
  169. case 'g':
  170. use_gpu = atoi(optarg);
  171. break;
  172. case ':':
  173. fprintf(stderr, "missing argument\n");
  174. break;
  175. default:
  176. fprintf(stderr, "Usage: %s -r/-c <max_rows/max_cols> -x <penalty> -p <platform> -d <device> -g <use_gpu>\n",
  177. argv[0]);
  178. exit(EXIT_FAILURE);
  179. }
  180. }
  181. max_rows = max_rows + 1;
  182. max_cols = max_cols + 1;
  183. int *reference;
  184. int *input_itemsets;
  185. int *output_itemsets;
  186. reference = (int *)malloc( max_rows * max_cols * sizeof(int) );
  187. input_itemsets = (int *)malloc( max_rows * max_cols * sizeof(int) );
  188. output_itemsets = (int *)malloc( max_rows * max_cols * sizeof(int) );
  189. srand(7);
  190. //initialization
  191. for (int i = 0 ; i < max_cols; i++){
  192. for (int j = 0 ; j < max_rows; j++){
  193. input_itemsets[i*max_cols+j] = 0;
  194. }
  195. }
  196. for( int i=1; i< max_rows ; i++){ //initialize the cols
  197. input_itemsets[i*max_cols] = rand() % 10 + 1;
  198. }
  199. for( int j=1; j< max_cols ; j++){ //initialize the rows
  200. input_itemsets[j] = rand() % 10 + 1;
  201. }
  202. for (int i = 1 ; i < max_cols; i++){
  203. for (int j = 1 ; j < max_rows; j++){
  204. reference[i*max_cols+j] = blosum62[input_itemsets[i*max_cols]][input_itemsets[j]];
  205. }
  206. }
  207. for( int i = 1; i< max_rows ; i++)
  208. input_itemsets[i*max_cols] = -i * penalty;
  209. for( int j = 1; j< max_cols ; j++)
  210. input_itemsets[j] = -j * penalty;
  211. int sourcesize = 1024*1024;
  212. char * source = (char *)calloc(sourcesize, sizeof(char));
  213. if(!source) { printf("ERROR: calloc(%d) failed\n", sourcesize); return -1; }
  214. // read the kernel core source
  215. char * kernel_nw1 = "nw_kernel1";
  216. char * kernel_nw2 = "nw_kernel2";
  217. FILE * fp = fopen(tempchar, "rb");
  218. if(!fp) { printf("ERROR: unable to open '%s'\n", tempchar); return -1; }
  219. fread(source + strlen(source), sourcesize, 1, fp);
  220. fclose(fp);
  221. int nworkitems, workgroupsize = 0;
  222. nworkitems = BLOCK_SIZE;
  223. if(nworkitems < 1 || workgroupsize < 0){
  224. printf("ERROR: invalid or missing <num_work_items>[/<work_group_size>]\n");
  225. return -1;
  226. }
  227. // set global and local workitems
  228. size_t local_work[3] = { (workgroupsize>0)?workgroupsize:1, 1, 1 };
  229. size_t global_work[3] = { nworkitems, 1, 1 }; //nworkitems = no. of GPU threads
  230. // OpenCL initialization
  231. if(initialize(platform_id, device_id, use_gpu)) return -1;
  232. // compile kernel
  233. cl_int err = 0;
  234. const char * slist[2] = { source, 0 };
  235. cl_program prog = clCreateProgramWithSource(context, 1, slist, NULL, &err);
  236. if(err != CL_SUCCESS) { printf("ERROR: clCreateProgramWithSource() => %d\n", err); return -1; }
  237. char clOptions[110];
  238. // sprintf(clOptions,"-I../../src");
  239. sprintf(clOptions," ");
  240. #ifdef BLOCK_SIZE
  241. sprintf(clOptions + strlen(clOptions), " -DBLOCK_SIZE=%d", BLOCK_SIZE);
  242. #endif
  243. err = clBuildProgram(prog, 0, NULL, clOptions, NULL, NULL);
  244. /*{ // show warnings/errors
  245. static char log[65536]; memset(log, 0, sizeof(log));
  246. cl_device_id device_id = 0;
  247. err = clGetContextInfo(context, CL_CONTEXT_DEVICES, sizeof(device_id), &device_id, NULL);
  248. clGetProgramBuildInfo(prog, device_id, CL_PROGRAM_BUILD_LOG, sizeof(log)-1, log, NULL);
  249. if(err || strstr(log,"warning:") || strstr(log, "error:")) printf("<<<<\n%s\n>>>>\n", log);
  250. }*/
  251. if(err != CL_SUCCESS) { printf("ERROR: clBuildProgram() => %d\n", err); return -1; }
  252. cl_kernel kernel1;
  253. cl_kernel kernel2;
  254. kernel1 = clCreateKernel(prog, kernel_nw1, &err);
  255. kernel2 = clCreateKernel(prog, kernel_nw2, &err);
  256. if(err != CL_SUCCESS) { printf("ERROR: clCreateKernel() 0 => %d\n", err); return -1; }
  257. clReleaseProgram(prog);
  258. // creat buffers
  259. cl_mem input_itemsets_d;
  260. cl_mem output_itemsets_d;
  261. cl_mem reference_d;
  262. input_itemsets_d = clCreateBuffer(context, CL_MEM_READ_WRITE, max_cols * max_rows * sizeof(int), NULL, &err );
  263. if(err != CL_SUCCESS) { printf("ERROR: clCreateBuffer input_item_set (size:%d) => %d\n", max_cols * max_rows, err); return -1;}
  264. reference_d = clCreateBuffer(context, CL_MEM_READ_WRITE, max_cols * max_rows * sizeof(int), NULL, &err );
  265. if(err != CL_SUCCESS) { printf("ERROR: clCreateBuffer reference (size:%d) => %d\n", max_cols * max_rows, err); return -1;}
  266. output_itemsets_d = clCreateBuffer(context, CL_MEM_READ_WRITE, max_cols * max_rows * sizeof(int), NULL, &err );
  267. if(err != CL_SUCCESS) { printf("ERROR: clCreateBuffer output_item_set (size:%d) => %d\n", max_cols * max_rows, err); return -1;}
  268. //write buffers
  269. err = clEnqueueWriteBuffer(cmd_queue, input_itemsets_d, 1, 0, max_cols * max_rows * sizeof(int), input_itemsets, 0, 0, 0);
  270. if(err != CL_SUCCESS) { printf("ERROR: clEnqueueWriteBuffer bufIn1 (size:%d) => %d\n", max_cols * max_rows, err); return -1; }
  271. err = clEnqueueWriteBuffer(cmd_queue, reference_d, 1, 0, max_cols * max_rows * sizeof(int), reference, 0, 0, 0);
  272. if(err != CL_SUCCESS) { printf("ERROR: clEnqueueWriteBuffer bufIn2 (size:%d) => %d\n", max_cols * max_rows, err); return -1; }
  273. int worksize = max_cols - 1;
  274. printf("worksize = %d\n", worksize);
  275. //these two parameters are for extension use, don't worry about it.
  276. int offset_r = 0, offset_c = 0;
  277. int block_width = worksize/BLOCK_SIZE ;
  278. clSetKernelArg(kernel1, 0, sizeof(void *), (void*) &reference_d);
  279. clSetKernelArg(kernel1, 1, sizeof(void *), (void*) &input_itemsets_d);
  280. clSetKernelArg(kernel1, 2, sizeof(void *), (void*) &output_itemsets_d);
  281. clSetKernelArg(kernel1, 3, sizeof(cl_int) * (BLOCK_SIZE + 1) *(BLOCK_SIZE+1), (void*)NULL );
  282. clSetKernelArg(kernel1, 4, sizeof(cl_int) * BLOCK_SIZE * BLOCK_SIZE, (void*)NULL );
  283. clSetKernelArg(kernel1, 5, sizeof(cl_int), (void*) &max_cols);
  284. clSetKernelArg(kernel1, 6, sizeof(cl_int), (void*) &penalty);
  285. clSetKernelArg(kernel1, 8, sizeof(cl_int), (void*) &block_width);
  286. clSetKernelArg(kernel1, 9, sizeof(cl_int), (void*) &worksize);
  287. clSetKernelArg(kernel1, 10, sizeof(cl_int), (void*) &offset_r);
  288. clSetKernelArg(kernel1, 11, sizeof(cl_int), (void*) &offset_c);
  289. clSetKernelArg(kernel2, 0, sizeof(void *), (void*) &reference_d);
  290. clSetKernelArg(kernel2, 1, sizeof(void *), (void*) &input_itemsets_d);
  291. clSetKernelArg(kernel2, 2, sizeof(void *), (void*) &output_itemsets_d);
  292. clSetKernelArg(kernel2, 3, sizeof(cl_int) * (BLOCK_SIZE + 1) *(BLOCK_SIZE+1), (void*)NULL );
  293. clSetKernelArg(kernel2, 4, sizeof(cl_int) * BLOCK_SIZE *BLOCK_SIZE, (void*)NULL );
  294. clSetKernelArg(kernel2, 5, sizeof(cl_int), (void*) &max_cols);
  295. clSetKernelArg(kernel2, 6, sizeof(cl_int), (void*) &penalty);
  296. clSetKernelArg(kernel2, 8, sizeof(cl_int), (void*) &block_width);
  297. clSetKernelArg(kernel2, 9, sizeof(cl_int), (void*) &worksize);
  298. clSetKernelArg(kernel2, 10, sizeof(cl_int), (void*) &offset_r);
  299. clSetKernelArg(kernel2, 11, sizeof(cl_int), (void*) &offset_c);
  300. printf("Processing upper-left matrix\n");
  301. for( int blk = 1 ; blk <= worksize/BLOCK_SIZE ; blk++){
  302. global_work[0] = BLOCK_SIZE * blk;
  303. local_work[0] = BLOCK_SIZE;
  304. clSetKernelArg(kernel1, 7, sizeof(cl_int), (void*) &blk);
  305. err = clEnqueueNDRangeKernel(cmd_queue, kernel1, 2, NULL, global_work, local_work, 0, 0, 0);
  306. if(err != CL_SUCCESS) { printf("ERROR: 1 clEnqueueNDRangeKernel()=>%d failed\n", err); return -1; }
  307. }
  308. clFinish(cmd_queue);
  309. printf("Processing lower-right matrix\n");
  310. for( int blk = worksize/BLOCK_SIZE - 1 ; blk >= 1 ; blk--){
  311. global_work[0] = BLOCK_SIZE * blk;
  312. local_work[0] = BLOCK_SIZE;
  313. clSetKernelArg(kernel2, 7, sizeof(cl_int), (void*) &blk);
  314. err = clEnqueueNDRangeKernel(cmd_queue, kernel2, 2, NULL, global_work, local_work, 0, 0, 0);
  315. if(err != CL_SUCCESS) { printf("ERROR: 2 clEnqueueNDRangeKernel()=>%d failed\n", err); return -1; }
  316. }
  317. // Lingjie Zhang modified at Nov 1, 2015
  318. // clFinish(cmd_queue);
  319. // fflush(stdout);
  320. //end Lingjie Zhang modification
  321. err = clEnqueueReadBuffer(cmd_queue, input_itemsets_d, 1, 0, max_cols * max_rows * sizeof(int), output_itemsets, 0, 0, 0);
  322. clFinish(cmd_queue);
  323. //#define TRACEBACK
  324. #ifdef TRACEBACK
  325. FILE *fpo = fopen("result.txt","w");
  326. fprintf(fpo, "print traceback value GPU:\n");
  327. for (int i = max_rows - 2, j = max_rows - 2; i>=0, j>=0;){
  328. int nw, n, w, traceback;
  329. if ( i == max_rows - 2 && j == max_rows - 2 )
  330. fprintf(fpo, "%d ", output_itemsets[ i * max_cols + j]); //print the first element
  331. if ( i == 0 && j == 0 )
  332. break;
  333. if ( i > 0 && j > 0 ){
  334. nw = output_itemsets[(i - 1) * max_cols + j - 1];
  335. w = output_itemsets[ i * max_cols + j - 1 ];
  336. n = output_itemsets[(i - 1) * max_cols + j];
  337. }
  338. else if ( i == 0 ){
  339. nw = n = LIMIT;
  340. w = output_itemsets[ i * max_cols + j - 1 ];
  341. }
  342. else if ( j == 0 ){
  343. nw = w = LIMIT;
  344. n = output_itemsets[(i - 1) * max_cols + j];
  345. }
  346. else{
  347. }
  348. //traceback = maximum(nw, w, n);
  349. int new_nw, new_w, new_n;
  350. new_nw = nw + reference[i * max_cols + j];
  351. new_w = w - penalty;
  352. new_n = n - penalty;
  353. traceback = maximum(new_nw, new_w, new_n);
  354. if(traceback == new_nw)
  355. traceback = nw;
  356. if(traceback == new_w)
  357. traceback = w;
  358. if(traceback == new_n)
  359. traceback = n;
  360. fprintf(fpo, "%d ", traceback);
  361. if(traceback == nw )
  362. {i--; j--; continue;}
  363. else if(traceback == w )
  364. {j--; continue;}
  365. else if(traceback == n )
  366. {i--; continue;}
  367. else
  368. ;
  369. }
  370. fclose(fpo);
  371. #endif
  372. printf("Computation Done\n");
  373. // OpenCL shutdown
  374. if(shutdown()) return -1;
  375. clReleaseMemObject(input_itemsets_d);
  376. clReleaseMemObject(output_itemsets_d);
  377. clReleaseMemObject(reference_d);
  378. free(reference);
  379. free(input_itemsets);
  380. free(output_itemsets);
  381. }