From 39b051160a9e859ddced8e395f8596127eac6b94 Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Wed, 26 Aug 2020 18:53:50 +0100 Subject: [PATCH] Added base tests for end to end manager functionality --- Makefile | 8 +- single_include/kompute/Kompute.hpp | 95 +++++++++++++----------- test/CMakeLists.txt | 6 +- test/Main.cpp | 114 ----------------------------- test/TestMain.cpp | 26 ++++++- test/TestManager.cpp | 104 ++++++++++++++++++++++++++ test/TestTensor.cpp | 27 ++----- 7 files changed, 199 insertions(+), 181 deletions(-) delete mode 100755 test/Main.cpp create mode 100755 test/TestManager.cpp diff --git a/Makefile b/Makefile index ae645e1f8..510d22266 100755 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ ####### SRC Build Params ####### -CC="/c/Program Files (x86)/Microsoft Visual Studio/2019/Community/MSBuild/Current/Bin/MSBuildTaskHost.exe" +CC="/c/Program Files (x86)/Microsoft Visual Studio/2019/Community/MSBuild/Current/Bin/MSBuild.exe" ####### Shader Build Params ####### @@ -25,6 +25,12 @@ run_cmake: -DCMAKE_EXPORT_COMPILE_COMMANDS=1 \ -G "Visual Studio 16 2019" +build_vs: + $(CC) build/kompute.sln + +run_tests: + ./build/test/Debug/test_kompute.exe + clean_cmake: rm -rf build/ diff --git a/single_include/kompute/Kompute.hpp b/single_include/kompute/Kompute.hpp index 43b22d35c..dd7dc732c 100755 --- a/single_include/kompute/Kompute.hpp +++ b/single_include/kompute/Kompute.hpp @@ -299,10 +299,12 @@ class Sequence std::unique_ptr baseOpPtr{ baseOp }; - SPDLOG_DEBUG("Kompute Sequence running init on OpBase derived class instance"); + SPDLOG_DEBUG( + "Kompute Sequence running init on OpBase derived class instance"); baseOpPtr->init(tensors); - SPDLOG_DEBUG("Kompute Sequence running record on OpBase derived class instance"); + SPDLOG_DEBUG( + "Kompute Sequence running record on OpBase derived class instance"); baseOpPtr->record(); mOperations.push_back(std::move(baseOpPtr)); @@ -345,7 +347,7 @@ class Manager ~Manager(); - Sequence constructSequence(); + std::weak_ptr managedSequence(); template void evalOp(std::vector> tensors) @@ -376,6 +378,9 @@ class Manager uint32_t mComputeQueueFamilyIndex = -1; std::shared_ptr mComputeQueue = nullptr; + // Always owned resources + std::vector> mManagedSequences; + #if DEBUG vk::DebugReportCallbackEXT mDebugReportCallback; vk::DispatchLoaderDynamic mDebugDispatcher; @@ -438,7 +443,6 @@ class Algorithm // Parameters void createParameters(std::vector>& tensorParams); void createDescriptorPool(); - }; } // End namespace kp @@ -498,8 +502,8 @@ OpMult::OpMult() // TODO: Remove physicalDevice from main initialiser template OpMult::OpMult(std::shared_ptr physicalDevice, - std::shared_ptr device, - std::shared_ptr commandBuffer) + std::shared_ptr device, + std::shared_ptr commandBuffer) : OpBase(physicalDevice, device, commandBuffer) { SPDLOG_DEBUG("Kompute OpMult constructor with params"); @@ -511,7 +515,6 @@ template OpMult::~OpMult() { SPDLOG_DEBUG("Kompute OpMult destructor started"); - } template @@ -531,20 +534,24 @@ OpMult::init(std::vector> tensors) this->mTensorRHS = tensors[1]; this->mTensorOutput = tensors[2]; - // The dispatch size is set up based on either explicitly provided template parameters or by default it would take the shape and size of the tensors + // The dispatch size is set up based on either explicitly provided template + // parameters or by default it would take the shape and size of the tensors if (tX > 0) { - // If at least the x value is provided we use mainly the parameters provided + // If at least the x value is provided we use mainly the parameters + // provided this->mX = tX; this->mY = tY > 0 ? tY : 1; this->mZ = tZ > 0 ? tZ : 1; - } - else { + } else { // TODO: Fully support the full size dispatch using size for the shape this->mX = this->mTensorLHS->size(); this->mY = 1; this->mZ = 1; } - spdlog::info("Kompute OpMult dispatch size X: {}, Y: {}, Z: {}", this->mX, this->mY, this->mZ); + spdlog::info("Kompute OpMult dispatch size X: {}, Y: {}, Z: {}", + this->mX, + this->mY, + this->mZ); // TODO: Explore adding a validate function if (!(this->mTensorLHS->isInit() && this->mTensorRHS->isInit() && @@ -570,16 +577,17 @@ OpMult::init(std::vector> tensors) this->mTensorOutputStaging = std::make_shared( this->mTensorOutput->data(), Tensor::TensorTypes::eStaging); - this->mTensorOutputStaging->init(this->mPhysicalDevice, - this->mDevice, - this->mCommandBuffer); + this->mTensorOutputStaging->init( + this->mPhysicalDevice, this->mDevice, this->mCommandBuffer); #if RELEASE std::vector shaderFileData( - shader_data::shaders_glsl_opmult_comp_spv, - shader_data::shaders_glsl_opmult_comp_spv + kp::shader_data::shaders_glsl_opmult_comp_spv_len); + shader_data::shaders_glsl_opmult_comp_spv, + shader_data::shaders_glsl_opmult_comp_spv + + kp::shader_data::shaders_glsl_opmult_comp_spv_len); #else - SPDLOG_DEBUG("Kompute OpMult Running debug loading shaders directly from spirv file"); + SPDLOG_DEBUG( + "Kompute OpMult Running debug loading shaders directly from spirv file"); // TODO: Move to utility function std::string shaderFilePath = "shaders/glsl/opmult.comp.spv"; @@ -592,7 +600,8 @@ OpMult::init(std::vector> tensors) fileStream.read(shaderDataRaw, shaderFileSize); fileStream.close(); - std::vector shaderFileData(shaderDataRaw, shaderDataRaw + shaderFileSize); + std::vector shaderFileData(shaderDataRaw, + shaderDataRaw + shaderFileSize); #endif SPDLOG_DEBUG("Kompute OpMult Initialising algorithm component"); @@ -608,43 +617,43 @@ OpMult::record() // Barrier to ensure the data is finished writing to buffer memory this->mTensorLHS->recordBufferMemoryBarrier( - vk::AccessFlagBits::eHostWrite, - vk::AccessFlagBits::eShaderRead, - vk::PipelineStageFlagBits::eHost, - vk::PipelineStageFlagBits::eComputeShader); + vk::AccessFlagBits::eHostWrite, + vk::AccessFlagBits::eShaderRead, + vk::PipelineStageFlagBits::eHost, + vk::PipelineStageFlagBits::eComputeShader); this->mTensorRHS->recordBufferMemoryBarrier( - vk::AccessFlagBits::eHostWrite, - vk::AccessFlagBits::eShaderRead, - vk::PipelineStageFlagBits::eHost, - vk::PipelineStageFlagBits::eComputeShader); + vk::AccessFlagBits::eHostWrite, + vk::AccessFlagBits::eShaderRead, + vk::PipelineStageFlagBits::eHost, + vk::PipelineStageFlagBits::eComputeShader); this->mAlgorithm->recordDispatch(this->mX, this->mY, this->mZ); // Barrier to ensure the shader code is executed before buffer read this->mTensorLHS->recordBufferMemoryBarrier( - vk::AccessFlagBits::eShaderWrite, - vk::AccessFlagBits::eTransferRead, - vk::PipelineStageFlagBits::eComputeShader, - vk::PipelineStageFlagBits::eTransfer); + vk::AccessFlagBits::eShaderWrite, + vk::AccessFlagBits::eTransferRead, + vk::PipelineStageFlagBits::eComputeShader, + vk::PipelineStageFlagBits::eTransfer); this->mTensorOutput->recordBufferMemoryBarrier( - vk::AccessFlagBits::eShaderWrite, - vk::AccessFlagBits::eTransferRead, - vk::PipelineStageFlagBits::eComputeShader, - vk::PipelineStageFlagBits::eTransfer); + vk::AccessFlagBits::eShaderWrite, + vk::AccessFlagBits::eTransferRead, + vk::PipelineStageFlagBits::eComputeShader, + vk::PipelineStageFlagBits::eTransfer); this->mTensorOutputStaging->recordCopyFrom(this->mTensorOutput); // Buffer to ensure wait until data is copied to staging buffer this->mTensorLHS->recordBufferMemoryBarrier( - vk::AccessFlagBits::eTransferWrite, - vk::AccessFlagBits::eHostRead, - vk::PipelineStageFlagBits::eTransfer, - vk::PipelineStageFlagBits::eHost); + vk::AccessFlagBits::eTransferWrite, + vk::AccessFlagBits::eHostRead, + vk::PipelineStageFlagBits::eTransfer, + vk::PipelineStageFlagBits::eHost); this->mTensorOutput->recordBufferMemoryBarrier( - vk::AccessFlagBits::eTransferWrite, - vk::AccessFlagBits::eHostRead, - vk::PipelineStageFlagBits::eTransfer, - vk::PipelineStageFlagBits::eHost); + vk::AccessFlagBits::eTransferWrite, + vk::AccessFlagBits::eHostRead, + vk::PipelineStageFlagBits::eTransfer, + vk::PipelineStageFlagBits::eHost); } template diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9a50630fc..6157e1ee4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,7 +1,11 @@ find_package(Catch2 REQUIRED) -add_executable(test_kompute Main.cpp) +file(GLOB test_kompute_CPP + "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp" +) + +add_executable(test_kompute ${test_kompute_CPP}) target_include_directories( test_kompute PUBLIC diff --git a/test/Main.cpp b/test/Main.cpp deleted file mode 100755 index c20dd5045..000000000 --- a/test/Main.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#if defined(_WIN32) -#pragma comment(linker, "/subsystem:console") -#endif - -// SPDLOG_ACTIVE_LEVEL must be defined before spdlog.h import -#if DEBUG -#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG -#endif - -#include - -#include -// ranges.h must come after spdlog.h -#include - -#include -#include - -#include "kompute/Kompute.hpp" - -int -main() -{ -#if DEBUG - spdlog::set_level(spdlog::level::debug); -#else - spdlog::set_level(spdlog::level::info); -#endif - - try { - - // Run Kompute - - { - spdlog::info("Creating manager"); - kp::Manager mgr; - - spdlog::info("Creating first tensor"); - std::shared_ptr tensorLHS{ new kp::Tensor( { 0, 1, 2 }) }; - mgr.evalOp({ tensorLHS }); - - spdlog::info("Creating second tensor"); - std::shared_ptr tensorRHS{ new kp::Tensor( - { 2, 4, 6 }) }; - mgr.evalOp({ tensorRHS }); - - // TODO: Add capabilities for just output tensor types - spdlog::info("Creating output tensor"); - std::shared_ptr tensorOutput{ new kp::Tensor( - { 0, 0, 0 }) }; - mgr.evalOp({ tensorOutput }); - - spdlog::info("OpCreateTensor success for tensors"); - spdlog::info("Tensor one: {}", tensorLHS->data()); - spdlog::info("Tensor two: {}", tensorRHS->data()); - spdlog::info("Tensor output: {}", tensorOutput->data()); - - spdlog::info("Calling op mult"); - mgr.evalOp>({ tensorLHS, tensorRHS, tensorOutput }); - - spdlog::info("OpMult call success"); - spdlog::info("Tensor output: {}", tensorOutput->data()); - - spdlog::info("Called manager eval success END PROGRAM"); - } - { - spdlog::info("Creating manager"); - kp::Manager mgr; - kp::Sequence sq = mgr.constructSequence(); - sq.begin(); - - spdlog::info("Creating first tensor"); - std::shared_ptr tensorLHS{ new kp::Tensor( - { 0, 1, 2 }) }; - - spdlog::info("Creating second tensor"); - std::shared_ptr tensorRHS{ new kp::Tensor( - { 2, 4, 6 }) }; - - // TODO: Add capabilities for just output tensor types - spdlog::info("Creating output tensor"); - std::shared_ptr tensorOutput{ new kp::Tensor( - { 0, 0, 0 }) }; - - sq.record({ tensorLHS }); - sq.record({ tensorRHS }); - sq.record({ tensorOutput }); - - spdlog::info("OpCreateTensor success for tensors"); - spdlog::info("Tensor one: {}", tensorLHS->data()); - spdlog::info("Tensor two: {}", tensorRHS->data()); - spdlog::info("Tensor output: {}", tensorOutput->data()); - - spdlog::info("Calling op mult"); - sq.record>({ tensorLHS, tensorRHS, tensorOutput }); - - sq.end(); - sq.eval(); - - spdlog::info("OpMult call success"); - spdlog::info("Tensor output: {}", tensorOutput->data()); - - spdlog::info("Called manager eval success END PROGRAM"); - } - - return 0; - } catch (const std::exception& exc) { - spdlog::error("Exception caught: {}", exc.what()); - return 1; - } catch (...) { - spdlog::error("Uncaught exception"); - return 1; - } -} diff --git a/test/TestMain.cpp b/test/TestMain.cpp index 6ba5b1ed6..27474ec8d 100644 --- a/test/TestMain.cpp +++ b/test/TestMain.cpp @@ -1,4 +1,28 @@ -#define CATCH_CONFIG_MAIN +#define CATCH_CONFIG_RUNNER + +// clang-format: SPDLOG_ACTIVE_LEVEL must be defined before spdlog.h import +#if DEBUG +#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG +#endif + +#include +// clang-format: ranges.h must come after spdlog.h +#include #include "catch2/catch.hpp" +int main( int argc, char* argv[] ) { + +#if DEBUG + spdlog::set_level(spdlog::level::debug); +#else + spdlog::set_level(spdlog::level::info); +#endif + + int result = Catch::Session().run( argc, argv ); + + // global clean-up... + + return result; +} + diff --git a/test/TestManager.cpp b/test/TestManager.cpp new file mode 100755 index 000000000..8e0b74de4 --- /dev/null +++ b/test/TestManager.cpp @@ -0,0 +1,104 @@ +#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" + +TEST_CASE("End to end OpMult Flow should execute correctly from manager") { + spdlog::info("TEST CASE STARTING"); + + spdlog::info("Creating manager"); + kp::Manager mgr; + + spdlog::info("Creating first tensor"); + std::shared_ptr tensorLHS{ new kp::Tensor( { 0, 1, 2 }) }; + mgr.evalOp({ tensorLHS }); + + spdlog::info("Creating second tensor"); + std::shared_ptr tensorRHS{ new kp::Tensor( + { 2, 4, 6 }) }; + mgr.evalOp({ tensorRHS }); + + // TODO: Add capabilities for just output tensor types + spdlog::info("Creating output tensor"); + std::shared_ptr tensorOutput{ new kp::Tensor( + { 0, 0, 0 }) }; + mgr.evalOp({ tensorOutput }); + + spdlog::info("OpCreateTensor success for tensors"); + spdlog::info("Tensor one: {}", tensorLHS->data()); + spdlog::info("Tensor two: {}", tensorRHS->data()); + spdlog::info("Tensor output: {}", tensorOutput->data()); + + spdlog::info("Calling op mult"); + mgr.evalOp>({ tensorLHS, tensorRHS, tensorOutput }); + + spdlog::info("OpMult call success"); + spdlog::info("Tensor output: {}", tensorOutput->data()); + + REQUIRE(tensorOutput->data() == std::vector{0, 4, 12}); + + spdlog::info("Called manager eval success END PROGRAM"); +} + +TEST_CASE("End to end OpMult Flow should execute correctly from sequence") { + spdlog::info("TEST CASE STARTING"); + + spdlog::info("Creating manager"); + + spdlog::info("Creating first tensor"); + std::shared_ptr tensorLHS{ new kp::Tensor( + { 0, 1, 2 }) }; + + spdlog::info("Creating second tensor"); + std::shared_ptr tensorRHS{ new kp::Tensor( + { 2, 4, 6 }) }; + + // TODO: Add capabilities for just output tensor types + spdlog::info("Creating output tensor"); + std::shared_ptr tensorOutput{ new kp::Tensor( + { 0, 0, 0 }) }; + + kp::Manager mgr; + + std::weak_ptr sq_ref = mgr.managedSequence(); + if (std::shared_ptr sq = sq_ref.lock()) { + sq->begin(); + + sq->record({ tensorLHS }); + sq->record({ tensorRHS }); + sq->record({ tensorOutput }); + + spdlog::info("OpCreateTensor success for tensors"); + spdlog::info("Tensor one: {}", tensorLHS->data()); + spdlog::info("Tensor two: {}", tensorRHS->data()); + spdlog::info("Tensor output: {}", tensorOutput->data()); + + spdlog::info("Calling op mult"); + sq->record>({ tensorLHS, tensorRHS, tensorOutput }); + + sq->end(); + sq->eval(); + } + sq_ref.reset(); + + spdlog::info("OpMult call success"); + spdlog::info("Tensor output: {}", tensorOutput->data()); + + REQUIRE(tensorOutput->data() == std::vector{0, 4, 12}); + + spdlog::info("Called manager eval success END PROGRAM"); +} diff --git a/test/TestTensor.cpp b/test/TestTensor.cpp index d471593cc..8534af072 100644 --- a/test/TestTensor.cpp +++ b/test/TestTensor.cpp @@ -1,25 +1,10 @@ + #include -#include "Tensor.hpp" +#include "kompute/Tensor.hpp" - -int Factorial( int number ) { - return number <= 1 ? number : Factorial( number - 1 ) * number; // fail -// return number <= 1 ? 1 : Factorial( number - 1 ) * number; // pass -} - -TEST_CASE( "Factorial of 0 is 1 (fail)", "[single-file]" ) { - REQUIRE( Factorial(0) == 1 ); -} - -TEST_CASE( "Factorials of 1 and higher are computed (pass)", "[single-file]" ) { - REQUIRE( Factorial(1) == 1 ); - REQUIRE( Factorial(2) == 2 ); - REQUIRE( Factorial(3) == 6 ); - REQUIRE( Factorial(10) == 3628800 ); -} - -TEST_CASE("Exploring if manager test compiles") { - kp::Tensor tensor({0,1,2}); - REQUIRE( tensor.size() == 3 ); +TEST_CASE("Tensor should have same vector as initialised") { + std::vector vec{0,1,2}; + kp::Tensor tensor(vec); + REQUIRE( tensor.data() == vec ); }