update
This commit is contained in:
346
benchmarks/opencl/nearn/main.cc
Executable file
346
benchmarks/opencl/nearn/main.cc
Executable file
@@ -0,0 +1,346 @@
|
||||
#ifndef __NEAREST_NEIGHBOR__
|
||||
#define __NEAREST_NEIGHBOR__
|
||||
|
||||
#include "nearestNeighbor.h"
|
||||
|
||||
cl_context context = NULL;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
std::vector<Record> records;
|
||||
float *recordDistances;
|
||||
// LatLong locations[REC_WINDOW];
|
||||
std::vector<LatLong> locations;
|
||||
int i;
|
||||
// args
|
||||
char filename[100];
|
||||
int resultsCount = 5, quiet = 0, timing = 0, platform = -1, device = -1;
|
||||
float lat = 30, lng = 90;
|
||||
|
||||
// parse command line
|
||||
if (parseCommandline(argc, argv, filename, &resultsCount, &lat, &lng, &quiet,
|
||||
&timing, &platform, &device)) {
|
||||
printUsage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int numRecords = loadData(filename, records, locations);
|
||||
|
||||
// for(i=0;i<numRecords;i++)
|
||||
// printf("%s, %f,
|
||||
// %f\n",(records[i].recString),locations[i].lat,locations[i].lng);
|
||||
|
||||
printf("Number of records: %d\n", numRecords);
|
||||
printf("Finding the %d closest neighbors.\n", resultsCount);
|
||||
|
||||
if (resultsCount > numRecords)
|
||||
resultsCount = numRecords;
|
||||
|
||||
context = cl_init_context(platform, device, quiet);
|
||||
|
||||
recordDistances = OpenClFindNearestNeighbors(context, numRecords, locations,
|
||||
lat, lng, timing);
|
||||
|
||||
// find the resultsCount least distances
|
||||
findLowest(records, recordDistances, numRecords, resultsCount);
|
||||
|
||||
// print out results
|
||||
if (!quiet)
|
||||
for (i = 0; i < resultsCount; i++) {
|
||||
printf("%s --> Distance=%f\n", records[i].recString, records[i].distance);
|
||||
}
|
||||
free(recordDistances);
|
||||
return 0;
|
||||
}
|
||||
|
||||
float *OpenClFindNearestNeighbors(cl_context context, int numRecords,
|
||||
std::vector<LatLong> &locations, float lat,
|
||||
float lng, int timing) {
|
||||
|
||||
// 1. set up kernel
|
||||
cl_kernel NN_kernel;
|
||||
cl_int status;
|
||||
cl_program cl_NN_program;
|
||||
cl_NN_program = cl_compileProgram((char *)"nearestNeighbor_kernel.cl", NULL);
|
||||
|
||||
NN_kernel = clCreateKernel(cl_NN_program, "NearestNeighbor", &status);
|
||||
status =
|
||||
cl_errChk(status, (char *)"Error Creating Nearest Neighbor kernel", true);
|
||||
if (status)
|
||||
exit(1);
|
||||
// 2. set up memory on device and send ipts data to device
|
||||
// copy ipts(1,2) to device
|
||||
// also need to alloate memory for the distancePoints
|
||||
cl_mem d_locations;
|
||||
cl_mem d_distances;
|
||||
|
||||
cl_int error = 0;
|
||||
|
||||
d_locations = clCreateBuffer(context, CL_MEM_READ_ONLY,
|
||||
sizeof(LatLong) * numRecords, NULL, &error);
|
||||
|
||||
d_distances = clCreateBuffer(context, CL_MEM_READ_WRITE,
|
||||
sizeof(float) * numRecords, NULL, &error);
|
||||
|
||||
cl_command_queue command_queue = cl_getCommandQueue();
|
||||
cl_event writeEvent, kernelEvent, readEvent;
|
||||
error = clEnqueueWriteBuffer(command_queue, d_locations,
|
||||
1, // change to 0 for nonblocking write
|
||||
0, // offset
|
||||
sizeof(LatLong) * numRecords, &locations[0], 0,
|
||||
NULL, &writeEvent);
|
||||
|
||||
// 3. send arguments to device
|
||||
cl_int argchk;
|
||||
argchk = clSetKernelArg(NN_kernel, 0, sizeof(cl_mem), (void *)&d_locations);
|
||||
argchk |= clSetKernelArg(NN_kernel, 1, sizeof(cl_mem), (void *)&d_distances);
|
||||
argchk |= clSetKernelArg(NN_kernel, 2, sizeof(int), (void *)&numRecords);
|
||||
argchk |= clSetKernelArg(NN_kernel, 3, sizeof(float), (void *)&lat);
|
||||
argchk |= clSetKernelArg(NN_kernel, 4, sizeof(float), (void *)&lng);
|
||||
|
||||
cl_errChk(argchk, "ERROR in Setting Nearest Neighbor kernel args", true);
|
||||
|
||||
// 4. enqueue kernel
|
||||
size_t globalWorkSize[1];
|
||||
globalWorkSize[0] = numRecords;
|
||||
if (numRecords % 64)
|
||||
globalWorkSize[0] += 64 - (numRecords % 64);
|
||||
// printf("Global Work Size: %zu\n",globalWorkSize[0]);
|
||||
|
||||
error = clEnqueueNDRangeKernel(command_queue, NN_kernel, 1, 0, globalWorkSize,
|
||||
NULL, 0, NULL, &kernelEvent);
|
||||
|
||||
cl_errChk(error, "ERROR in Executing Kernel NearestNeighbor", true);
|
||||
|
||||
// 5. transfer data off of device
|
||||
|
||||
// create distances std::vector
|
||||
float *distances = (float *)malloc(sizeof(float) * numRecords);
|
||||
|
||||
error = clEnqueueReadBuffer(command_queue, d_distances,
|
||||
1, // change to 0 for nonblocking write
|
||||
0, // offset
|
||||
sizeof(float) * numRecords, distances, 0, NULL,
|
||||
&readEvent);
|
||||
|
||||
cl_errChk(error, "ERROR with clEnqueueReadBuffer", true);
|
||||
if (timing) {
|
||||
clFinish(command_queue);
|
||||
cl_ulong eventStart, eventEnd, totalTime = 0;
|
||||
printf("# Records\tWrite(s) [size]\t\tKernel(s)\tRead(s) "
|
||||
"[size]\t\tTotal(s)\n");
|
||||
printf("%d \t", numRecords);
|
||||
// Write Buffer
|
||||
error = clGetEventProfilingInfo(writeEvent, CL_PROFILING_COMMAND_START,
|
||||
sizeof(cl_ulong), &eventStart, NULL);
|
||||
cl_errChk(error, "ERROR in Event Profiling (Write Start)", true);
|
||||
error = clGetEventProfilingInfo(writeEvent, CL_PROFILING_COMMAND_END,
|
||||
sizeof(cl_ulong), &eventEnd, NULL);
|
||||
cl_errChk(error, "ERROR in Event Profiling (Write End)", true);
|
||||
|
||||
printf("%f [%.2fMB]\t", (float)((eventEnd - eventStart) / 1e9),
|
||||
(float)((sizeof(LatLong) * numRecords) / 1e6));
|
||||
totalTime += eventEnd - eventStart;
|
||||
// Kernel
|
||||
error = clGetEventProfilingInfo(kernelEvent, CL_PROFILING_COMMAND_START,
|
||||
sizeof(cl_ulong), &eventStart, NULL);
|
||||
cl_errChk(error, "ERROR in Event Profiling (Kernel Start)", true);
|
||||
error = clGetEventProfilingInfo(kernelEvent, CL_PROFILING_COMMAND_END,
|
||||
sizeof(cl_ulong), &eventEnd, NULL);
|
||||
cl_errChk(error, "ERROR in Event Profiling (Kernel End)", true);
|
||||
|
||||
printf("%f\t", (float)((eventEnd - eventStart) / 1e9));
|
||||
totalTime += eventEnd - eventStart;
|
||||
// Read Buffer
|
||||
error = clGetEventProfilingInfo(readEvent, CL_PROFILING_COMMAND_START,
|
||||
sizeof(cl_ulong), &eventStart, NULL);
|
||||
cl_errChk(error, "ERROR in Event Profiling (Read Start)", true);
|
||||
error = clGetEventProfilingInfo(readEvent, CL_PROFILING_COMMAND_END,
|
||||
sizeof(cl_ulong), &eventEnd, NULL);
|
||||
cl_errChk(error, "ERROR in Event Profiling (Read End)", true);
|
||||
|
||||
printf("%f [%.2fMB]\t", (float)((eventEnd - eventStart) / 1e9),
|
||||
(float)((sizeof(float) * numRecords) / 1e6));
|
||||
totalTime += eventEnd - eventStart;
|
||||
|
||||
printf("%f\n\n", (float)(totalTime / 1e9));
|
||||
}
|
||||
// 6. return finalized data and release buffers
|
||||
clReleaseMemObject(d_locations);
|
||||
clReleaseMemObject(d_distances);
|
||||
return distances;
|
||||
}
|
||||
|
||||
int loadData(char *filename, std::vector<Record> &records,
|
||||
std::vector<LatLong> &locations) {
|
||||
FILE *flist, *fp;
|
||||
int i = 0;
|
||||
char dbname[64];
|
||||
int recNum = 0;
|
||||
|
||||
/**Main processing **/
|
||||
|
||||
int q = 0;
|
||||
|
||||
flist = fopen(filename, "r");
|
||||
while (!feof(flist)) {
|
||||
/**
|
||||
* Read in REC_WINDOW records of length REC_LENGTH
|
||||
* If this is the last file in the filelist, then done
|
||||
* else open next file to be read next iteration
|
||||
*/
|
||||
if (fscanf(flist, "%s\n", dbname) != 1) {
|
||||
printf("error reading filelist\n");
|
||||
exit(0);
|
||||
}
|
||||
printf("loading db: %s\n", dbname);
|
||||
fp = fopen(dbname, "r");
|
||||
if (!fp) {
|
||||
printf("error opening a db\n");
|
||||
exit(1);
|
||||
}
|
||||
// read each record
|
||||
while (!feof(fp)) {
|
||||
Record record;
|
||||
LatLong latLong;
|
||||
fgets(record.recString, 49, fp);
|
||||
fgetc(fp); // newline
|
||||
if (feof(fp))
|
||||
break;
|
||||
|
||||
// parse for lat and long
|
||||
char substr[6];
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
substr[i] = *(record.recString + i + 28);
|
||||
substr[5] = '\0';
|
||||
latLong.lat = atof(substr);
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
substr[i] = *(record.recString + i + 33);
|
||||
substr[5] = '\0';
|
||||
latLong.lng = atof(substr);
|
||||
|
||||
locations.push_back(latLong);
|
||||
records.push_back(record);
|
||||
recNum++;
|
||||
if (0 == (recNum % 500))
|
||||
break;
|
||||
}
|
||||
|
||||
if (++q == 3)
|
||||
break;
|
||||
fclose(fp);
|
||||
}
|
||||
fclose(flist);
|
||||
return recNum;
|
||||
}
|
||||
|
||||
void findLowest(std::vector<Record> &records, float *distances, int numRecords,
|
||||
int topN) {
|
||||
int i, j;
|
||||
float val;
|
||||
int minLoc;
|
||||
Record *tempRec;
|
||||
float tempDist;
|
||||
|
||||
for (i = 0; i < topN; i++) {
|
||||
minLoc = i;
|
||||
for (j = i; j < numRecords; j++) {
|
||||
val = distances[j];
|
||||
if (val < distances[minLoc])
|
||||
minLoc = j;
|
||||
}
|
||||
// swap locations and distances
|
||||
tempRec = &records[i];
|
||||
records[i] = records[minLoc];
|
||||
records[minLoc] = *tempRec;
|
||||
|
||||
tempDist = distances[i];
|
||||
distances[i] = distances[minLoc];
|
||||
distances[minLoc] = tempDist;
|
||||
|
||||
// add distance to the min we just found
|
||||
records[i].distance = distances[i];
|
||||
}
|
||||
}
|
||||
|
||||
int parseCommandline(int argc, char *argv[], char *filename, int *r, float *lat,
|
||||
float *lng, int *q, int *t, int *p, int *d) {
|
||||
int i;
|
||||
// if (argc < 2) return 1; // error
|
||||
strncpy(filename, "filelist.txt", 100);
|
||||
char flag;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (argv[i][0] == '-') { // flag
|
||||
flag = argv[i][1];
|
||||
switch (flag) {
|
||||
case 'r': // number of results
|
||||
i++;
|
||||
*r = atoi(argv[i]);
|
||||
break;
|
||||
case 'l': // lat or lng
|
||||
if (argv[i][2] == 'a') { // lat
|
||||
*lat = atof(argv[i + 1]);
|
||||
} else { // lng
|
||||
*lng = atof(argv[i + 1]);
|
||||
}
|
||||
i++;
|
||||
break;
|
||||
case 'h': // help
|
||||
return 1;
|
||||
break;
|
||||
case 'q': // quiet
|
||||
*q = 1;
|
||||
break;
|
||||
case 't': // timing
|
||||
*t = 1;
|
||||
break;
|
||||
case 'p': // platform
|
||||
i++;
|
||||
*p = atoi(argv[i]);
|
||||
break;
|
||||
case 'd': // device
|
||||
i++;
|
||||
*d = atoi(argv[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((*d >= 0 && *p < 0) ||
|
||||
(*p >= 0 &&
|
||||
*d < 0)) // both p and d must be specified if either are specified
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void printUsage() {
|
||||
printf("Nearest Neighbor Usage\n");
|
||||
printf("\n");
|
||||
printf("nearestNeighbor [filename] -r [int] -lat [float] -lng [float] [-hqt] "
|
||||
"[-p [int] -d [int]]\n");
|
||||
printf("\n");
|
||||
printf("example:\n");
|
||||
printf("$ ./nearestNeighbor filelist.txt -r 5 -lat 30 -lng 90\n");
|
||||
printf("\n");
|
||||
printf("filename the filename that lists the data input files\n");
|
||||
printf("-r [int] the number of records to return (default: 10)\n");
|
||||
printf("-lat [float] the latitude for nearest neighbors (default: 0)\n");
|
||||
printf("-lng [float] the longitude for nearest neighbors (default: 0)\n");
|
||||
printf("\n");
|
||||
printf("-h, --help Display the help file\n");
|
||||
printf("-q Quiet mode. Suppress all text output.\n");
|
||||
printf("-t Print timing information.\n");
|
||||
printf("\n");
|
||||
printf("-p [int] Choose the platform (must choose both platform and "
|
||||
"device)\n");
|
||||
printf("-d [int] Choose the device (must choose both platform and "
|
||||
"device)\n");
|
||||
printf("\n");
|
||||
printf("\n");
|
||||
printf("Notes: 1. The filename is required as the first parameter.\n");
|
||||
printf(" 2. If you declare either the device or the platform,\n");
|
||||
printf(" you must declare both.\n\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user