Skip to content
Merged
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
b6e08a6
.
ysims Jul 1, 2022
1898c2f
.
ysims Jul 2, 2022
1b83189
add flag
ysims Jul 2, 2022
cc1b19a
Add functionality to save the opencl compiled binary
ysims Jul 3, 2022
b86fea2
include filesystem
ysims Jul 3, 2022
afc9b4b
fix compile issues
ysims Jul 3, 2022
4a5cadd
print statements
ysims Jul 3, 2022
b5aa7ae
Delete
ysims Jul 3, 2022
6dbafa4
debugging
ysims Jul 3, 2022
0adb8be
.
ysims Jul 3, 2022
36da129
.
ysims Jul 3, 2022
f07efb6
.
ysims Jul 3, 2022
27c4de0
.
ysims Jul 4, 2022
2f6b881
.
ysims Jul 4, 2022
601b27a
.
ysims Jul 4, 2022
f8020a1
.
ysims Jul 4, 2022
99ef176
oops
ysims Jul 4, 2022
7543913
maybe actually save the variable
ysims Jul 4, 2022
40095fd
.
ysims Jul 4, 2022
c3d54ca
Remove logs
ysims Jul 4, 2022
35d1fac
Minor changes
ysims Jul 4, 2022
5cbdcc7
check if we don't need this
ysims Jul 4, 2022
aaecbea
Remove unneeded code
ysims Jul 4, 2022
d7ae577
minor formatting
ysims Jul 4, 2022
4f168f8
something something
ysims Jul 4, 2022
f60c498
Fix compile errors
ysims Jul 4, 2022
59bf655
add logs
ysims Jul 5, 2022
89f5fd4
more logs
ysims Jul 5, 2022
2bfaabc
.
ysims Jul 5, 2022
ae4941c
.
ysims Jul 5, 2022
bc93439
.
ysims Jul 5, 2022
15b51c0
fix up some things
ysims Jul 6, 2022
925fa7a
move loading into if
ysims Jul 6, 2022
29a0f33
fix compile errors
ysims Jul 6, 2022
a545623
clear binary
ysims Jul 6, 2022
a07d465
.
ysims Jul 6, 2022
b2a0846
.
ysims Jul 6, 2022
15c69be
compile
ysims Jul 6, 2022
2ad991a
.
ysims Jul 6, 2022
946a0bd
.
ysims Jul 6, 2022
f71f5c8
.
ysims Jul 6, 2022
696f8d2
.
ysims Jul 6, 2022
91818ec
close
ysims Jul 6, 2022
9f88425
read binary
ysims Jul 6, 2022
f253c8d
.
ysims Jul 6, 2022
0f99162
reset vars
ysims Jul 6, 2022
6aaf369
.
ysims Jul 6, 2022
e146ff1
.
ysims Jul 6, 2022
37b59a8
.
ysims Jul 6, 2022
dafe3d1
.
ysims Jul 6, 2022
b87688a
.
ysims Jul 6, 2022
efe87d4
.
ysims Jul 6, 2022
d5bf1bb
.
ysims Jul 6, 2022
26ef153
.
ysims Jul 6, 2022
1980646
null to nullptr
ysims Jul 6, 2022
1a6c054
move around function
ysims Jul 6, 2022
554c5a2
add delete
ysims Jul 6, 2022
21717e4
change saving binary type to vector char
ysims Jul 6, 2022
8eabe87
.
ysims Jul 6, 2022
11fa3ac
.
ysims Jul 6, 2022
e4d14df
.
ysims Jul 7, 2022
bb23ec5
.
ysims Jul 7, 2022
f9113fc
.
ysims Jul 7, 2022
f4565b3
.
ysims Jul 7, 2022
9b101bf
.
ysims Jul 7, 2022
282fd21
.
ysims Jul 7, 2022
d3e0d9a
.
ysims Jul 7, 2022
8cba41c
.
ysims Jul 7, 2022
afcf39c
.
ysims Jul 7, 2022
a5241d4
.
ysims Jul 7, 2022
610a820
.
ysims Jul 7, 2022
f395be9
remove logs
ysims Jul 7, 2022
325aa35
.
ysims Jul 7, 2022
fc7f4f1
build if read failed
ysims Jul 7, 2022
b875f56
treat as exception instead
ysims Jul 7, 2022
a7c0790
.
ysims Jul 7, 2022
cdc56fd
Merge branch 'test' into main
ysims Jul 7, 2022
7cd11f1
compile error
ysims Jul 7, 2022
1ce331a
move to function
ysims Jul 7, 2022
bc2dad5
Move build to function
ysims Jul 7, 2022
abe8de9
fix compile errors
ysims Jul 7, 2022
a53bc2e
Remove logs and add comments
ysims Jul 7, 2022
53d4c60
split functions
ysims Jul 7, 2022
4fd332e
Apply suggestions from code review
ysims Jul 7, 2022
10a4135
compile errors
ysims Jul 7, 2022
cd7db89
remove iostream
ysims Jul 7, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 132 additions & 25 deletions cpp/visualmesh/engine/opencl/engine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
// If OpenCL is disabled then don't provide this file
#if !defined(VISUALMESH_DISABLE_OPENCL)

#include <fstream>
#include <iomanip>
#include <numeric>
#include <sstream>
Expand Down Expand Up @@ -63,56 +64,164 @@ namespace engine {
// OpenCL ::clSetKernelArg functions take the sizeof a pointer as their argument, this is correct
static constexpr size_t MEM_SIZE = sizeof(cl_mem);

public:
/**
* @brief Construct a new OpenCL Engine object
* @brief Load an OpenCL binary from a file and build it
*
* @param binary_path path to save the binary file to
* @param device OpenCL device id
*
* @param structure the network structure to use classification
*/
Engine(const NetworkStructure<Scalar>& structure = {}) {
void load_binary(const std::string& binary_path, cl_device_id& device) {
// If the file doesn't exist, this isn't an error so don't throw just return that it didn't work
std::ifstream read_binary(binary_path, std::ios::in);
if (!read_binary) { throw std::runtime_error("Failed to read from precompiled OpenCL binary."); }

// Error flag to check if any OpenCL functions fail
cl_int error = CL_SUCCESS;

// Get the length
read_binary.seekg(0, read_binary.end);
size_t binary_size = read_binary.tellg();
read_binary.seekg(0, read_binary.beg);

// Read the binary file
std::vector<char> binary_load(binary_size, 0);
read_binary.read(binary_load.data(), binary_size);
read_binary.close();
if (!read_binary) { throw std::runtime_error("Failed to read from precompiled OpenCL binary."); }

// Create the program and build using the loaded binary
cl_int binary_status = CL_SUCCESS;
const unsigned char* binary_ptr = reinterpret_cast<unsigned char*>(binary_load.data());

program = cl::program(
::clCreateProgramWithBinary(context, 1, &device, &binary_size, &binary_ptr, &binary_status, &error),
::clReleaseProgram);
throw_cl_error(error, "Failed to create program from binary");

// Create the OpenCL context and command queue
cl_int error = CL_SUCCESS;
cl_device_id device = nullptr;
std::tie(context, device) = operation::make_context();
queue = operation::make_queue(context, device);
error = ::clBuildProgram(program,
1,
&device,
"-cl-single-precision-constant -cl-fast-relaxed-math -cl-mad-enable",
nullptr,
nullptr);

// Get program sources (this does concatenated strings)
std::stringstream sources;
sources << operation::get_scalar_defines(Scalar(0.0));
sources << PROJECT_EQUIDISTANT_CL;
sources << PROJECT_EQUISOLID_CL;
sources << PROJECT_RECTILINEAR_CL;
sources << LOAD_IMAGE_CL;
sources << operation::make_network(structure);
// If it didn't work, log and throw an error
if (error != CL_SUCCESS) {
// Get program build log
size_t used = 0;
::clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, 0, nullptr, &used);
std::vector<char> log(used);
::clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, log.size(), log.data(), &used);
// Throw an error with the build log
throw_cl_error(error,
"Error building OpenCL program\n" + std::string(log.begin(), log.begin() + used));
}
}

std::string source = sources.str();
const char* cstr = source.c_str();
size_t csize = source.size();
/**
* @brief Build the OpenCL program
*
* @param device OpenCL device id
* @param source OpenCL source information
*/
void build_from_source(cl_device_id& device, const std::string& source) {
// Error flag to check if any OpenCL functions fail
cl_int error = CL_SUCCESS;

// Create the program and build
const char* cstr = source.c_str();
size_t csize = source.size();
program =
cl::program(::clCreateProgramWithSource(context, 1, &cstr, &csize, &error), ::clReleaseProgram);
throw_cl_error(error, "Error adding sources to OpenCL program");

// Compile the program
error = ::clBuildProgram(program,
0,
nullptr,
"-cl-single-precision-constant -cl-fast-relaxed-math -cl-mad-enable",
nullptr,
nullptr);

// If it didn't work, log and throw an error
if (error != CL_SUCCESS) {
// Get program build log
size_t used = 0;
::clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, 0, nullptr, &used);
std::vector<char> log(used);
::clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, log.size(), log.data(), &used);

// Throw an error with the build log
throw_cl_error(error,
"Error building OpenCL program\n" + std::string(log.begin(), log.begin() + used));
}
}

/**
* @brief Save the current OpenCL program in a binary file
*
* @param binary_path path to save the binary file to
*/
void save_binary(std::string binary_path) {

// Get the size of the binary to save
size_t binary_size{};
clGetProgramInfo(program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &binary_size, nullptr);

// Get the data to save
std::vector<char> binary_save(binary_size, 0);
// Get an lvalue ptr to pass to clGetProgramInfo
char* binary_ptr = binary_save.data();
clGetProgramInfo(program, CL_PROGRAM_BINARIES, binary_save.size(), &binary_ptr, nullptr);

// Write to the file and close the file
std::ofstream write_binary(binary_path, std::ofstream::binary);
write_binary.write(binary_save.data(), binary_save.size());
write_binary.close();
}

public:
/**
* @brief Construct a new OpenCL Engine object
*
* @param structure the network structure to use classification
* @param cache_directory directory to save/load the compiled OpenCL binary
*/
Engine(const NetworkStructure<Scalar>& structure = {}, const std::string& cache_directory = "") {
// Create the OpenCL context and command queue
cl_int error = CL_SUCCESS;
cl_device_id device = nullptr;
std::tie(context, device) = operation::make_context();
queue = operation::make_queue(context, device);

// Get program sources (this does concatenated strings)
std::stringstream sources;
sources << operation::get_scalar_defines(Scalar(0.0));
sources << PROJECT_EQUIDISTANT_CL;
sources << PROJECT_EQUISOLID_CL;
sources << PROJECT_RECTILINEAR_CL;
sources << LOAD_IMAGE_CL;
sources << operation::make_network(structure);

std::string source = sources.str();

// The hash of the sources represents the name of the OpenCL compiled program binary file, so that a new
// binary will be created for different sources
const std::size_t source_hash = std::hash<std::string>{}(source);

// If the compiled binary exists, read it
std::string binary_path = cache_directory + "/" + std::to_string(source_hash) + ".bin";

// Try to read the binary
try {
load_binary(binary_path, device);
}
// The compiled binary doesn't exist, create it
catch (std::exception& /* e */) {
build_from_source(device, source);
save_binary(binary_path);
}

// Get the kernels
project_rectilinear =
cl::kernel(::clCreateKernel(program, "project_rectilinear", &error), ::clReleaseKernel);
throw_cl_error(error, "Error getting project_rectilinear kernel");
Expand Down Expand Up @@ -513,9 +622,7 @@ namespace engine {
// Cache for future runs
device_points_cache[&mesh] = cl_points;
}
else {
cl_points = device_mesh->second;
}
else { cl_points = device_mesh->second; }

// First count the size of the buffer we will need to allocate
int n_points = 0;
Expand Down