-
Notifications
You must be signed in to change notification settings - Fork 92
[OpenCL/GPU] Kernel binary caching @open sesame 04/04 09:22 #2503
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,8 @@ | |
|
||
#include "opencl_program.h" | ||
|
||
#include <cstring> | ||
#include <fstream> | ||
#include <string> | ||
|
||
#include "opencl_loader.h" | ||
|
@@ -29,8 +31,8 @@ namespace nntrainer::opencl { | |
* @return true if successful or false otherwise | ||
*/ | ||
bool Program::BuildProgram(cl_device_id device_id, | ||
const std::string &compiler_options) { | ||
|
||
const std::string &compiler_options, | ||
bool binaryCreated) { | ||
// clBuildProgram returns NULL with error code if fails | ||
const int error_code = clBuildProgram( | ||
program_, 0, nullptr, compiler_options.c_str(), nullptr, nullptr); | ||
|
@@ -41,6 +43,105 @@ bool Program::BuildProgram(cl_device_id device_id, | |
return false; | ||
} | ||
|
||
// saving kernel binary | ||
if (!binaryCreated) | ||
return GetProgramInfo(device_id); | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* @brief Utility to get program info and save kernel binaries | ||
* | ||
* @param device_id OpenCL device id | ||
* @return true if successful or false otherwise | ||
*/ | ||
bool Program::GetProgramInfo(cl_device_id device_id) { | ||
// since only GPU is being used | ||
s-debadri marked this conversation as resolved.
Show resolved
Hide resolved
|
||
unsigned int num_devices = 1; | ||
|
||
cl_int error_code = CL_SUCCESS; | ||
size_t *binaries_size = NULL; | ||
unsigned char **binaries_ptr = NULL; | ||
char *kernel_names; | ||
|
||
// Read the binary size | ||
size_t binaries_size_alloc_size = sizeof(size_t) * num_devices; | ||
binaries_size = (size_t *)malloc(binaries_size_alloc_size); | ||
error_code = clGetProgramInfo(program_, CL_PROGRAM_BINARY_SIZES, | ||
binaries_size_alloc_size, binaries_size, NULL); | ||
s-debadri marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
if (error_code != CL_SUCCESS) { | ||
ml_loge("Failed to get program binary size. OpenCL error code: %d. %s", | ||
error_code, | ||
(GetProgramBuildInfo(device_id, CL_PROGRAM_BUILD_LOG)).c_str()); | ||
return false; | ||
} | ||
|
||
// Read the kernel name | ||
size_t *kernel_names_size; | ||
error_code = clGetProgramInfo(program_, CL_PROGRAM_KERNEL_NAMES, 0, NULL, | ||
s-debadri marked this conversation as resolved.
Show resolved
Hide resolved
|
||
kernel_names_size); | ||
s-debadri marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
if (error_code != CL_SUCCESS) { | ||
ml_loge("Failed to get program kernel name size. OpenCL error code: %d. %s", | ||
error_code, | ||
(GetProgramBuildInfo(device_id, CL_PROGRAM_BUILD_LOG)).c_str()); | ||
return false; | ||
} | ||
|
||
// since only one kernel is being saved via this function at a time | ||
// kernel_names_size -> array with 1 element | ||
kernel_names = (char *)malloc(kernel_names_size[0]); | ||
error_code = clGetProgramInfo(program_, CL_PROGRAM_KERNEL_NAMES, | ||
kernel_names_size[0], kernel_names, NULL); | ||
s-debadri marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
if (error_code != CL_SUCCESS) { | ||
ml_loge("Failed to get program kernel names. OpenCL error code: %d. %s", | ||
error_code, | ||
(GetProgramBuildInfo(device_id, CL_PROGRAM_BUILD_LOG)).c_str()); | ||
return false; | ||
} else { | ||
ml_logi("Saving kernel binary for: %s", std::string(kernel_names).c_str()); | ||
} | ||
|
||
// Read the binary | ||
size_t binaries_ptr_alloc_size = sizeof(unsigned char *) * num_devices; | ||
binaries_ptr = (unsigned char **)malloc(binaries_ptr_alloc_size); | ||
|
||
memset(binaries_ptr, 0, binaries_ptr_alloc_size); | ||
s-debadri marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for (unsigned int i = 0; i < num_devices; ++i) { | ||
binaries_ptr[i] = (unsigned char *)malloc(binaries_size[i]); | ||
} | ||
|
||
error_code = clGetProgramInfo(program_, CL_PROGRAM_BINARIES, | ||
binaries_ptr_alloc_size, binaries_ptr, NULL); | ||
|
||
if (error_code != CL_SUCCESS) { | ||
ml_loge("Failed to get program binary data. OpenCL error code: %d. %s", | ||
error_code, | ||
(GetProgramBuildInfo(device_id, CL_PROGRAM_BUILD_LOG)).c_str()); | ||
return false; | ||
s-debadri marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
// Write the binary to file | ||
for (unsigned int i = 0; i < num_devices; ++i) { | ||
std::ofstream fs(std::string(kernel_names) + "_kernel.bin", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It needs to get a parameter save path like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incorporated opencl-kernel-path pre-processor directive in latest commit |
||
std::ios::out | std::ios::binary | std::ios::app); | ||
fs.write((char *)binaries_ptr[i], binaries_size[i]); | ||
fs.close(); | ||
} | ||
|
||
// cleanup | ||
if (binaries_ptr) { | ||
for (unsigned int i = 0; i < num_devices; ++i) { | ||
free(binaries_ptr[i]); | ||
} | ||
free(binaries_ptr); | ||
} | ||
free(binaries_size); | ||
free(kernel_names); | ||
|
||
return true; | ||
} | ||
|
||
|
@@ -103,6 +204,41 @@ bool Program::CreateCLProgram(const cl_context &context, | |
return BuildProgram(device_id, compiler_options); | ||
} | ||
|
||
/** | ||
* @brief Create OpenCL program from pre compiled binary | ||
* | ||
* @param context OpenCL context | ||
* @param device_id OpenCL device id | ||
* @param size binary file size | ||
* @param binary data saved as binary | ||
* @param binary_name name of binary file for logging | ||
* @param compiler_options string compiler options | ||
* @return true if successful or false otherwise | ||
*/ | ||
bool Program::CreateCLProgramWithBinary(const cl_context &context, | ||
const cl_device_id &device_id, | ||
size_t size, unsigned char *binary, | ||
std::string binary_name, | ||
const std::string &compiler_options) { | ||
|
||
int error_code; | ||
const cl_device_id device_list[] = {device_id}; | ||
const size_t lengths[] = {size}; | ||
const unsigned char *binaries[] = {binary}; | ||
|
||
program_ = clCreateProgramWithBinary(context, 1, device_list, lengths, | ||
binaries, NULL, &error_code); | ||
if (!program_ || error_code != CL_SUCCESS) { | ||
ml_loge("Failed to create compute program. OpenCL error code: %d", | ||
error_code); | ||
return false; | ||
} | ||
|
||
ml_logi("Loaded program from binary for: %s", binary_name.c_str()); | ||
|
||
return BuildProgram(device_id, compiler_options, true); | ||
} | ||
|
||
/** | ||
* @brief Get the Program object | ||
* | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be better to add a comment for
@param binaryCreated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added in latest commit.