From 6fb99c089bcac718909a9ba6d0b253db48f322b7 Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Fri, 28 Aug 2020 18:39:58 +0100 Subject: [PATCH] Added updated docstrings --- docs/CMakeLists.txt | 16 ++-- docs/index.rst | 22 ++++- single_include/kompute/Kompute.hpp | 140 ++++++++++++++++++++++++----- src/Manager.cpp | 6 +- src/Sequence.cpp | 40 ++++++++- src/include/kompute/Algorithm.hpp | 31 ++++++- src/include/kompute/Manager.hpp | 34 ++++++- src/include/kompute/Sequence.hpp | 75 +++++++++++++--- test/TestManager.cpp | 16 +--- test/TestSequence.cpp | 26 ++++++ 10 files changed, 334 insertions(+), 72 deletions(-) create mode 100644 test/TestSequence.cpp diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 163befb87..7e2597621 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -52,16 +52,14 @@ add_custom_target(gensphinx ALL ${SPHINX_SOURCE} ${SPHINX_BUILD} -Dbreathe_projects.Kompute=${DOXYGEN_XML_PATH} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS ${DOXYGEN_INDEX_FILE} + DEPENDS gendoxygen COMMENT "Generating documentation with Sphinx") # For completeness we also copy the output doxygen html files -file(COPY ${DOXYGEN_OUTPUT_DIR}/html/ - DESTINATION ${SPHINX_BUILD}/doxygen/) -#add_custom_target(includedoxygen ALL -# COMMAND ${CMAKE_COMMAND} -# -E copy_directory -# ${DOXYGEN_OUTPUT_DIR}/html/ -# ${SPHINX_BUILD}/doxygen/ -# DEPENDS gensphinx) +add_custom_target(gendocsall ALL + COMMAND ${CMAKE_COMMAND} + -E copy_directory + ${DOXYGEN_OUTPUT_DIR}/html/ + ${SPHINX_BUILD}/doxygen/ + DEPENDS gensphinx) diff --git a/docs/index.rst b/docs/index.rst index 7dcb760ed..2f7c8543e 100755 --- a/docs/index.rst +++ b/docs/index.rst @@ -13,24 +13,44 @@ Welcome to Vulkan Kompute's documentation! :caption: Contents: -Docs +Reference ==== +You can also go directoy to the `raw doxygen docs `_ + +Manager +------- + .. doxygenclass:: kp::Manager :members: +Sequence +------- + .. doxygenclass:: kp::Sequence :members: +OpBase +------- + .. doxygenclass:: kp::OpBase :members: +OpMult +------- + .. doxygenclass:: kp::OpMult :members: +OpCreateTensor +------- + .. doxygenclass:: kp::OpCreateTensor :members: +Algorithm +------- + .. doxygenclass:: kp::Algorithm :members: diff --git a/single_include/kompute/Kompute.hpp b/single_include/kompute/Kompute.hpp index c9c01755a..6b0f21246 100755 --- a/single_include/kompute/Kompute.hpp +++ b/single_include/kompute/Kompute.hpp @@ -420,41 +420,85 @@ class OpBase namespace kp { /** - Container of operations that can be sent to GPU as batch -*/ + * Container of operations that can be sent to GPU as batch + */ class Sequence { public: /** - Constructor + * Base constructor for Sequence. Should not be used unless explicit intended. */ Sequence(); + /** + * Main constructor for sequence which requires core vulkan components to generate all dependent resources. + * + * @param physicalDevice Vulkan physical device + * @param device Vulkan logical device + * @param computeQueue Vulkan compute queue + * @param queueIndex Vulkan compute queue index in device + */ Sequence(std::shared_ptr physicalDevice, std::shared_ptr device, std::shared_ptr computeQueue, uint32_t queueIndex); + /** + * Destructor for sequence which is responsible for cleaning all subsequent owned operations. + */ ~Sequence(); - // Initialiser + /** + * Initialises sequence including the creation of the command pool and the command buffer. + */ void init(); - // Record command functions - void begin(); - void end(); - void eval(); + /** + * Begins recording commands for commands to be submitted into the command buffer. + */ + bool begin(); + /** + * Ends the recording and stops recording commands when the record command is sent. + */ + bool end(); + /** + * Eval sends all the recorded and stored operations in the vector of operations into the gpu as a submit job with a barrier. + */ + bool eval(); - // TODO: Explore design without template using just top level class + /** + * Returns true if the sequence is currently in recording activated. + * + * @return Boolean stating if recording ongoing. + */ + bool isRecording(); + + /** + * Returns true if the sequence has been successfully initialised. + * + * @return Boolean stating if sequence has been initialised. + */ + bool isInit(); + + /** + * Record function for operation to be added to the GPU queue in batch. This template requires classes to be derived from the OpBase class. This function also requires the Sequence to be recording, otherwise it will not be able to add the operation. + * + * @param tensors Vector of tensors to use for the operation + */ template - void record(std::vector> tensors) + bool record(std::vector> tensors) { static_assert(std::is_base_of::value, - "Template only valid with OpBase derived classes"); + "Kompute Sequence record(...) template only valid with OpBase derived classes"); SPDLOG_DEBUG("Kompute Sequence record function started"); + if (!this->isRecording()) { + spdlog::error("Kompute sequence record attempted when not record BEGIN"); + return false; + } + SPDLOG_DEBUG("Kompute Sequence creating OpBase derived class instance"); - T* op = new T( - this->mPhysicalDevice, this->mDevice, this->mCommandBuffer, tensors); + T* op = + new T(this->mPhysicalDevice, this->mDevice, this->mCommandBuffer, tensors); OpBase* baseOp = dynamic_cast(op); std::unique_ptr baseOpPtr{ baseOp }; @@ -468,6 +512,8 @@ class Sequence baseOpPtr->record(); mOperations.push_back(std::move(baseOpPtr)); + + return true; } private: @@ -483,7 +529,8 @@ class Sequence // Base op objects std::vector> mOperations; - // Record state + // State + bool mIsInit = false; bool mRecording = false; // Create functions @@ -505,28 +552,54 @@ class Manager private: public: /** - Constructor + Base constructor and default used which creates the base resources including choosing the device 0 by default. */ Manager(); + /** + Similar to base constructor but allows the user to provide the device they would like to create the resources on. + */ Manager(uint32_t physicalDeviceIndex); + /** + * Manager constructor which allows your own vulkan application to integrate with the vulkan kompute use. + * + * @param instance Vulkan compute instance to base this application + * @physicalDevice Vulkan physical device to use for application + * @device Vulkan logical device to use for all base resources + * @physicalDeviceIndex Index for vulkan physical device used + */ Manager(std::shared_ptr instance, std::shared_ptr physicalDevice, std::shared_ptr device, uint32_t physicalDeviceIndex); + /** + * Manager destructor which would ensure all owned resources are destroyed unless explicitly stated that resources should not be destroyed or freed. + */ ~Manager(); - std::weak_ptr getOrCreateManagedSequence(std::string sessionName); + /** + * Get or create a managed Sequence that will be contained by this manager. If the named sequence does not currently exist, it would be created and initialised. + * + * @param sequenceName The name for the named sequence to be retrieved or created + * @return Weak pointer to the manager owned sequence resource + */ + std::weak_ptr getOrCreateManagedSequence(std::string sequenceName); + /** + * Operation that adds extra operations to existing or new created sequences. + * + * @param tensors The tensors to be used in the operation recorded + * @param sequenceName The name of the sequence to be retrieved or created + */ template void evalOp(std::vector> tensors, - std::string sessionName = KP_DEFAULT_SESSION) + std::string sequenceName = KP_DEFAULT_SESSION) { SPDLOG_DEBUG("Kompute Manager evalOp triggered"); std::weak_ptr sqWeakPtr = - this->getOrCreateManagedSequence(sessionName); + this->getOrCreateManagedSequence(sequenceName); if (std::shared_ptr sq = sqWeakPtr.lock()) { SPDLOG_DEBUG("Kompute Manager evalOp running sequence BEGIN"); @@ -574,22 +647,47 @@ class Manager namespace kp { +/** + Abstraction for compute shaders that are run on top of tensors grouped via ParameterGroups (which group descriptorsets) +*/ class Algorithm { public: + /** + Base constructor for Algorithm. Should not be used unless explicit intended. + */ Algorithm(); + /** + * Default constructor for Algorithm + * + * @param device The Vulkan device to use for creating resources + * @param commandBuffer The vulkan command buffer to bind the pipeline and shaders + */ Algorithm(std::shared_ptr device, std::shared_ptr commandBuffer); - // TODO: Add specialisation data - // TODO: Explore other ways of passing shader (ie raw bytes) + /** + * Initialiser for the shader data provided to the algoithm as well as tensor parameters that will be used in shader. + * + * @param shaderFileData The bytes in spir-v format of the shader + * @tensorParams The Tensors to be used in the Algorithm / shader for processing + */ void init(const std::vector& shaderFileData, std::vector> tensorParams); + /** + * Destructor for Algorithm which is responsible for freeing and desroying respective pipelines and owned parameter groups. + */ ~Algorithm(); - // Record commands + /** + * Records the dispatch function with the provided template parameters or alternatively using the size of the tensor by default. + * + * @param x Layout X dispatch value + * @param y Layout Y dispatch value + * @param z Layout Z dispatch value + */ void recordDispatch(uint32_t x = 1, uint32_t y = 1, uint32_t z = 1); private: diff --git a/src/Manager.cpp b/src/Manager.cpp index 469de4dfa..ffa15ee12 100644 --- a/src/Manager.cpp +++ b/src/Manager.cpp @@ -88,11 +88,11 @@ Manager::~Manager() } std::weak_ptr -Manager::getOrCreateManagedSequence(std::string sessionName) +Manager::getOrCreateManagedSequence(std::string sequenceName) { SPDLOG_DEBUG("Kompute Manager creating Sequence object"); std::unordered_map>::iterator found = - this->mManagedSequences.find(sessionName); + this->mManagedSequences.find(sequenceName); if (found == this->mManagedSequences.end()) { std::shared_ptr sq = @@ -101,7 +101,7 @@ Manager::getOrCreateManagedSequence(std::string sessionName) this->mComputeQueue, this->mComputeQueueFamilyIndex); sq->init(); - this->mManagedSequences.insert({ sessionName, sq }); + this->mManagedSequences.insert({ sequenceName, sq }); return sq; } else { return found->second; diff --git a/src/Sequence.cpp b/src/Sequence.cpp index de1376c6a..35a14cf47 100644 --- a/src/Sequence.cpp +++ b/src/Sequence.cpp @@ -6,6 +6,7 @@ namespace kp { Sequence::Sequence() { SPDLOG_DEBUG("Kompute Sequence base constructor"); + this->mIsInit = false; } Sequence::Sequence(std::shared_ptr physicalDevice, @@ -19,6 +20,7 @@ Sequence::Sequence(std::shared_ptr physicalDevice, this->mDevice = device; this->mComputeQueue = computeQueue; this->mQueueIndex = queueIndex; + this->mIsInit = true; } Sequence::~Sequence() @@ -60,11 +62,19 @@ Sequence::init() { this->createCommandPool(); this->createCommandBuffer(); + this->mIsInit = true; } -void +bool Sequence::begin() { + SPDLOG_DEBUG("Kompute sequence called BEGIN"); + + if (this->isRecording()) { + spdlog::warn("Kompute Sequence begin called when already recording"); + return false; + } + if (!this->mCommandPool) { throw std::runtime_error("Kompute Sequence command pool is null"); } @@ -77,11 +87,19 @@ Sequence::begin() spdlog::warn("Kompute Sequence attempted to start command recording " "but recording already started"); } + return true; } -void +bool Sequence::end() { + SPDLOG_DEBUG("Kompute Sequence calling END"); + + if (!this->isRecording()) { + spdlog::warn("Kompute Sequence end called when not recording"); + return false; + } + if (!this->mCommandPool) { throw std::runtime_error("Kompute Sequence command pool is null"); } @@ -94,13 +112,19 @@ Sequence::end() spdlog::warn("Kompute Sequence attempted to end command recording but " "recording not started"); } + return true; } -void +bool Sequence::eval() { SPDLOG_DEBUG("Kompute sequence compute recording EVAL"); + if (this->isRecording()) { + spdlog::warn("Kompute Sequence eval called when still recording"); + return false; + } + const vk::PipelineStageFlags waitStageMask = vk::PipelineStageFlagBits::eTransfer; vk::SubmitInfo submitInfo( @@ -122,6 +146,16 @@ Sequence::eval() } SPDLOG_DEBUG("Kompute sequence EVAL success"); + + return true; +} + +bool Sequence::isRecording() { + return this->mRecording; +} + +bool Sequence::isInit() { + return this->mIsInit; } void diff --git a/src/include/kompute/Algorithm.hpp b/src/include/kompute/Algorithm.hpp index f4ed71ca6..846525fb1 100644 --- a/src/include/kompute/Algorithm.hpp +++ b/src/include/kompute/Algorithm.hpp @@ -6,22 +6,47 @@ namespace kp { +/** + Abstraction for compute shaders that are run on top of tensors grouped via ParameterGroups (which group descriptorsets) +*/ class Algorithm { public: + /** + Base constructor for Algorithm. Should not be used unless explicit intended. + */ Algorithm(); + /** + * Default constructor for Algorithm + * + * @param device The Vulkan device to use for creating resources + * @param commandBuffer The vulkan command buffer to bind the pipeline and shaders + */ Algorithm(std::shared_ptr device, std::shared_ptr commandBuffer); - // TODO: Add specialisation data - // TODO: Explore other ways of passing shader (ie raw bytes) + /** + * Initialiser for the shader data provided to the algoithm as well as tensor parameters that will be used in shader. + * + * @param shaderFileData The bytes in spir-v format of the shader + * @tensorParams The Tensors to be used in the Algorithm / shader for processing + */ void init(const std::vector& shaderFileData, std::vector> tensorParams); + /** + * Destructor for Algorithm which is responsible for freeing and desroying respective pipelines and owned parameter groups. + */ ~Algorithm(); - // Record commands + /** + * Records the dispatch function with the provided template parameters or alternatively using the size of the tensor by default. + * + * @param x Layout X dispatch value + * @param y Layout Y dispatch value + * @param z Layout Z dispatch value + */ void recordDispatch(uint32_t x = 1, uint32_t y = 1, uint32_t z = 1); private: diff --git a/src/include/kompute/Manager.hpp b/src/include/kompute/Manager.hpp index baf705260..797f84107 100644 --- a/src/include/kompute/Manager.hpp +++ b/src/include/kompute/Manager.hpp @@ -18,28 +18,54 @@ class Manager private: public: /** - Constructor + Base constructor and default used which creates the base resources including choosing the device 0 by default. */ Manager(); + /** + Similar to base constructor but allows the user to provide the device they would like to create the resources on. + */ Manager(uint32_t physicalDeviceIndex); + /** + * Manager constructor which allows your own vulkan application to integrate with the vulkan kompute use. + * + * @param instance Vulkan compute instance to base this application + * @physicalDevice Vulkan physical device to use for application + * @device Vulkan logical device to use for all base resources + * @physicalDeviceIndex Index for vulkan physical device used + */ Manager(std::shared_ptr instance, std::shared_ptr physicalDevice, std::shared_ptr device, uint32_t physicalDeviceIndex); + /** + * Manager destructor which would ensure all owned resources are destroyed unless explicitly stated that resources should not be destroyed or freed. + */ ~Manager(); - std::weak_ptr getOrCreateManagedSequence(std::string sessionName); + /** + * Get or create a managed Sequence that will be contained by this manager. If the named sequence does not currently exist, it would be created and initialised. + * + * @param sequenceName The name for the named sequence to be retrieved or created + * @return Weak pointer to the manager owned sequence resource + */ + std::weak_ptr getOrCreateManagedSequence(std::string sequenceName); + /** + * Operation that adds extra operations to existing or new created sequences. + * + * @param tensors The tensors to be used in the operation recorded + * @param sequenceName The name of the sequence to be retrieved or created + */ template void evalOp(std::vector> tensors, - std::string sessionName = KP_DEFAULT_SESSION) + std::string sequenceName = KP_DEFAULT_SESSION) { SPDLOG_DEBUG("Kompute Manager evalOp triggered"); std::weak_ptr sqWeakPtr = - this->getOrCreateManagedSequence(sessionName); + this->getOrCreateManagedSequence(sequenceName); if (std::shared_ptr sq = sqWeakPtr.lock()) { SPDLOG_DEBUG("Kompute Manager evalOp running sequence BEGIN"); diff --git a/src/include/kompute/Sequence.hpp b/src/include/kompute/Sequence.hpp index 71fb404b4..d358d258c 100644 --- a/src/include/kompute/Sequence.hpp +++ b/src/include/kompute/Sequence.hpp @@ -7,41 +7,85 @@ namespace kp { /** - Container of operations that can be sent to GPU as batch -*/ + * Container of operations that can be sent to GPU as batch + */ class Sequence { public: /** - Constructor + * Base constructor for Sequence. Should not be used unless explicit intended. */ Sequence(); + /** + * Main constructor for sequence which requires core vulkan components to generate all dependent resources. + * + * @param physicalDevice Vulkan physical device + * @param device Vulkan logical device + * @param computeQueue Vulkan compute queue + * @param queueIndex Vulkan compute queue index in device + */ Sequence(std::shared_ptr physicalDevice, std::shared_ptr device, std::shared_ptr computeQueue, uint32_t queueIndex); + /** + * Destructor for sequence which is responsible for cleaning all subsequent owned operations. + */ ~Sequence(); - // Initialiser + /** + * Initialises sequence including the creation of the command pool and the command buffer. + */ void init(); - // Record command functions - void begin(); - void end(); - void eval(); + /** + * Begins recording commands for commands to be submitted into the command buffer. + */ + bool begin(); + /** + * Ends the recording and stops recording commands when the record command is sent. + */ + bool end(); + /** + * Eval sends all the recorded and stored operations in the vector of operations into the gpu as a submit job with a barrier. + */ + bool eval(); - // TODO: Explore design without template using just top level class + /** + * Returns true if the sequence is currently in recording activated. + * + * @return Boolean stating if recording ongoing. + */ + bool isRecording(); + + /** + * Returns true if the sequence has been successfully initialised. + * + * @return Boolean stating if sequence has been initialised. + */ + bool isInit(); + + /** + * Record function for operation to be added to the GPU queue in batch. This template requires classes to be derived from the OpBase class. This function also requires the Sequence to be recording, otherwise it will not be able to add the operation. + * + * @param tensors Vector of tensors to use for the operation + */ template - void record(std::vector> tensors) + bool record(std::vector> tensors) { static_assert(std::is_base_of::value, - "Template only valid with OpBase derived classes"); + "Kompute Sequence record(...) template only valid with OpBase derived classes"); SPDLOG_DEBUG("Kompute Sequence record function started"); + if (!this->isRecording()) { + spdlog::error("Kompute sequence record attempted when not record BEGIN"); + return false; + } + SPDLOG_DEBUG("Kompute Sequence creating OpBase derived class instance"); - T* op = new T( - this->mPhysicalDevice, this->mDevice, this->mCommandBuffer, tensors); + T* op = + new T(this->mPhysicalDevice, this->mDevice, this->mCommandBuffer, tensors); OpBase* baseOp = dynamic_cast(op); std::unique_ptr baseOpPtr{ baseOp }; @@ -55,6 +99,8 @@ class Sequence baseOpPtr->record(); mOperations.push_back(std::move(baseOpPtr)); + + return true; } private: @@ -70,7 +116,8 @@ class Sequence // Base op objects std::vector> mOperations; - // Record state + // State + bool mIsInit = false; bool mRecording = false; // Create functions diff --git a/test/TestManager.cpp b/test/TestManager.cpp index 475d7ae02..9674cc977 100755 --- a/test/TestManager.cpp +++ b/test/TestManager.cpp @@ -1,22 +1,10 @@ -#if defined(_WIN32) -#pragma comment(linker, "/subsystem:console") -#endif - -// clang-format: SPDLOG_ACTIVE_LEVEL must be defined before spdlog.h import -#if DEBUG -#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG -#endif - -#include - -#include -// clang-format: ranges.h must come after spdlog.h -#include #include "catch2/catch.hpp" #include "kompute/Kompute.hpp" +#include + TEST_CASE("End to end OpMult Flow should execute correctly from manager") { spdlog::info("TEST CASE STARTING"); diff --git a/test/TestSequence.cpp b/test/TestSequence.cpp new file mode 100644 index 000000000..86246d9d2 --- /dev/null +++ b/test/TestSequence.cpp @@ -0,0 +1,26 @@ + +#include "catch2/catch.hpp" + +#include "kompute/Kompute.hpp" + +TEST_CASE("Sequence begin end recording should work as expected") { + kp::Manager mgr; + + std::weak_ptr sqWeakPtr = + mgr.getOrCreateManagedSequence("newSequence"); + + if (std::shared_ptr sq = sqWeakPtr.lock()) { + REQUIRE(sq->eval()); + REQUIRE(!sq->isRecording()); + REQUIRE(sq->begin()); + REQUIRE(sq->isRecording()); + REQUIRE(!sq->begin()); + REQUIRE(sq->isRecording()); + REQUIRE(sq->end()); + REQUIRE(!sq->isRecording()); + REQUIRE(!sq->end()); + REQUIRE(!sq->isRecording()); + REQUIRE(sq->eval()); + } +} +