Переглянути джерело

Implemented device selection for pathfinder

We now use parameters as the way to select OpenCL platform, device and
type instead of having the hardcoded in the code. In this way we can
easily change the type of the benchmark without recompiling it.

Since the parameters parsing routine was quite artisanal and ad-hoc I
opted for reimplementing it adding name to paramters(e.g. -p for
platform...).

Also the initialization of the context was always relying on the first
platform available, extended to actually support more platforms.
Andrea Gussoni 8 роки тому
батько
коміт
d857df9315

+ 35 - 29
opencl/pathfinder/OpenCL.cpp

@@ -70,13 +70,13 @@ cl_kernel OpenCL::kernel(string kernelName)
 	return this->kernelArray[kernelName];
 }
 
-void OpenCL::createKernel(string kernelName)
+void OpenCL::createKernel(string kernelName, int device_idx)
 {
 	cl_kernel kernel = clCreateKernel(this->program, kernelName.c_str(), NULL);
 	kernelArray[kernelName] = kernel;
 	
 	// Get the kernel work group size.
-	clGetKernelWorkGroupInfo(kernelArray[kernelName], device_id[0], CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &lwsize, NULL);
+	clGetKernelWorkGroupInfo(kernelArray[kernelName], device_id[device_idx], CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &lwsize, NULL);
 	if (lwsize == 0)
 	{
 		cout << "Error: clGetKernelWorkGroupInfo() returned a max work group size of zero!" << endl;
@@ -103,7 +103,7 @@ void OpenCL::createKernel(string kernelName)
 	}
 }
 
-void OpenCL::buildKernel()
+void OpenCL::buildKernel(int device_idx)
 {
 	/* Load the source code for all of the kernels into the array source_str */
 	FILE*  theFile;
@@ -155,10 +155,10 @@ void OpenCL::buildKernel()
 		char*  build_log;
 		size_t log_size;
 		// First call to know the proper size
-		clGetProgramBuildInfo(program, device_id[0], CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size);
+		clGetProgramBuildInfo(program, device_id[device_idx], CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size);
 		build_log = new char[log_size + 1];
 		// Second call to get the log
-		clGetProgramBuildInfo(program, device_id[0], CL_PROGRAM_BUILD_LOG, log_size, build_log, NULL);
+		clGetProgramBuildInfo(program, device_id[device_idx], CL_PROGRAM_BUILD_LOG, log_size, build_log, NULL);
 		build_log[log_size] = '\0';
 		cout << build_log << endl;
 		delete[] build_log;
@@ -179,10 +179,10 @@ void OpenCL::buildKernel()
 		char*  build_log;
 		size_t log_size;
 		// First call to know the proper size
-		clGetProgramBuildInfo(program, device_id[0], CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size);
+		clGetProgramBuildInfo(program, device_id[device_idx], CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size);
 		build_log = new char[log_size + 1];
 		// Second call to get the log
-		clGetProgramBuildInfo(program, device_id[0], CL_PROGRAM_BUILD_LOG, log_size, build_log, NULL);
+		clGetProgramBuildInfo(program, device_id[device_idx], CL_PROGRAM_BUILD_LOG, log_size, build_log, NULL);
 		build_log[log_size] = '\0';
 		cout << build_log << endl;
 		delete[] build_log;
@@ -192,15 +192,21 @@ void OpenCL::buildKernel()
 	}
 }
 
-void OpenCL::getDevices(cl_device_type deviceType)
+void OpenCL::getDevices(int platform_idx, int device_idx, cl_device_type deviceType)
 {
 	cl_uint         platforms_n = 0;
 	cl_uint         devices_n   = 0;
+
+  // create OpenCL context
+  clGetPlatformIDs(0, NULL, &platforms_n);
+  
+  cl_platform_id *platforms_ids;
+  platforms_ids = (cl_platform_id*) malloc(sizeof(cl_platform_id) * platforms_n);
 	
 	/* The following code queries the number of platforms and devices, and
 	 * lists the information about both.
 	 */
-	clGetPlatformIDs(100, platform_id, &platforms_n);
+	clGetPlatformIDs(platforms_n, platforms_ids, NULL);
 	if (VERBOSE)
 	{
 		printf("\n=== %d OpenCL platform(s) found: ===\n", platforms_n);
@@ -208,26 +214,27 @@ void OpenCL::getDevices(cl_device_type deviceType)
 		{
 			char buffer[10240];
 			printf("  -- %d --\n", i);
-			clGetPlatformInfo(platform_id[i], CL_PLATFORM_PROFILE, 10240, buffer,
+			clGetPlatformInfo(platforms_ids[i], CL_PLATFORM_PROFILE, 10240, buffer,
 			                  NULL);
 			printf("  PROFILE = %s\n", buffer);
-			clGetPlatformInfo(platform_id[i], CL_PLATFORM_VERSION, 10240, buffer,
+			clGetPlatformInfo(platforms_ids[i], CL_PLATFORM_VERSION, 10240, buffer,
 			                  NULL);
 			printf("  VERSION = %s\n", buffer);
-			clGetPlatformInfo(platform_id[i], CL_PLATFORM_NAME, 10240, buffer, NULL);
+			clGetPlatformInfo(platforms_ids[i], CL_PLATFORM_NAME, 10240, buffer, NULL);
 			printf("  NAME = %s\n", buffer);
-			clGetPlatformInfo(platform_id[i], CL_PLATFORM_VENDOR, 10240, buffer, NULL);
+			clGetPlatformInfo(platforms_ids[i], CL_PLATFORM_VENDOR, 10240, buffer, NULL);
 			printf("  VENDOR = %s\n", buffer);
-			clGetPlatformInfo(platform_id[i], CL_PLATFORM_EXTENSIONS, 10240, buffer,
+			clGetPlatformInfo(platforms_ids[i], CL_PLATFORM_EXTENSIONS, 10240, buffer,
 			                  NULL);
 			printf("  EXTENSIONS = %s\n", buffer);
 		}
 	}
+  
+  printf("DEBUG %d \n", platform_idx);
 	
-	clGetDeviceIDs(platform_id[1], deviceType, 100, device_id, &devices_n);
+	clGetDeviceIDs(platforms_ids[platform_idx], deviceType, 100, device_id, &devices_n);
 	if (VERBOSE)
 	{
-		printf("Using the default platform (platform 0)...\n\n");
 		printf("=== %d OpenCL device(s) found on platform:\n", devices_n);
 		for (int i = 0; i < devices_n; i++)
 		{
@@ -265,16 +272,15 @@ void OpenCL::getDevices(cl_device_type deviceType)
 		printf("\n");
 	}
 	
-	// Create an OpenCL context.
-	context = clCreateContext(NULL, devices_n, device_id, NULL, NULL, &ret);
-	if (ret != CL_SUCCESS)
-	{
-		printf("\nError at clCreateContext! Error code %i\n\n", ret);
-		exit(1);
-	}
+  cl_context_properties ctxprop[] = {CL_CONTEXT_PLATFORM, (cl_context_properties) platforms_ids[platform_idx], 0};
+  context = clCreateContextFromType(ctxprop, deviceType, NULL, NULL, NULL);
+  if (!context) {
+      printf("ERROR: clCreateContextFromType failed\n");
+      exit(1);
+  }
  
 	// Create a command queue.
-	command_queue = clCreateCommandQueue(context, device_id[0], 0, &ret);
+	command_queue = clCreateCommandQueue(context, device_id[device_idx], 0, &ret);
 	if (ret != CL_SUCCESS)
 	{
 		printf("\nError at clCreateCommandQueue! Error code %i\n\n", ret);
@@ -282,12 +288,12 @@ void OpenCL::getDevices(cl_device_type deviceType)
 	}
 }
 
-void OpenCL::init(int isGPU)
+void OpenCL::init(int platform_idx, int device_idx, int use_gpu)
 {
-	if (isGPU)
-		getDevices(CL_DEVICE_TYPE_GPU);
+	if (use_gpu)
+		getDevices(platform_idx, device_idx, CL_DEVICE_TYPE_GPU);
 	else
-		getDevices(CL_DEVICE_TYPE_CPU);
+		getDevices(platform_idx, device_idx, CL_DEVICE_TYPE_CPU);
 
-	buildKernel();
+	buildKernel(device_idx);
 }

+ 5 - 5
opencl/pathfinder/OpenCL.h

@@ -24,8 +24,8 @@ class OpenCL
 public:
 	OpenCL(int displayOutput);
 	~OpenCL();
-	void init(int isGPU);
-	void createKernel(string kernelName);
+	void init(int platform_idx, int device_idx, int use_gpu);
+	void createKernel(string kernelName, int device_idx);
 	cl_kernel kernel(string kernelName);
 	void gwSize(size_t theSize);
 	cl_context ctxt();
@@ -38,13 +38,13 @@ private:
 	size_t                  lwsize;            // Local work size.
 	size_t                  gwsize;            // Global work size.
 	cl_int                  ret;               // Holds the error code returned by cl functions.
-	cl_platform_id          platform_id[100];
+	//cl_platform_id          platform_id[100];
 	cl_device_id            device_id[100];
 	map<string, cl_kernel>  kernelArray;
 	cl_context              context;
 	cl_command_queue        command_queue;
 	cl_program              program;
 	
-	void getDevices(cl_device_type deviceType);
-	void buildKernel();
+	void getDevices(int platform_idx, int device_idx, cl_device_type deviceType);
+	void buildKernel(int device_idx);
 };

+ 50 - 16
opencl/pathfinder/main.cpp

@@ -10,11 +10,12 @@
  ***********************************************************************/
 
 // Other header files.
+#include <assert.h>
+#include <iostream>
 #include <stdio.h>
 #include <stdlib.h>
 #include <time.h>
-#include <assert.h>
-#include <iostream>
+#include <unistd.h>
 #include "OpenCL.h"
 
 using namespace std;
@@ -37,19 +38,46 @@ int** wall;
 int*  result;
 int   pyramid_height;
 
-void init(int argc, char** argv)
+void init(int argc, char** argv, int *platform_idx, int *device_idx, int *use_gpu)
 {
-	if (argc == 4)
-	{
-		cols = atoi(argv[1]);
-		rows = atoi(argv[2]);
-		pyramid_height = atoi(argv[3]);
-	}
-	else
-	{
-		printf("Usage: dynproc row_len col_len pyramid_height\n");
-		exit(0);
+  
+  // Rewritten parameters parsing for selecting platform and device and old
+  // parameters
+    
+  // The lengths of the two sequences should be able to divided by 16.
+	// And at current stage  max_rows needs to equal max_cols
+  int opt;
+  extern char *optarg;
+	while ((opt = getopt(argc, argv, "r:c:h:p:d:g:")) != -1 ) {
+		switch(opt){
+			case 'r':
+			   rows = atoi(optarg);
+			   break;
+			case 'c':
+			   cols = atoi(optarg);
+			   break;
+      case 'h':
+			   pyramid_height = atoi(optarg);
+         break;
+      case 'p':
+			   *platform_idx = atoi(optarg);
+			   break;
+      case 'd':
+  		   *device_idx = atoi(optarg);
+  		   break;
+      case 'g':
+         *use_gpu = atoi(optarg);
+         break;            
+      case ':':
+			   fprintf(stderr, "missing argument\n");
+			   break;
+      default:
+			   fprintf(stderr, "Usage: %s -r <row_len> -c <col_len> -h <pyramid_height> -p <platform> -d <device> -g <use_gpu>\n",
+                 argv[0]);
+			   exit(EXIT_FAILURE);
+		}
 	}
+  
 	data = new int[rows * cols];
 	wall = new int*[rows];
 	for (int n = 0; n < rows; n++)
@@ -88,7 +116,13 @@ void fatal(char *s)
 
 int main(int argc, char** argv)
 {
-	init(argc, argv);
+  
+  // Variables to store information on platform and device to use_gpu
+  int platform_idx = 0;
+  int device_idx = 0;
+  int use_gpu = 0;
+  
+	init(argc, argv, &platform_idx, &device_idx, &use_gpu);
 	
 	// Pyramid parameters.
 	int borderCols = (pyramid_height) * HALO;
@@ -103,12 +137,12 @@ int main(int argc, char** argv)
 
 	// Create and initialize the OpenCL object.
 	OpenCL cl(1);  // 1 means to display output (debugging mode).
-	cl.init(0);    // 1 means to use GPU. 0 means use CPU.
+	cl.init(platform_idx, device_idx, use_gpu);    // 1 means to use GPU. 0 means use CPU.
 	cl.gwSize(rows * cols);
 
 	// Create and build the kernel.
 	string kn = "dynproc_kernel";  // the kernel name, for future use.
-	cl.createKernel(kn);
+	cl.createKernel(kn, device_idx);
 
 	// Allocate device memory.
 	cl_mem d_gpuWall = clCreateBuffer(cl.ctxt(),

+ 1 - 1
opencl/pathfinder/run-cpu

@@ -1 +1 @@
-./pathfinder 100000 100 20
+./pathfinder -r 100000 -c 100 -h 20 -p 1 -d 0 -g 0

+ 1 - 0
opencl/pathfinder/run-gpu

@@ -0,0 +1 @@
+./pathfinder -r 100000 -c 100 -h 20 -p 0 -d 0 -g 1