nearestNeighbor.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. #ifndef __NEAREST_NEIGHBOR__
  2. #define __NEAREST_NEIGHBOR__
  3. #include "nearestNeighbor.h"
  4. cl_context context=NULL;
  5. int main(int argc, char *argv[]) {
  6. std::vector<Record> records;
  7. float *recordDistances;
  8. //LatLong locations[REC_WINDOW];
  9. std::vector<LatLong> locations;
  10. int i;
  11. // args
  12. char filename[100];
  13. int resultsCount=10,quiet=0,timing=0,platform=-1,device=-1;
  14. float lat=0.0,lng=0.0;
  15. // parse command line
  16. if (parseCommandline(argc, argv, filename,&resultsCount,&lat,&lng,
  17. &quiet, &timing, &platform, &device)) {
  18. printUsage();
  19. return 0;
  20. }
  21. int numRecords = loadData(filename,records,locations);
  22. //for(i=0;i<numRecords;i++)
  23. // printf("%s, %f, %f\n",(records[i].recString),locations[i].lat,locations[i].lng);
  24. if (!quiet) {
  25. printf("Number of records: %d\n",numRecords);
  26. printf("Finding the %d closest neighbors.\n",resultsCount);
  27. }
  28. if (resultsCount > numRecords) resultsCount = numRecords;
  29. context = cl_init_context(platform,device,quiet);
  30. recordDistances = OpenClFindNearestNeighbors(context,numRecords,locations,lat,lng,timing);
  31. // find the resultsCount least distances
  32. findLowest(records,recordDistances,numRecords,resultsCount);
  33. // print out results
  34. if (!quiet)
  35. for(i=0;i<resultsCount;i++) {
  36. printf("%s --> Distance=%f\n",records[i].recString,records[i].distance);
  37. }
  38. free(recordDistances);
  39. return 0;
  40. }
  41. float *OpenClFindNearestNeighbors(
  42. cl_context context,
  43. int numRecords,
  44. std::vector<LatLong> &locations,float lat,float lng,
  45. int timing) {
  46. // 1. set up kernel
  47. cl_kernel NN_kernel;
  48. cl_int status;
  49. cl_program cl_NN_program;
  50. cl_NN_program = cl_compileProgram(
  51. (char *)"nearestNeighbor_kernel.cl",NULL);
  52. NN_kernel = clCreateKernel(
  53. cl_NN_program, "NearestNeighbor", &status);
  54. status = cl_errChk(status, (char *)"Error Creating Nearest Neighbor kernel",true);
  55. if(status)exit(1);
  56. // 2. set up memory on device and send ipts data to device
  57. // copy ipts(1,2) to device
  58. // also need to alloate memory for the distancePoints
  59. cl_mem d_locations;
  60. cl_mem d_distances;
  61. cl_int error=0;
  62. d_locations = clCreateBuffer(context, CL_MEM_READ_ONLY,
  63. sizeof(LatLong) * numRecords, NULL, &error);
  64. d_distances = clCreateBuffer(context, CL_MEM_READ_WRITE,
  65. sizeof(float) * numRecords, NULL, &error);
  66. cl_command_queue command_queue = cl_getCommandQueue();
  67. cl_event writeEvent,kernelEvent,readEvent;
  68. error = clEnqueueWriteBuffer(command_queue,
  69. d_locations,
  70. 1, // change to 0 for nonblocking write
  71. 0, // offset
  72. sizeof(LatLong) * numRecords,
  73. &locations[0],
  74. 0,
  75. NULL,
  76. &writeEvent);
  77. // 3. send arguments to device
  78. cl_int argchk;
  79. argchk = clSetKernelArg(NN_kernel, 0, sizeof(cl_mem), (void *)&d_locations);
  80. argchk |= clSetKernelArg(NN_kernel, 1, sizeof(cl_mem), (void *)&d_distances);
  81. argchk |= clSetKernelArg(NN_kernel, 2, sizeof(int), (void *)&numRecords);
  82. argchk |= clSetKernelArg(NN_kernel, 3, sizeof(float), (void *)&lat);
  83. argchk |= clSetKernelArg(NN_kernel, 4, sizeof(float), (void *)&lng);
  84. cl_errChk(argchk,"ERROR in Setting Nearest Neighbor kernel args",true);
  85. // 4. enqueue kernel
  86. size_t globalWorkSize[1];
  87. globalWorkSize[0] = numRecords;
  88. if (numRecords % 64) globalWorkSize[0] += 64 - (numRecords % 64);
  89. //printf("Global Work Size: %zu\n",globalWorkSize[0]);
  90. error = clEnqueueNDRangeKernel(
  91. command_queue, NN_kernel, 1, 0,
  92. globalWorkSize,NULL,
  93. 0, NULL, &kernelEvent);
  94. cl_errChk(error,"ERROR in Executing Kernel NearestNeighbor",true);
  95. // 5. transfer data off of device
  96. // create distances std::vector
  97. float *distances = (float *)malloc(sizeof(float) * numRecords);
  98. error = clEnqueueReadBuffer(command_queue,
  99. d_distances,
  100. 1, // change to 0 for nonblocking write
  101. 0, // offset
  102. sizeof(float) * numRecords,
  103. distances,
  104. 0,
  105. NULL,
  106. &readEvent);
  107. cl_errChk(error,"ERROR with clEnqueueReadBuffer",true);
  108. if (timing) {
  109. clFinish(command_queue);
  110. cl_ulong eventStart,eventEnd,totalTime=0;
  111. printf("# Records\tWrite(s) [size]\t\tKernel(s)\tRead(s) [size]\t\tTotal(s)\n");
  112. printf("%d \t",numRecords);
  113. // Write Buffer
  114. error = clGetEventProfilingInfo(writeEvent,CL_PROFILING_COMMAND_START,
  115. sizeof(cl_ulong),&eventStart,NULL);
  116. cl_errChk(error,"ERROR in Event Profiling (Write Start)",true);
  117. error = clGetEventProfilingInfo(writeEvent,CL_PROFILING_COMMAND_END,
  118. sizeof(cl_ulong),&eventEnd,NULL);
  119. cl_errChk(error,"ERROR in Event Profiling (Write End)",true);
  120. printf("%f [%.2fMB]\t",(float)((eventEnd-eventStart)/1e9),(float)((sizeof(LatLong) * numRecords)/1e6));
  121. totalTime += eventEnd-eventStart;
  122. // Kernel
  123. error = clGetEventProfilingInfo(kernelEvent,CL_PROFILING_COMMAND_START,
  124. sizeof(cl_ulong),&eventStart,NULL);
  125. cl_errChk(error,"ERROR in Event Profiling (Kernel Start)",true);
  126. error = clGetEventProfilingInfo(kernelEvent,CL_PROFILING_COMMAND_END,
  127. sizeof(cl_ulong),&eventEnd,NULL);
  128. cl_errChk(error,"ERROR in Event Profiling (Kernel End)",true);
  129. printf("%f\t",(float)((eventEnd-eventStart)/1e9));
  130. totalTime += eventEnd-eventStart;
  131. // Read Buffer
  132. error = clGetEventProfilingInfo(readEvent,CL_PROFILING_COMMAND_START,
  133. sizeof(cl_ulong),&eventStart,NULL);
  134. cl_errChk(error,"ERROR in Event Profiling (Read Start)",true);
  135. error = clGetEventProfilingInfo(readEvent,CL_PROFILING_COMMAND_END,
  136. sizeof(cl_ulong),&eventEnd,NULL);
  137. cl_errChk(error,"ERROR in Event Profiling (Read End)",true);
  138. printf("%f [%.2fMB]\t",(float)((eventEnd-eventStart)/1e9),(float)((sizeof(float) * numRecords)/1e6));
  139. totalTime += eventEnd-eventStart;
  140. printf("%f\n\n",(float)(totalTime/1e9));
  141. }
  142. // 6. return finalized data and release buffers
  143. clReleaseMemObject(d_locations);
  144. clReleaseMemObject(d_distances);
  145. return distances;
  146. }
  147. int loadData(char *filename,std::vector<Record> &records,std::vector<LatLong> &locations){
  148. FILE *flist,*fp;
  149. int i=0;
  150. char dbname[64];
  151. int recNum=0;
  152. /**Main processing **/
  153. flist = fopen(filename, "r");
  154. while(!feof(flist)) {
  155. /**
  156. * Read in REC_WINDOW records of length REC_LENGTH
  157. * If this is the last file in the filelist, then done
  158. * else open next file to be read next iteration
  159. */
  160. if(fscanf(flist, "%s\n", dbname) != 1) {
  161. fprintf(stderr, "error reading filelist\n");
  162. exit(0);
  163. }
  164. fp = fopen(dbname, "r");
  165. if(!fp) {
  166. printf("error opening a db\n");
  167. exit(1);
  168. }
  169. // read each record
  170. while(!feof(fp)){
  171. Record record;
  172. LatLong latLong;
  173. fgets(record.recString,49,fp);
  174. fgetc(fp); // newline
  175. if (feof(fp)) break;
  176. // parse for lat and long
  177. char substr[6];
  178. for(i=0;i<5;i++) substr[i] = *(record.recString+i+28);
  179. substr[5] = '\0';
  180. latLong.lat = atof(substr);
  181. for(i=0;i<5;i++) substr[i] = *(record.recString+i+33);
  182. substr[5] = '\0';
  183. latLong.lng = atof(substr);
  184. locations.push_back(latLong);
  185. records.push_back(record);
  186. recNum++;
  187. }
  188. fclose(fp);
  189. }
  190. fclose(flist);
  191. return recNum;
  192. }
  193. void findLowest(std::vector<Record> &records,float *distances,int numRecords,int topN){
  194. int i,j;
  195. float val;
  196. int minLoc;
  197. Record *tempRec;
  198. float tempDist;
  199. for(i=0;i<topN;i++) {
  200. minLoc = i;
  201. for(j=i;j<numRecords;j++) {
  202. val = distances[j];
  203. if (val < distances[minLoc]) minLoc = j;
  204. }
  205. // swap locations and distances
  206. tempRec = &records[i];
  207. records[i] = records[minLoc];
  208. records[minLoc] = *tempRec;
  209. tempDist = distances[i];
  210. distances[i] = distances[minLoc];
  211. distances[minLoc] = tempDist;
  212. // add distance to the min we just found
  213. records[i].distance = distances[i];
  214. }
  215. }
  216. int parseCommandline(int argc, char *argv[], char* filename,int *r,float *lat,float *lng,
  217. int *q, int *t, int *p, int *d){
  218. int i;
  219. if (argc < 2) return 1; // error
  220. strncpy(filename,argv[1],100);
  221. char flag;
  222. for(i=1;i<argc;i++) {
  223. if (argv[i][0]=='-') {// flag
  224. flag = argv[i][1];
  225. switch (flag) {
  226. case 'r': // number of results
  227. i++;
  228. *r = atoi(argv[i]);
  229. break;
  230. case 'l': // lat or lng
  231. if (argv[i][2]=='a') {//lat
  232. *lat = atof(argv[i+1]);
  233. }
  234. else {//lng
  235. *lng = atof(argv[i+1]);
  236. }
  237. i++;
  238. break;
  239. case 'h': // help
  240. return 1;
  241. break;
  242. case 'q': // quiet
  243. *q = 1;
  244. break;
  245. case 't': // timing
  246. *t = 1;
  247. break;
  248. case 'p': // platform
  249. i++;
  250. *p = atoi(argv[i]);
  251. break;
  252. case 'd': // device
  253. i++;
  254. *d = atoi(argv[i]);
  255. break;
  256. }
  257. }
  258. }
  259. if ((*d >= 0 && *p<0) || (*p>=0 && *d<0)) // both p and d must be specified if either are specified
  260. return 1;
  261. return 0;
  262. }
  263. void printUsage(){
  264. printf("Nearest Neighbor Usage\n");
  265. printf("\n");
  266. printf("nearestNeighbor [filename] -r [int] -lat [float] -lng [float] [-hqt] [-p [int] -d [int]]\n");
  267. printf("\n");
  268. printf("example:\n");
  269. printf("$ ./nearestNeighbor filelist.txt -r 5 -lat 30 -lng 90\n");
  270. printf("\n");
  271. printf("filename the filename that lists the data input files\n");
  272. printf("-r [int] the number of records to return (default: 10)\n");
  273. printf("-lat [float] the latitude for nearest neighbors (default: 0)\n");
  274. printf("-lng [float] the longitude for nearest neighbors (default: 0)\n");
  275. printf("\n");
  276. printf("-h, --help Display the help file\n");
  277. printf("-q Quiet mode. Suppress all text output.\n");
  278. printf("-t Print timing information.\n");
  279. printf("\n");
  280. printf("-p [int] Choose the platform (must choose both platform and device)\n");
  281. printf("-d [int] Choose the device (must choose both platform and device)\n");
  282. printf("\n");
  283. printf("\n");
  284. printf("Notes: 1. The filename is required as the first parameter.\n");
  285. printf(" 2. If you declare either the device or the platform,\n");
  286. printf(" you must declare both.\n\n");
  287. }
  288. #endif