From f1d9157e1196ab3043308a8f9d15e4a91ec31fb6 Mon Sep 17 00:00:00 2001 From: thawn Date: Thu, 1 Dec 2022 22:08:34 +0100 Subject: [PATCH 1/6] extend documentation: add_new_kernel --- docs/add_new_kernel/add_new_kernel.md | 129 ++++++++++++++++++++++++-- 1 file changed, 121 insertions(+), 8 deletions(-) diff --git a/docs/add_new_kernel/add_new_kernel.md b/docs/add_new_kernel/add_new_kernel.md index 7a07deada..b47fce6c4 100644 --- a/docs/add_new_kernel/add_new_kernel.md +++ b/docs/add_new_kernel/add_new_kernel.md @@ -1,12 +1,12 @@ # Add new kernel to CLIc -All kernel operation in CLIc must inherite from the `Operation` class which define all the major functions needed for running an OpenCL kernel, and must have a valid kernel file `.cl` associated to it. The `Operation` class is defined in [`clic/include/core/cleOperation.hpp`](https://github.com/clEsperanto/CLIc_prototype/blob/master/clic/include/core/cleOperation.hpp) and the source code is in [`clic/src/core/cleOperation.cpp`](https://github.com/clEsperanto/CLIc_prototype/blob/master/clic/src/core/cleOperation.cpp). The kernel files are located in [clij-opencl-kernels](https://github.com/clEsperanto/clij-opencl-kernels/tree/clesperanto_kernels) repository. +All kernel speranto in CLIc must inherite from the `speranto` class which define all the major functions needed for running an OpenCL kernel, and must have a valid kernel file `.cl` associated to it. The `speranto` class is defined in [`clic/include/core/clesperanto.hpp`](https://github.com/clEsperanto/CLIc_prototype/blob/master/clic/include/core/clesperanto.hpp) and the source code is in [`clic/src/core/clesperanto.cpp`](https://github.com/clEsperanto/CLIc_prototype/blob/master/clic/src/core/clesperanto.cpp). The kernel files are located in [clij-opencl-kernels](https://github.com/clEsperanto/clij-opencl-kernels/tree/clesperanto_kernels) repository. ## Define a new kernel class -The first step is to define a new class inheriting from `Operation` class, by creating a header file (`.hpp`) and a source file (`.cpp`). The class name must correspond to the kernel name. For example, the `AddImageAndScalarKernel` kernel is defined in [`clic/include/tier1/cleAddImageAndScalarKernel.hpp`]() and the source code is in [`clic/src/tier1/cleAddImageAndScalarKernel.cpp`](). +The first step is to define a new class inheriting from `speranto` class, by creating a header file (`.hpp`) and a source file (`.cpp`). The class name must correspond to the kernel name. For example, the `AddImageAndScalarKernel` kernel is defined in [`clic/include/tier1/cleAddImageAndScalarKernel.hpp`]() and the source code is in [`clic/src/tier1/cleAddImageAndScalarKernel.cpp`](). -The operations are grouped in different tiers, defining their complexity. The `tier1` operations are the most basic operations, the `tier2` operations are more complex operations which rely on some `tier1` operations. The `tier3` operations rely a minima on a `tier2` operation. The `tier4` on `tier3` and so on. +The sperantos are grouped in different tiers, defining their complexity. The `tier1` sperantos are the most basic sperantos, the `tier2` sperantos are more complex sperantos which rely on some `tier1` sperantos. The `tier3` sperantos rely a minima on a `tier2` speranto. The `tier4` on `tier3` and so on. ### __Header file__ @@ -18,13 +18,13 @@ First we declare the `AddImageAndScalarKernel` class in a header (`.hpp`) file a #ifndef __TIER1_CLEADDIMAGEANDSCALARKERNEL_HPP // <-- include guard #define __TIER1_CLEADDIMAGEANDSCALARKERNEL_HPP // -#include "cleOperation.hpp" // <-- include the Operation class +#include "clesperanto.hpp" // <-- include the speranto class namespace cle // <-- namespace cle { -class AddImageAndScalarKernel : public Operation // <-- kernel class which inherit -{ // from Operation class +class AddImageAndScalarKernel : public speranto // <-- kernel class which inherit +{ // from speranto class public: /* my class methods */ } @@ -87,7 +87,7 @@ From the header file previously created we can see that the `AddImageAndScalarKe The constructor is defined as follow: ```cpp AddImageAndScalarKernel::AddImageAndScalarKernel(const ProcessorPointer & device) : - Operation(device, 3) + speranto(device, 3) { std::string cl_header = { #include "cle_add_image_and_scalar.h" @@ -95,7 +95,7 @@ AddImageAndScalarKernel::AddImageAndScalarKernel(const ProcessorPointer & device this->SetSource("add_image_and_scalar", cl_header); } ``` -This is the most complex methods we will declare for now. The constructor is called when we instanciate the kernel class. To do so we first rely on the mother class `Operation` constructor whic takes two arguments: the `device` on which the kernel will run and the number of arguments of the kernel. In this case we have three arguments: the input image, the output image and the scalar value. Then, to finish the constructor, we need to provide the kernel source code. This is done by calling the `SetSource` method which takes two arguments: the kernel name as it is name in the OpenCL code and the kernel source file. The kernel source file is stored in a string variable `cl_header` which is defined by including a stringify version of the kernel file `.cl`. This assume that the kernel to be compiled is located in the `clij-opencl-kernels` repository. +This is the most complex methods we will declare for now. The constructor is called when we instanciate the kernel class. To do so we first rely on the mother class `speranto` constructor whic takes two arguments: the `device` on which the kernel will run and the number of arguments of the kernel. In this case we have three arguments: the input image, the output image and the scalar value. Then, to finish the constructor, we need to provide the kernel source code. This is done by calling the `SetSource` method which takes two arguments: the kernel name as it is name in the OpenCL code and the kernel source file. The kernel source file is stored in a string variable `cl_header` which is defined by including a stringify version of the kernel file `.cl`. This assume that the kernel to be compiled is located in the `clij-opencl-kernels` repository. Once the constructor is done, we can declare the `SetInput` and `SetOutput` functions as follow: ```cpp @@ -141,3 +141,116 @@ In addition to simplying kernel call, it enable simple python wrapper for the `p ### __Summary__ We have now a fully implemented kernel class in the CLIc library. The next step is to make the kernel accessible to the user by adding a new method to the `Clesperanto` class gateway and to provide a valid test case to insure that the kernel is working as expected. + +## Add a new method to the `Clesperanto` class gateway + +In order to make the new kernel accessible to the user, we need to add a new method to the `Clesperanto` class gateway. +The `Clesperanto` class is defined in [`clic/include/core/clesperanto.hpp`](https://github.com/clEsperanto/CLIc_prototype/blob/master/clic/include/core/clesperanto.hpp) and the source code is in [`clic/src/core/clesperanto.cpp`](https://github.com/clEsperanto/CLIc_prototype/blob/master/clic/src/core/clesperanto.cpp). + +### Modify the header file + +Add the new kernel as a method to the header (`clic/include/core/clesperanto.hpp`): +```cpp + auto + AddImageAndScalar(const Image & source, const Image & destination, const float & scalar = 0) -> void; +``` + +### Modify the source file + +And call `AddImageAndScalarKernel_Call` from within this method in (`clic/src/core/clesperanto.cpp`): +```cpp +auto +Clesperanto::AddImageAndScalar(const Image & source, const Image & destination, const float & scalar) -> void +{ + AddImageAndScalarKernel_Call(this->GetDevice(), source, destination, scalar); +} +``` + +## Add a valid test case + +In order to ensure that the kernel is working as expected, write a test case and register it in `tests/CMakeLists.txt`. + +### Write a test case + +In this example, add `tests/add_image_and_scalar_test.cpp`. In order to be able to generate random test data, we include ``. Obviously, we also need to include `clesperanto.hpp`. + +```cpp +#include + +#include "clesperanto.hpp" + +template +auto +``` +The test routine itself is defined in `run_test`, which accepts two parameters: `shape` and `mem_type`. In this case, the test routine simply tests whether the kernel manages to add a scalar (10) to a constant vector filled with the value 10. + +```cpp +run_test(const std::array & shape, const cle::MemoryType & mem_type) -> bool +{ + const type value = 10; + const type scalar = 10; + std::vector input(shape[0] * shape[1] * shape[2]); + std::vector valid(shape[0] * shape[1] * shape[2]); + std::fill(input.begin(), input.end(), static_cast(value)); + std::fill(valid.begin(), valid.end(), static_cast(value + scalar)); + + cle::Clesperanto cle; + cle.GetDevice()->WaitForKernelToFinish(); + auto gpu_input = cle.Push(input, shape, mem_type); + auto gpu_output = cle.Create(shape, mem_type); + cle.AddImageAndScalar(gpu_input, gpu_output, scalar); + auto output = cle.Pull(gpu_output); + + return std::equal(output.begin(), output.end(), valid.begin()); +} +``` +The main function executes `run_test` with vectors of various shapes: +```cpp +auto +main(int argc, char ** argv) -> int +{ + if (!run_test({ 10, 1, 1 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } + + if (!run_test({ 10, 1, 1 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } +\\ many more different shapes are tested +} +``` + +### Register the test + +In `tests/CMakeLists.txt`, we need to register the text in three places: + +In the beginning, we register the executable, its dependencies and define targets: +```makefile +add_executable(add_image_and_scalar_test add_image_and_scalar_test.cpp) +add_dependencies(add_image_and_scalar_test CLIc) +target_link_libraries(add_image_and_scalar_test PRIVATE CLIc::CLIc) +set_target_properties(add_image_and_scalar_test PROPERTIES FOLDER "Tests") +target_compile_features(add_image_and_scalar_test PRIVATE cxx_std_17) +``` +below that, we add the test: +```makefile +add_test(NAME add_image_and_scalar_test WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMAND add_image_and_scalar_test) +``` +finally, we have to pass the test to the `set_tests_properties` function: +```makefile +set_tests_properties( + [...] + add_image_and_scalar_test + [...] +) +``` + +### Verify that the test is working + +Now you can [build the binaries as described in the documentation](https://github.com/clEsperanto/CLIc_prototype/blob/master/docs/guidelines.md#source-compilation). + +If the compilation succeeds, you can find your compiled test case in `build/tests/add_image_and_scalar_test` + +Execute it and make sure it runs without errors. \ No newline at end of file From d36db3822ab8611f712efec0c0611791171c0bf5 Mon Sep 17 00:00:00 2001 From: thawn Date: Thu, 1 Dec 2022 22:15:40 +0100 Subject: [PATCH 2/6] reverted some accidental changes --- docs/add_new_kernel/add_new_kernel.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/add_new_kernel/add_new_kernel.md b/docs/add_new_kernel/add_new_kernel.md index b47fce6c4..97ff8841b 100644 --- a/docs/add_new_kernel/add_new_kernel.md +++ b/docs/add_new_kernel/add_new_kernel.md @@ -1,12 +1,12 @@ # Add new kernel to CLIc -All kernel speranto in CLIc must inherite from the `speranto` class which define all the major functions needed for running an OpenCL kernel, and must have a valid kernel file `.cl` associated to it. The `speranto` class is defined in [`clic/include/core/clesperanto.hpp`](https://github.com/clEsperanto/CLIc_prototype/blob/master/clic/include/core/clesperanto.hpp) and the source code is in [`clic/src/core/clesperanto.cpp`](https://github.com/clEsperanto/CLIc_prototype/blob/master/clic/src/core/clesperanto.cpp). The kernel files are located in [clij-opencl-kernels](https://github.com/clEsperanto/clij-opencl-kernels/tree/clesperanto_kernels) repository. +All kernel operation in CLIc must inherite from the `Operation` class which define all the major functions needed for running an OpenCL kernel, and must have a valid kernel file `.cl` associated to it. The `Operation` class is defined in [`clic/include/core/cleOperation.hpp`](https://github.com/clEsperanto/CLIc_prototype/blob/master/clic/include/core/cleOperation.hpp) and the source code is in [`clic/src/core/cleOperation.cpp`](https://github.com/clEsperanto/CLIc_prototype/blob/master/clic/src/core/cleOperation.cpp). The kernel files are located in [clij-opencl-kernels](https://github.com/clEsperanto/clij-opencl-kernels/tree/clesperanto_kernels) repository. ## Define a new kernel class -The first step is to define a new class inheriting from `speranto` class, by creating a header file (`.hpp`) and a source file (`.cpp`). The class name must correspond to the kernel name. For example, the `AddImageAndScalarKernel` kernel is defined in [`clic/include/tier1/cleAddImageAndScalarKernel.hpp`]() and the source code is in [`clic/src/tier1/cleAddImageAndScalarKernel.cpp`](). +The first step is to define a new class inheriting from `Operation` class, by creating a header file (`.hpp`) and a source file (`.cpp`). The class name must correspond to the kernel name. For example, the `AddImageAndScalarKernel` kernel is defined in [`clic/include/tier1/cleAddImageAndScalarKernel.hpp`]() and the source code is in [`clic/src/tier1/cleAddImageAndScalarKernel.cpp`](). -The sperantos are grouped in different tiers, defining their complexity. The `tier1` sperantos are the most basic sperantos, the `tier2` sperantos are more complex sperantos which rely on some `tier1` sperantos. The `tier3` sperantos rely a minima on a `tier2` speranto. The `tier4` on `tier3` and so on. +The operations are grouped in different tiers, defining their complexity. The `tier1` operations are the most basic operations, the `tier2` operations are more complex operations which rely on some `tier1` operations. The `tier3` operations rely a minima on a `tier2` operation. The `tier4` on `tier3` and so on. ### __Header file__ @@ -18,13 +18,13 @@ First we declare the `AddImageAndScalarKernel` class in a header (`.hpp`) file a #ifndef __TIER1_CLEADDIMAGEANDSCALARKERNEL_HPP // <-- include guard #define __TIER1_CLEADDIMAGEANDSCALARKERNEL_HPP // -#include "clesperanto.hpp" // <-- include the speranto class +#include "cleOperation.hpp" // <-- include the Operation class namespace cle // <-- namespace cle { -class AddImageAndScalarKernel : public speranto // <-- kernel class which inherit -{ // from speranto class +class AddImageAndScalarKernel : public Operation // <-- kernel class which inherit +{ // from Operation class public: /* my class methods */ } @@ -87,7 +87,7 @@ From the header file previously created we can see that the `AddImageAndScalarKe The constructor is defined as follow: ```cpp AddImageAndScalarKernel::AddImageAndScalarKernel(const ProcessorPointer & device) : - speranto(device, 3) + Operation(device, 3) { std::string cl_header = { #include "cle_add_image_and_scalar.h" @@ -95,7 +95,7 @@ AddImageAndScalarKernel::AddImageAndScalarKernel(const ProcessorPointer & device this->SetSource("add_image_and_scalar", cl_header); } ``` -This is the most complex methods we will declare for now. The constructor is called when we instanciate the kernel class. To do so we first rely on the mother class `speranto` constructor whic takes two arguments: the `device` on which the kernel will run and the number of arguments of the kernel. In this case we have three arguments: the input image, the output image and the scalar value. Then, to finish the constructor, we need to provide the kernel source code. This is done by calling the `SetSource` method which takes two arguments: the kernel name as it is name in the OpenCL code and the kernel source file. The kernel source file is stored in a string variable `cl_header` which is defined by including a stringify version of the kernel file `.cl`. This assume that the kernel to be compiled is located in the `clij-opencl-kernels` repository. +This is the most complex methods we will declare for now. The constructor is called when we instanciate the kernel class. To do so we first rely on the mother class `Operation` constructor whic takes two arguments: the `device` on which the kernel will run and the number of arguments of the kernel. In this case we have three arguments: the input image, the output image and the scalar value. Then, to finish the constructor, we need to provide the kernel source code. This is done by calling the `SetSource` method which takes two arguments: the kernel name as it is name in the OpenCL code and the kernel source file. The kernel source file is stored in a string variable `cl_header` which is defined by including a stringify version of the kernel file `.cl`. This assume that the kernel to be compiled is located in the `clij-opencl-kernels` repository. Once the constructor is done, we can declare the `SetInput` and `SetOutput` functions as follow: ```cpp From d13f382b94c05dcab1d3af04a28ae521a44ede4e Mon Sep 17 00:00:00 2001 From: thawn Date: Thu, 1 Dec 2022 22:17:12 +0100 Subject: [PATCH 3/6] fixed typo --- docs/add_new_kernel/add_new_kernel.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/add_new_kernel/add_new_kernel.md b/docs/add_new_kernel/add_new_kernel.md index 97ff8841b..f03fb5a7e 100644 --- a/docs/add_new_kernel/add_new_kernel.md +++ b/docs/add_new_kernel/add_new_kernel.md @@ -1,6 +1,6 @@ # Add new kernel to CLIc -All kernel operation in CLIc must inherite from the `Operation` class which define all the major functions needed for running an OpenCL kernel, and must have a valid kernel file `.cl` associated to it. The `Operation` class is defined in [`clic/include/core/cleOperation.hpp`](https://github.com/clEsperanto/CLIc_prototype/blob/master/clic/include/core/cleOperation.hpp) and the source code is in [`clic/src/core/cleOperation.cpp`](https://github.com/clEsperanto/CLIc_prototype/blob/master/clic/src/core/cleOperation.cpp). The kernel files are located in [clij-opencl-kernels](https://github.com/clEsperanto/clij-opencl-kernels/tree/clesperanto_kernels) repository. +All kernel operations in CLIc must inherite from the `Operation` class which define all the major functions needed for running an OpenCL kernel, and must have a valid kernel file `.cl` associated to it. The `Operation` class is defined in [`clic/include/core/cleOperation.hpp`](https://github.com/clEsperanto/CLIc_prototype/blob/master/clic/include/core/cleOperation.hpp) and the source code is in [`clic/src/core/cleOperation.cpp`](https://github.com/clEsperanto/CLIc_prototype/blob/master/clic/src/core/cleOperation.cpp). The kernel files are located in [clij-opencl-kernels](https://github.com/clEsperanto/clij-opencl-kernels/tree/clesperanto_kernels) repository. ## Define a new kernel class From b48bcb574a41143071afd8c1d4e738ba16165483 Mon Sep 17 00:00:00 2001 From: thawn Date: Fri, 2 Dec 2022 12:28:57 +0100 Subject: [PATCH 4/6] split add_new_kernel.md into two files --- docs/add_new_kernel/add_new_kernel.md | 91 +-------------------------- docs/add_new_kernel/add_test_case.md | 88 ++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 88 deletions(-) create mode 100644 docs/add_new_kernel/add_test_case.md diff --git a/docs/add_new_kernel/add_new_kernel.md b/docs/add_new_kernel/add_new_kernel.md index f03fb5a7e..f403a6d82 100644 --- a/docs/add_new_kernel/add_new_kernel.md +++ b/docs/add_new_kernel/add_new_kernel.md @@ -140,7 +140,7 @@ In addition to simplying kernel call, it enable simple python wrapper for the `p ### __Summary__ -We have now a fully implemented kernel class in the CLIc library. The next step is to make the kernel accessible to the user by adding a new method to the `Clesperanto` class gateway and to provide a valid test case to insure that the kernel is working as expected. +We have now a fully implemented kernel class in the CLIc library. The next step is to make the kernel accessible to the user by adding a new method to the `Clesperanto` class gateway. ## Add a new method to the `Clesperanto` class gateway @@ -166,91 +166,6 @@ Clesperanto::AddImageAndScalar(const Image & source, const Image & destination, } ``` -## Add a valid test case - -In order to ensure that the kernel is working as expected, write a test case and register it in `tests/CMakeLists.txt`. - -### Write a test case - -In this example, add `tests/add_image_and_scalar_test.cpp`. In order to be able to generate random test data, we include ``. Obviously, we also need to include `clesperanto.hpp`. - -```cpp -#include - -#include "clesperanto.hpp" - -template -auto -``` -The test routine itself is defined in `run_test`, which accepts two parameters: `shape` and `mem_type`. In this case, the test routine simply tests whether the kernel manages to add a scalar (10) to a constant vector filled with the value 10. - -```cpp -run_test(const std::array & shape, const cle::MemoryType & mem_type) -> bool -{ - const type value = 10; - const type scalar = 10; - std::vector input(shape[0] * shape[1] * shape[2]); - std::vector valid(shape[0] * shape[1] * shape[2]); - std::fill(input.begin(), input.end(), static_cast(value)); - std::fill(valid.begin(), valid.end(), static_cast(value + scalar)); - - cle::Clesperanto cle; - cle.GetDevice()->WaitForKernelToFinish(); - auto gpu_input = cle.Push(input, shape, mem_type); - auto gpu_output = cle.Create(shape, mem_type); - cle.AddImageAndScalar(gpu_input, gpu_output, scalar); - auto output = cle.Pull(gpu_output); - - return std::equal(output.begin(), output.end(), valid.begin()); -} -``` -The main function executes `run_test` with vectors of various shapes: -```cpp -auto -main(int argc, char ** argv) -> int -{ - if (!run_test({ 10, 1, 1 }, cle::BUFFER)) - { - return EXIT_FAILURE; - } - - if (!run_test({ 10, 1, 1 }, cle::BUFFER)) - { - return EXIT_FAILURE; - } -\\ many more different shapes are tested -} -``` - -### Register the test - -In `tests/CMakeLists.txt`, we need to register the text in three places: - -In the beginning, we register the executable, its dependencies and define targets: -```makefile -add_executable(add_image_and_scalar_test add_image_and_scalar_test.cpp) -add_dependencies(add_image_and_scalar_test CLIc) -target_link_libraries(add_image_and_scalar_test PRIVATE CLIc::CLIc) -set_target_properties(add_image_and_scalar_test PROPERTIES FOLDER "Tests") -target_compile_features(add_image_and_scalar_test PRIVATE cxx_std_17) -``` -below that, we add the test: -```makefile -add_test(NAME add_image_and_scalar_test WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMAND add_image_and_scalar_test) -``` -finally, we have to pass the test to the `set_tests_properties` function: -```makefile -set_tests_properties( - [...] - add_image_and_scalar_test - [...] -) -``` - -### Verify that the test is working - -Now you can [build the binaries as described in the documentation](https://github.com/clEsperanto/CLIc_prototype/blob/master/docs/guidelines.md#source-compilation). - -If the compilation succeeds, you can find your compiled test case in `build/tests/add_image_and_scalar_test` +### __Summary__ -Execute it and make sure it runs without errors. \ No newline at end of file +Now that the kernel is accessible to the user, it is very important to [**provide a valid test case**](https://github.com/clEsperanto/CLIc_prototype/blob/extend_doc_add_new_kernel/docs/add_new_kernel/add_test_case.md) to insure that the kernel is working as expected. \ No newline at end of file diff --git a/docs/add_new_kernel/add_test_case.md b/docs/add_new_kernel/add_test_case.md new file mode 100644 index 000000000..2509cab2d --- /dev/null +++ b/docs/add_new_kernel/add_test_case.md @@ -0,0 +1,88 @@ +# Add a valid test case + +In order to ensure that the kernel is working as expected, write a test case and register it in `tests/CMakeLists.txt`. + +## Write a test case + +In this example, add `tests/add_image_and_scalar_test.cpp`. In order to be able to generate random test data, we include ``. Obviously, we also need to include `clesperanto.hpp`. + +```cpp +#include + +#include "clesperanto.hpp" + +template +auto +``` +The test routine itself is defined in `run_test`, which accepts two parameters: `shape` and `mem_type`. In this case, the test routine simply tests whether the kernel manages to add a scalar (10) to a constant vector filled with the value 10. + +```cpp +run_test(const std::array & shape, const cle::MemoryType & mem_type) -> bool +{ + const type value = 10; + const type scalar = 10; + std::vector input(shape[0] * shape[1] * shape[2]); + std::vector valid(shape[0] * shape[1] * shape[2]); + std::fill(input.begin(), input.end(), static_cast(value)); + std::fill(valid.begin(), valid.end(), static_cast(value + scalar)); + + cle::Clesperanto cle; + cle.GetDevice()->WaitForKernelToFinish(); + auto gpu_input = cle.Push(input, shape, mem_type); + auto gpu_output = cle.Create(shape, mem_type); + cle.AddImageAndScalar(gpu_input, gpu_output, scalar); + auto output = cle.Pull(gpu_output); + + return std::equal(output.begin(), output.end(), valid.begin()); +} +``` +The main function executes `run_test` with vectors of various shapes: +```cpp +auto +main(int argc, char ** argv) -> int +{ + if (!run_test({ 10, 1, 1 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } + + if (!run_test({ 10, 1, 1 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } +\\ many more different shapes are tested +} +``` + +## Register the test + +In `tests/CMakeLists.txt`, we need to register the text in three places: + +In the beginning, we register the executable, its dependencies and define targets: +```makefile +add_executable(add_image_and_scalar_test add_image_and_scalar_test.cpp) +add_dependencies(add_image_and_scalar_test CLIc) +target_link_libraries(add_image_and_scalar_test PRIVATE CLIc::CLIc) +set_target_properties(add_image_and_scalar_test PROPERTIES FOLDER "Tests") +target_compile_features(add_image_and_scalar_test PRIVATE cxx_std_17) +``` +below that, we add the test: +```makefile +add_test(NAME add_image_and_scalar_test WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMAND add_image_and_scalar_test) +``` +finally, we have to pass the test to the `set_tests_properties` function: +```makefile +set_tests_properties( + [...] + add_image_and_scalar_test + [...] +) +``` + +## Verify that the test is working + +Now you can [build the binaries as described in the documentation](https://github.com/clEsperanto/CLIc_prototype/blob/master/docs/guidelines.md#source-compilation). + +If the compilation succeeds, you can find your compiled test case in `build/tests/add_image_and_scalar_test` + +Execute it and make sure it runs without errors. \ No newline at end of file From 812f7bd24e36b95d94c7660ff152082507e158c6 Mon Sep 17 00:00:00 2001 From: Stephane Rigaud Date: Tue, 6 Dec 2022 11:42:52 +0100 Subject: [PATCH 5/6] remove submodule form install doc --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8aa2a6055..ef49101c2 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Codecov](https://codecov.io/gh/clEsperanto/CLIc_prototype/branch/master/graph/badge.svg?token=QRSZHYDFIF)](https://codecov.io/gh/clEsperanto/CLIc_prototype) [![License](https://img.shields.io/badge/license-BSD-informational)](https://github.com/clEsperanto/CLIc_prototype/blob/master/LICENSE) [![CppStd](https://img.shields.io/badge/cpp--std-c%2B%2B17-blue)](https://en.cppreference.com/w/cpp/17) -[![OpenCL](https://img.shields.io/badge/OpenCL-1.2%20%7C%202.%202%20%7C3.0-green)](https://www.khronos.org/opencl/) +[![OpenCL](https://img.shields.io/badge/OpenCL-1.2%20%7C%202.2%20%7C%203.0-green)](https://www.khronos.org/opencl/) [![Website](https://img.shields.io/website?url=http%3A%2F%2Fclesperanto.net)](http://clesperanto.net) [![GitHub issues](https://img.shields.io/github/issues-raw/clEsperanto/CLIc_prototype)](https://github.com/clEsperanto/CLIc_prototype/issues) [![GitHub stars](https://img.shields.io/github/stars/clEsperanto/CLIc_prototype?style=social)](https://github.com/clEsperanto/CLIc_prototype) @@ -58,8 +58,8 @@ Follow the [installation guide](./docs/guidelines.md) for helps on compilation a Clone the repository and update the submodules ``` -git clone git@github.com:clEsperanto/CLIc_prototype.git CLIc -cd CLIc && git submodule update --init +git clone git@github.com:clEsperanto/CLIc_prototype.git +cd CLIc_prototype ``` Create a build folder and configure cmake to generate the adapted makefile. From 0224382b92260553dd8be035e3fe0a679b5c8987 Mon Sep 17 00:00:00 2001 From: Stephane Rigaud Date: Tue, 6 Dec 2022 11:43:12 +0100 Subject: [PATCH 6/6] update guidline and rearrange foldes --- docs/guidelines.md | 27 ++++-- .../linux_build/configure_cmake.png | Bin .../linux_build/configure_compiler.png | Bin .../linux_build/linux_build.md | 0 .../macos_build/configure_cmake.png | Bin .../macos_build/configure_compiler.png | Bin .../macos_build/macos_build.md | 0 .../{ => how_to_build}/opencl_installation.md | 0 .../windows_build/configure_cmake.png | Bin .../windows_build/configure_compiler.png | Bin .../windows_build/release_build.png | Bin .../windows_build/visual_studio_download.png | Bin .../visual_studio_installation.png | Bin .../windows_build/windows_build.md | 0 docs/how_to_contribute/coding_style.md | 80 ++++++++++++++++++ .../kernel_class_creation.md} | 14 ++- .../kernel_test_case.md} | 4 +- 17 files changed, 110 insertions(+), 15 deletions(-) rename docs/{ => how_to_build}/linux_build/configure_cmake.png (100%) rename docs/{ => how_to_build}/linux_build/configure_compiler.png (100%) rename docs/{ => how_to_build}/linux_build/linux_build.md (100%) rename docs/{ => how_to_build}/macos_build/configure_cmake.png (100%) rename docs/{ => how_to_build}/macos_build/configure_compiler.png (100%) rename docs/{ => how_to_build}/macos_build/macos_build.md (100%) rename docs/{ => how_to_build}/opencl_installation.md (100%) rename docs/{ => how_to_build}/windows_build/configure_cmake.png (100%) rename docs/{ => how_to_build}/windows_build/configure_compiler.png (100%) rename docs/{ => how_to_build}/windows_build/release_build.png (100%) rename docs/{ => how_to_build}/windows_build/visual_studio_download.png (100%) rename docs/{ => how_to_build}/windows_build/visual_studio_installation.png (100%) rename docs/{ => how_to_build}/windows_build/windows_build.md (100%) create mode 100644 docs/how_to_contribute/coding_style.md rename docs/{add_new_kernel/add_new_kernel.md => how_to_contribute/kernel_class_creation.md} (96%) rename docs/{add_new_kernel/add_test_case.md => how_to_contribute/kernel_test_case.md} (96%) diff --git a/docs/guidelines.md b/docs/guidelines.md index 7f185a9f2..e46c85967 100644 --- a/docs/guidelines.md +++ b/docs/guidelines.md @@ -2,24 +2,41 @@ ## Requierements -1. A C++ compiler +1. A C++ compiler (e.g. gcc, clang, msvc) 2. [CMake](https://cmake.org/download/), version 3.20 or higher. 3. [OpenCL](https://www.khronos.org/opencl/) ## OpenCL installation -CLIc rely on both the `FindOpenCL` package provided by CMake to determine the OpenCL library location on the system and the [Khronos OpenCL headers](https://github.com/KhronosGroup/OpenCL-Headers) for compilation. -Please follow the [instruction to install OpenCL](./opencl_installation.md) before considering using CLIc. +CLIc rely on the OpenCL library to operate. The OpenCL library is provided by the vendor of your GPU. Please follow the [instruction to install OpenCL](./how_to_build/opencl_installation.md) before considering using CLIc. ## Source compilation -|[Windows](./windows_build/windows_build.md)|[Linux](./linux_build/linux_build.md)|[MacOS](./macos_build/macos_build.md)| +|[Windows](./how_to_build/windows_build/windows_build.md)|[Linux](./how_to_build/linux_build/linux_build.md)|[MacOS](./how_to_build/macos_build/macos_build.md)| |-|-|-| +## Developpeur guidelines + +All contribution should be done through forks and pull requests. Please follow the [contribution guidelines](./contribution_guidelines.md) to contribute to CLIc. + +Add a new kernels to CLIc: +- Provide an nD opencl kernel to the [clesperanto-kernels](https://github.com/clEsperanto/clij-opencl-kernels/tree/clesperanto_kernels) repository +- Add a new kernel class to CLIc (see [here](./how_to_contribute/kernel_class_creation.md)) + - Create the [header file](./how_to_contribute/kernel_class_creation.md#header) for the new kernel class + - Create the [source file](./how_to_contribute/kernel_class_creation.md#source) for the new kernel class + - Provide a `Call` function and a `Gateway method` to operate the new kernel class (see [here](./how_to_contribute/kernel_class_creation.md#call-and-gateway-access)) +- Add a test case for the new kernel class (see [here](./how_to_contribute/kernel_test_case.md)) + - Create the [source file](./how_to_contribute/kernel_test_case.md#test_source) of the test case + - Add the test case to the [test suite](./how_to_contribute/kernel_test_case.md#test_cmakelist) +- All code should respect the coding style enforced through the use of [clang-format](https://clang.llvm.org/docs/ClangFormat.html). See [here](./how_to_contribute/coding_style.md) for more information. + +If you do not know where to start, you can check the [list of kernels](https://github.com/clEsperanto/CLIc_prototype/issues/120) still missing, and do not hesitate to take contact with use through an issue. + + ## FAQ **WIP** ## More help? -Do not hesitate to create [an issue](https://github.com/clEsperanto/CLIc_prototype/issues) if you are facing un-documented errors or difficulties. \ No newline at end of file +Do not hesitate to create [an issue](https://github.com/clEsperanto/CLIc_prototype/issues) if you are facing un-documented errors or difficulties. Or via the [clEsperanto](https://forum.image.sc/tags/clesperanto) section of the `image.sc` forum. \ No newline at end of file diff --git a/docs/linux_build/configure_cmake.png b/docs/how_to_build/linux_build/configure_cmake.png similarity index 100% rename from docs/linux_build/configure_cmake.png rename to docs/how_to_build/linux_build/configure_cmake.png diff --git a/docs/linux_build/configure_compiler.png b/docs/how_to_build/linux_build/configure_compiler.png similarity index 100% rename from docs/linux_build/configure_compiler.png rename to docs/how_to_build/linux_build/configure_compiler.png diff --git a/docs/linux_build/linux_build.md b/docs/how_to_build/linux_build/linux_build.md similarity index 100% rename from docs/linux_build/linux_build.md rename to docs/how_to_build/linux_build/linux_build.md diff --git a/docs/macos_build/configure_cmake.png b/docs/how_to_build/macos_build/configure_cmake.png similarity index 100% rename from docs/macos_build/configure_cmake.png rename to docs/how_to_build/macos_build/configure_cmake.png diff --git a/docs/macos_build/configure_compiler.png b/docs/how_to_build/macos_build/configure_compiler.png similarity index 100% rename from docs/macos_build/configure_compiler.png rename to docs/how_to_build/macos_build/configure_compiler.png diff --git a/docs/macos_build/macos_build.md b/docs/how_to_build/macos_build/macos_build.md similarity index 100% rename from docs/macos_build/macos_build.md rename to docs/how_to_build/macos_build/macos_build.md diff --git a/docs/opencl_installation.md b/docs/how_to_build/opencl_installation.md similarity index 100% rename from docs/opencl_installation.md rename to docs/how_to_build/opencl_installation.md diff --git a/docs/windows_build/configure_cmake.png b/docs/how_to_build/windows_build/configure_cmake.png similarity index 100% rename from docs/windows_build/configure_cmake.png rename to docs/how_to_build/windows_build/configure_cmake.png diff --git a/docs/windows_build/configure_compiler.png b/docs/how_to_build/windows_build/configure_compiler.png similarity index 100% rename from docs/windows_build/configure_compiler.png rename to docs/how_to_build/windows_build/configure_compiler.png diff --git a/docs/windows_build/release_build.png b/docs/how_to_build/windows_build/release_build.png similarity index 100% rename from docs/windows_build/release_build.png rename to docs/how_to_build/windows_build/release_build.png diff --git a/docs/windows_build/visual_studio_download.png b/docs/how_to_build/windows_build/visual_studio_download.png similarity index 100% rename from docs/windows_build/visual_studio_download.png rename to docs/how_to_build/windows_build/visual_studio_download.png diff --git a/docs/windows_build/visual_studio_installation.png b/docs/how_to_build/windows_build/visual_studio_installation.png similarity index 100% rename from docs/windows_build/visual_studio_installation.png rename to docs/how_to_build/windows_build/visual_studio_installation.png diff --git a/docs/windows_build/windows_build.md b/docs/how_to_build/windows_build/windows_build.md similarity index 100% rename from docs/windows_build/windows_build.md rename to docs/how_to_build/windows_build/windows_build.md diff --git a/docs/how_to_contribute/coding_style.md b/docs/how_to_contribute/coding_style.md new file mode 100644 index 000000000..306fe7e44 --- /dev/null +++ b/docs/how_to_contribute/coding_style.md @@ -0,0 +1,80 @@ +# Coding Style + +## General + +For clarity and consistency, we rely on clang-format to format the code. The [configuration file](../../.clang-format) is located in the root of the repository. It is strongly recommended to use the clang-format plugin for your favorite editor, or to use the command line tool. + +The formatting rules are strongly inspired by the same rules used in the [ITK](https://github.com/InsightSoftwareConsortium/ITK) Library. + +To format the code, run the following command at the root of your repository: + +```bash +clang-format -i -style=file $(find . -name "*.cpp" -or -name "*.hpp") +``` + +If you do not have clang-format, please refer to their [documentations](https://clang.llvm.org/docs/index.html) for installation, or to the following [issue](https://github.com/clEsperanto/CLIc_prototype/issues/116) on how to install it on your computer. + +## Naming + +### Variables + +Variables should be named using `camelCase` convention. For example: + +```cpp +int numberOfIterations = 10; +``` + +### Classes + +Classes should be named using `PascalCase` convention. For example: + +```cpp +class MyClass +{ +}; +``` + +All kernel classes should keep the `Kernel` suffix. For example: + +```cpp +class AddImagesKernel : public Operation +{ +}; +``` + +### Macros + +Macros should be named using `UPPER_CASE` convention. For example: + +```cpp +#define MY_MACRO 10 +``` + +### Constants + +Constants should be named using `UPPER_CASE` convention. For example: + +```cpp +const int MY_CONSTANT = 10; +``` + +### Namespaces + +Namespaces should be named using `lower_case` convention. For example: + +```cpp +namespace my_namespace +{ +} +``` + +Only two namespace are currently used in the library, `cle` and `backend`. Those are to differentiate the library code from the backend code (OpenCL). + +### Files + +Files should be named using the prefix `cle` and the suffix `hpp` or `cpp`. For example: + +```bash +cleAddImagesKernel.hpp +cleAddImagesKernel.cpp +``` diff --git a/docs/add_new_kernel/add_new_kernel.md b/docs/how_to_contribute/kernel_class_creation.md similarity index 96% rename from docs/add_new_kernel/add_new_kernel.md rename to docs/how_to_contribute/kernel_class_creation.md index f403a6d82..1ebb7d4a8 100644 --- a/docs/add_new_kernel/add_new_kernel.md +++ b/docs/how_to_contribute/kernel_class_creation.md @@ -1,4 +1,4 @@ -# Add new kernel to CLIc +# Kernel class creation All kernel operations in CLIc must inherite from the `Operation` class which define all the major functions needed for running an OpenCL kernel, and must have a valid kernel file `.cl` associated to it. The `Operation` class is defined in [`clic/include/core/cleOperation.hpp`](https://github.com/clEsperanto/CLIc_prototype/blob/master/clic/include/core/cleOperation.hpp) and the source code is in [`clic/src/core/cleOperation.cpp`](https://github.com/clEsperanto/CLIc_prototype/blob/master/clic/src/core/cleOperation.cpp). The kernel files are located in [clij-opencl-kernels](https://github.com/clEsperanto/clij-opencl-kernels/tree/clesperanto_kernels) repository. @@ -8,7 +8,7 @@ The first step is to define a new class inheriting from `Operation` class, by cr The operations are grouped in different tiers, defining their complexity. The `tier1` operations are the most basic operations, the `tier2` operations are more complex operations which rely on some `tier1` operations. The `tier3` operations rely a minima on a `tier2` operation. The `tier4` on `tier3` and so on. -### __Header file__ +### __Header file__ First we declare the `AddImageAndScalarKernel` class in a header (`.hpp`) file as follow: @@ -62,7 +62,7 @@ auto SetScalar(const float & scalar) -> void; As you can see the header file only hold declaration of class and methods, no actual code is written here. This is the role of the source file. -### __Source file__ +### __Source file__ For each header file we need to create a corresponding source file (`.cpp`) with the same name. The source file is where the class methods code are defined. ```cpp @@ -120,7 +120,9 @@ auto AddImageAndScalarKernel::SetScalar(const float & scalar) -> void ``` Same as for the `SetInput` and `SetOutput` functions, the `AddParameter` method is called to add the scalar value to the kernel arguments. The `AddParameter` method can be used as well to add also integers. -### __The Kernel Call function__ +### __Call function and Gateway methaod__ + +## __The Kernel Call function__ The last step to finalise the class if to declare the `Call` function. This function is the one that will be called to run the kernel. It is named identically as the class with the prefix `_Call` and is defined in the header file as an `inline` function. The `inline` keyword is used to tell the compiler to copy the function code at the place where the function is called. This is done to avoid the overhead of calling a function. The `inline` keyword is not mandatory but it is recommended to use it for the `Call` function. @@ -138,10 +140,6 @@ inline auto AddImageAndScalarKernel_Call(const ProcessorPointer & device, const It allows a quick and simple way to call and run the kernel without having to instanciate the kernel class. The `Call` function takes the same arguments as the kernel class constructor and the `SetInput`, `SetOutput` and `SetScalar` functions. The `Call` function is then responsible to instanciate the kernel class, to set the input and output images and the scalar value and to run the kernel. In addition to simplying kernel call, it enable simple python wrapper for the `pyclesperanto` package. The drowback is that each call of the `Call` function will instanciate a new kernel class. This is not a problem for small kernels but for large kernels it is better to instanciate the kernel class only once and to call the `Execute` method multiple times. -### __Summary__ - -We have now a fully implemented kernel class in the CLIc library. The next step is to make the kernel accessible to the user by adding a new method to the `Clesperanto` class gateway. - ## Add a new method to the `Clesperanto` class gateway In order to make the new kernel accessible to the user, we need to add a new method to the `Clesperanto` class gateway. diff --git a/docs/add_new_kernel/add_test_case.md b/docs/how_to_contribute/kernel_test_case.md similarity index 96% rename from docs/add_new_kernel/add_test_case.md rename to docs/how_to_contribute/kernel_test_case.md index 2509cab2d..408707f04 100644 --- a/docs/add_new_kernel/add_test_case.md +++ b/docs/how_to_contribute/kernel_test_case.md @@ -2,7 +2,7 @@ In order to ensure that the kernel is working as expected, write a test case and register it in `tests/CMakeLists.txt`. -## Write a test case +## Write a test case In this example, add `tests/add_image_and_scalar_test.cpp`. In order to be able to generate random test data, we include ``. Obviously, we also need to include `clesperanto.hpp`. @@ -54,7 +54,7 @@ main(int argc, char ** argv) -> int } ``` -## Register the test +## Register the test In `tests/CMakeLists.txt`, we need to register the text in three places: