Quellcode durchsuchen

OpenCL: implement new functions to store compiled OpenCL kernels on the file system

void starpu_opencl_load_program_source(const char *source_file_name, char *located_file_name, char *located_dir_name, char *opencl_program_source);
int starpu_opencl_compile_opencl_from_file(const char *source_file_name, const char* build_options);
int starpu_opencl_compile_opencl_from_string(const char *opencl_program_source, const char *file_name, const char* build_options);
Nathalie Furmento vor 13 Jahren
Ursprung
Commit
8705aa7b2f

+ 31 - 0
doc/chapters/basic-api.texi

@@ -2309,6 +2309,37 @@ This function compiles an OpenCL source code stored in a string.
 This function unloads an OpenCL compiled code.
 @end deftypefun
 
+@deftypefun void starpu_opencl_load_program_source ({const char *}@var{source_file_name}, char *@var{located_file_name}, char *@var{located_dir_name}, char *@var{opencl_program_source})
+Store the contents of the file @var{source_file_name} in the buffer
+@var{opencl_program_source}. The file @var{source_file_name} can be
+located in the current directory, or in the directory specified by the
+environment variable @code{STARPU_OPENCL_PROGRAM_DIR}, or in the
+directory @code{share/starpu/opencl} of the installation directory of
+StarPU, or in the source directory of StarPU.
+When the file is found, @code{located_file_name} is the full name of
+the file as it has been located on the system, @code{located_dir_name}
+the directory where it has been located. Otherwise, they are both set
+to the empty string.
+@end deftypefun
+
+@deftypefun int starpu_opencl_compile_opencl_from_file ({const char *}@var{source_file_name}, {const char*} @var{build_options})
+Compile the OpenCL kernel stored in the file @code{source_file_name}
+with the given options @code{build_options} and stores the result in
+the directory @code{$STARPU_HOME/.starpu/opencl} with the same
+filename as @code{source_file_name}. The compilation is done for every
+OpenCL device, and the filename is suffixed with the vendor id and the
+device id of the OpenCL device.
+@end deftypefun
+
+@deftypefun int starpu_opencl_compile_opencl_from_string ({const char *}@var{opencl_program_source}, {const char *}@var{file_name}, {const char* }@var{build_options})
+Compile the OpenCL kernel in the string @code{opencl_program_source}
+with the given options @code{build_options} and stores the result in
+the directory @code{$STARPU_HOME/.starpu/opencl} with the filename
+@code{file_name}. The compilation is done for every
+OpenCL device, and the filename is suffixed with the vendor id and the
+device id of the OpenCL device.
+@end deftypefun
+
 @node Loading OpenCL kernels
 @subsection Loading OpenCL kernels
 

+ 4 - 0
include/starpu_opencl.h

@@ -59,6 +59,10 @@ void starpu_opencl_get_queue(int devid, cl_command_queue *queue);
 void starpu_opencl_get_current_context(cl_context *context);
 void starpu_opencl_get_current_queue(cl_command_queue *queue);
 
+void starpu_opencl_load_program_source(const char *source_file_name, char *located_file_name, char *located_dir_name, char *opencl_program_source);
+int starpu_opencl_compile_opencl_from_file(const char *source_file_name, const char* build_options);
+int starpu_opencl_compile_opencl_from_string(const char *opencl_program_source, const char *file_name, const char* build_options);
+
 int starpu_opencl_load_opencl_from_file(const char *source_file_name, struct starpu_opencl_program *opencl_programs, const char* build_options);
 int starpu_opencl_load_opencl_from_string(const char *opencl_program_source, struct starpu_opencl_program *opencl_programs, const char* build_options);
 int starpu_opencl_unload_opencl(struct starpu_opencl_program *opencl_programs);

+ 131 - 16
src/drivers/opencl/driver_opencl_utils.c

@@ -26,6 +26,7 @@
 #include <starpu_opencl.h>
 #include <starpu_profiling.h>
 #include <core/workers.h>
+#include <common/utils.h>
 #include "driver_opencl_utils.h"
 #include "driver_opencl.h"
 
@@ -164,8 +165,62 @@ char *_starpu_opencl_load_program_source(const char *filename)
         return source;
 }
 
-int starpu_opencl_load_opencl_from_string(const char *opencl_program_source, struct starpu_opencl_program *opencl_programs,
-					  const char* build_options)
+void _starpu_opencl_create_binary_directory(char *path, size_t maxlen)
+{
+	static int _directory_created = 0;
+
+	snprintf(path, maxlen, "%s/.starpu/opencl/", _starpu_get_home_path());
+
+	if (_directory_created == 0)
+	{
+		int ret;
+
+		_STARPU_DISP("Creating directory %s\n", path);
+		_starpu_mkpath_and_check(path, S_IRWXU);
+		_directory_created = 1;
+	}
+}
+
+char *_starpu_opencl_get_device_type_as_string(int id)
+{
+	cl_device_type type;
+
+	type = _starpu_opencl_get_device_type(id);
+	switch (type)
+	{
+		case CL_DEVICE_TYPE_GPU: return "gpu";
+		case CL_DEVICE_TYPE_ACCELERATOR: return "acc";
+		case CL_DEVICE_TYPE_CPU: return "cpu";
+		default: return "unk";
+	}
+}
+
+int _starpu_opencl_get_binary_name(char *binary_file_name, size_t maxlen, char *source_file_name, int dev, cl_device_id device)
+{
+	char binary_directory[1024];
+	char *p;
+	cl_int err;
+	cl_uint vendor_id;
+
+	_starpu_opencl_create_binary_directory(binary_directory, 1024);
+
+	p = strrchr(source_file_name, '/');
+	if (!p) p=(char *)source_file_name;
+	snprintf(binary_file_name, maxlen, "%s/%s", binary_directory, p);
+
+	p = strstr(binary_file_name, ".cl");
+	if (p == NULL) p=binary_file_name + strlen(binary_file_name);
+
+	err = clGetDeviceInfo(device, CL_DEVICE_VENDOR_ID, sizeof(vendor_id), &vendor_id, NULL);
+	if (err != CL_SUCCESS) STARPU_OPENCL_REPORT_ERROR(err);
+
+	sprintf(p, ".%s.vendor_id_%d_device_id_%d", _starpu_opencl_get_device_type_as_string(dev), (int)vendor_id, dev);
+
+	return CL_SUCCESS;
+}
+
+int _starpu_opencl_compile_or_load_opencl_from_string(const char *opencl_program_source, const char* build_options,
+						      struct starpu_opencl_program *opencl_programs, const char* source_file_name)
 {
         unsigned int dev;
         unsigned int nb_devices;
@@ -179,7 +234,8 @@ int starpu_opencl_load_opencl_from_string(const char *opencl_program_source, str
                 cl_program   program;
                 cl_int       err;
 
-                opencl_programs->programs[dev] = NULL;
+		if (opencl_programs)
+			opencl_programs->programs[dev] = NULL;
 
                 starpu_opencl_get_device(dev, &device);
                 starpu_opencl_get_context(dev, &context);
@@ -220,32 +276,69 @@ int starpu_opencl_load_opencl_from_string(const char *opencl_program_source, str
 		}
 
                 // Store program
-                opencl_programs->programs[dev] = program;
+		if (opencl_programs)
+			opencl_programs->programs[dev] = program;
+		else
+		{
+			char binary_file_name[1024];
+			char *binary;
+			size_t binary_len;
+			FILE *fh;
+
+			err = _starpu_opencl_get_binary_name(binary_file_name, 1024, (char *)source_file_name, dev, device);
+			if (err != CL_SUCCESS) STARPU_OPENCL_REPORT_ERROR(err);
+
+			err = clGetProgramInfo(program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &binary_len, NULL);
+			if (err != CL_SUCCESS) STARPU_OPENCL_REPORT_ERROR(err);
+			binary = malloc(binary_len);
+
+			err = clGetProgramInfo(program, CL_PROGRAM_BINARIES, sizeof(binary), &binary, NULL);
+			if (err != CL_SUCCESS) STARPU_OPENCL_REPORT_ERROR(err);
+
+			fh = fopen(binary_file_name, "w");
+			if (fh == NULL)
+			{
+				_STARPU_DISP("Error: Failed to open file\n");
+				perror("fopen");
+				return EXIT_FAILURE;
+			}
+			fwrite(binary, binary_len, 1, fh);
+			fclose(fh);
+			free(binary);
+			_STARPU_DISP("File <%s> created\n", binary_file_name);
+		}
         }
         return EXIT_SUCCESS;
 }
 
-int starpu_opencl_load_opencl_from_file(const char *source_file_name, struct starpu_opencl_program *opencl_programs,
-					const char* build_options)
+void starpu_opencl_load_program_source(const char *source_file_name, char *located_file_name, char *located_dir_name, char *opencl_program_source)
+{
+        // Locate source file
+        _starpu_opencl_locate_file(source_file_name, located_file_name, located_dir_name);
+        _STARPU_DEBUG("Source file name : <%s>\n", located_file_name);
+        _STARPU_DEBUG("Source directory name : <%s>\n", located_dir_name);
+
+        // Load the compute program from disk into a char *
+        char *source = _starpu_opencl_load_program_source(located_file_name);
+        if(!source)
+                _STARPU_ERROR("Failed to load compute program from file <%s>!\n", located_file_name);
+
+	sprintf(opencl_program_source, "%s", source);
+}
+
+int _starpu_opencl_compile_or_load_opencl_from_file(const char *source_file_name, struct starpu_opencl_program *opencl_programs, const char* build_options)
 {
 	int nb_devices;
         char located_file_name[1024];
         char located_dir_name[1024];
 	char new_build_options[1024];
+	char opencl_program_source[16384];
 
 	// Do not try to load and compile the file if there is no devices
 	nb_devices = starpu_opencl_worker_get_count();
 	if (nb_devices == 0) return EXIT_SUCCESS;
 
-        // Locate source file
-        _starpu_opencl_locate_file(source_file_name, located_file_name, located_dir_name);
-        _STARPU_DEBUG("Source file name : <%s>\n", located_file_name);
-        _STARPU_DEBUG("Source directory name : <%s>\n", located_dir_name);
-
-        // Load the compute program from disk into a cstring buffer
-        char *opencl_program_source = _starpu_opencl_load_program_source(located_file_name);
-        if(!opencl_program_source)
-                _STARPU_ERROR("Failed to load compute program from file <%s>!\n", located_file_name);
+	starpu_opencl_load_program_source(source_file_name, located_file_name, located_dir_name, opencl_program_source);
 
 	if (!strcmp(located_dir_name, ""))
 		strcpy(new_build_options, build_options);
@@ -255,7 +348,29 @@ int starpu_opencl_load_opencl_from_file(const char *source_file_name, struct sta
 		sprintf(new_build_options, "-I %s", located_dir_name);
 	_STARPU_DEBUG("Build options: <%s>\n", new_build_options);
 
-        return starpu_opencl_load_opencl_from_string(opencl_program_source, opencl_programs, new_build_options);
+        return _starpu_opencl_compile_or_load_opencl_from_string(opencl_program_source, new_build_options, opencl_programs, source_file_name);
+}
+
+int starpu_opencl_compile_opencl_from_file(const char *source_file_name, const char* build_options)
+{
+	return _starpu_opencl_compile_or_load_opencl_from_file(source_file_name, NULL, build_options);
+}
+
+int starpu_opencl_compile_opencl_from_string(const char *opencl_program_source, const char *file_name, const char* build_options)
+{
+	return _starpu_opencl_compile_or_load_opencl_from_string(opencl_program_source, build_options, NULL, file_name);
+}
+
+int starpu_opencl_load_opencl_from_string(const char *opencl_program_source, struct starpu_opencl_program *opencl_programs,
+					  const char* build_options)
+{
+	return _starpu_opencl_compile_or_load_opencl_from_string(opencl_program_source, build_options, opencl_programs, NULL);
+}
+
+int starpu_opencl_load_opencl_from_file(const char *source_file_name, struct starpu_opencl_program *opencl_programs,
+					const char* build_options)
+{
+	return _starpu_opencl_compile_or_load_opencl_from_file(source_file_name, opencl_programs, build_options);
 }
 
 int starpu_opencl_unload_opencl(struct starpu_opencl_program *opencl_programs)

+ 3 - 1
src/drivers/opencl/driver_opencl_utils.h

@@ -1,6 +1,6 @@
 /* StarPU --- Runtime system for heterogeneous multicore architectures.
  *
- * Copyright (C) 2010, 2011  Centre National de la Recherche Scientifique
+ * Copyright (C) 2010, 2011, 2012  Centre National de la Recherche Scientifique
  *
  * StarPU is free software; you can redistribute it and/or modify
  * it under the terms of the GNU Lesser General Public License as published by
@@ -19,6 +19,8 @@
 
 #include <config.h>
 
+char *_starpu_opencl_get_device_type_as_string(int id);
+
 #define _STARPU_OPENCL_PLATFORM_MAX 4
 
 #endif /* __STARPU_OPENCL_UTILS_H__ */