From 1c8d08b8d93a438acce2dce0bcfe7e1f58509e1a Mon Sep 17 00:00:00 2001 From: Ysobel Date: Mon, 11 Jul 2022 21:22:30 +0700 Subject: [PATCH 1/6] apply caching --- cpp/visualmesh/engine/opencl/engine.hpp | 149 ++++++++++++++++++++---- 1 file changed, 129 insertions(+), 20 deletions(-) diff --git a/cpp/visualmesh/engine/opencl/engine.hpp b/cpp/visualmesh/engine/opencl/engine.hpp index d1f642f..c829ecf 100644 --- a/cpp/visualmesh/engine/opencl/engine.hpp +++ b/cpp/visualmesh/engine/opencl/engine.hpp @@ -25,6 +25,7 @@ #include #include #include +#include #include "visualmesh/engine/opencl/kernels/load_image.cl.hpp" #include "visualmesh/engine/opencl/kernels/project_equidistant.cl.hpp" @@ -60,54 +61,162 @@ namespace engine { template class Engine { 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& structure = {}) : max_width(4) { + 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."); } - // Create the OpenCL context and command queue + // Error flag to check if any OpenCL functions fail cl_int error = CL_SUCCESS; - cl_device_id device; - 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); + // Get the length + read_binary.seekg(0, read_binary.end); + size_t binary_size = read_binary.tellg(); + read_binary.seekg(0, read_binary.beg); - std::string source = sources.str(); - const char* cstr = source.c_str(); - size_t csize = source.size(); + // Read the binary file + std::vector 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(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"); + + error = ::clBuildProgram(program, + 1, + &device, + "-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 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 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 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 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(); + } + + /** + * @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& 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{}(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); + } project_rectilinear = cl::kernel(::clCreateKernel(program, "project_rectilinear", &error), ::clReleaseKernel); From d9bce0034deb826ed1e3649e1411ab018d8eaba7 Mon Sep 17 00:00:00 2001 From: Ysobel Date: Wed, 25 Jan 2023 19:06:07 +1100 Subject: [PATCH 2/6] Add move to input in CPU engine --- cpp/visualmesh/engine/cpu/engine.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/visualmesh/engine/cpu/engine.hpp b/cpp/visualmesh/engine/cpu/engine.hpp index 9fc76e6..f69e9b9 100644 --- a/cpp/visualmesh/engine/cpu/engine.hpp +++ b/cpp/visualmesh/engine/cpu/engine.hpp @@ -269,7 +269,7 @@ namespace engine { return ClassifiedMesh{std::move(projected.pixel_coordinates), std::move(projected.neighbourhood), std::move(projected.global_indices), - input}; + std::move(input)}; } /** From 719030db25dc84aedfd43d22b2188793fe39b38d Mon Sep 17 00:00:00 2001 From: Ysobel Date: Wed, 25 Jan 2023 19:10:06 +1100 Subject: [PATCH 3/6] remove duplicate functions (merge issue) --- cpp/visualmesh/engine/opencl/engine.hpp | 118 ------------------------ 1 file changed, 118 deletions(-) diff --git a/cpp/visualmesh/engine/opencl/engine.hpp b/cpp/visualmesh/engine/opencl/engine.hpp index 700a846..cdea741 100644 --- a/cpp/visualmesh/engine/opencl/engine.hpp +++ b/cpp/visualmesh/engine/opencl/engine.hpp @@ -21,12 +21,10 @@ // If OpenCL is disabled then don't provide this file #if !defined(VISUALMESH_DISABLE_OPENCL) -#include #include #include #include #include -#include #include "visualmesh/engine/opencl/kernels/load_image.cl.hpp" #include "visualmesh/engine/opencl/kernels/project_equidistant.cl.hpp" @@ -181,122 +179,6 @@ namespace engine { } public: - - /** - * @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 - * - */ - 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 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(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"); - - error = ::clBuildProgram(program, - 1, - &device, - "-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 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 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"); - - 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 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 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(); - } - /** * @brief Construct a new OpenCL Engine object * From 4a4da25de2519546eb2cce6d8c5fd9d8f8cf0f4f Mon Sep 17 00:00:00 2001 From: Ysobel Date: Wed, 25 Jan 2023 19:10:40 +1100 Subject: [PATCH 4/6] Shouldn't be deleted --- cpp/visualmesh/engine/opencl/engine.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/cpp/visualmesh/engine/opencl/engine.hpp b/cpp/visualmesh/engine/opencl/engine.hpp index cdea741..9c7989f 100644 --- a/cpp/visualmesh/engine/opencl/engine.hpp +++ b/cpp/visualmesh/engine/opencl/engine.hpp @@ -21,6 +21,7 @@ // If OpenCL is disabled then don't provide this file #if !defined(VISUALMESH_DISABLE_OPENCL) +#include #include #include #include From e300ad3f61ea7daf7576f809c209d68a4fd010d4 Mon Sep 17 00:00:00 2001 From: Ysobel Date: Wed, 1 Feb 2023 20:14:12 +1100 Subject: [PATCH 5/6] update lookup call --- cpp/visualmesh/visualmesh.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/visualmesh/visualmesh.hpp b/cpp/visualmesh/visualmesh.hpp index 4804765..f8539c8 100644 --- a/cpp/visualmesh/visualmesh.hpp +++ b/cpp/visualmesh/visualmesh.hpp @@ -148,7 +148,7 @@ class VisualMesh { // z height from the transformation matrix const Scalar& h = Hoc[2][3]; auto mesh = height(h); - return mesh->lookup(Hoc, lens); + return std::make_pair(mesh, mesh.lookup(Hoc, lens)); } private: From 437f48e9e3a2155eae8e78b7bcff0d24982a3b03 Mon Sep 17 00:00:00 2001 From: Ysobel Date: Thu, 2 Feb 2023 08:49:35 +1100 Subject: [PATCH 6/6] . --- cpp/visualmesh/visualmesh.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/visualmesh/visualmesh.hpp b/cpp/visualmesh/visualmesh.hpp index f8539c8..85d7da8 100644 --- a/cpp/visualmesh/visualmesh.hpp +++ b/cpp/visualmesh/visualmesh.hpp @@ -133,7 +133,7 @@ class VisualMesh { return std::abs(it->first - height) < std::abs(std::prev(it)->first - height) ? it->second : std::prev(it)->second; } - + // /** * Performs a visual mesh lookup using the description of the lens provided to find visual mesh points on the image. *