Added functionality for named sequences to be created

This commit is contained in:
Alejandro Saucedo 2020-08-28 15:19:39 +01:00
parent c8db55aa1b
commit b91c392f5e
15 changed files with 299 additions and 173 deletions

View file

@ -1,28 +1,26 @@
####### SRC Build Params #######
CC="/c/Program Files (x86)/Microsoft Visual Studio/2019/Community/MSBuild/Current/Bin/MSBuild.exe"
####### Shader Build Params #######
ifeq ($(OS),Windows_NT) # is Windows_NT on XP, 2000, 7, Vista, 10... ifeq ($(OS),Windows_NT) # is Windows_NT on XP, 2000, 7, Vista, 10...
SCMP=C:\VulkanSDK\1.2.141.2\Bin32\glslangValidator.exe CMAKE_BIN ?= "C:\Program Files\CMake\bin\cmake.exe"
SCMP_BIN="C:\\VulkanSDK\\1.2.141.2\\Bin32\\glslangValidator.exe"
MSBUILD_BIN ?= "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\MSBuild\\Current\\Bin\\MSBuild.exe"
VCPKG_CMAKE ?= "C:\\Users\\axsau\\Programming\\lib\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake"
else else
SCMP=/c/VulkanSDK/1.2.141.2/Bin32/glslangValidator.exe CLANG_FORMAT_BIN ?= "/home/alejandro/Programming/lib/clang+llvm-10.0.0-x86_64-linux-gnu-ubuntu-18.04/bin/clang-format"
CMAKE_BIN ?= "/c/Program Files/CMake/bin/cmake.exe"
SCMP_BIN ?= "/c/VulkanSDK/1.2.141.2/Bin32/glslangValidator.exe"
MSBUILD_BIN ?= "/c/Program Files (x86)/Microsoft Visual Studio/2019/Community/MSBuild/Current/Bin/MSBuild.exe"
VCPKG_CMAKE ?= "C:\\Users\\axsau\\Programming\\lib\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake"
endif endif
####### Package manager #######
VCPKG=/c/Users/axsau/Programming/lib/vcpkg/vcpkg
####### Main Target Rules ####### ####### Main Target Rules #######
run_cmake: run_cmake:
cmake \ $(CMAKE_BIN) \
-Bbuild \ -Bbuild \
-DCMAKE_TOOLCHAIN_FILE=C:\\Users\\axsau\\Programming\\lib\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake \ -DCMAKE_TOOLCHAIN_FILE=$(VCPKG_CMAKE) \
-DCMAKE_EXPORT_COMPILE_COMMANDS=1 \ -DCMAKE_EXPORT_COMPILE_COMMANDS=1 \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-G "Visual Studio 16 2019" -G "Visual Studio 16 2019"
push_docs_to_ghpages: push_docs_to_ghpages:
@ -31,10 +29,25 @@ push_docs_to_ghpages:
GIT_DEPLOY_REPO="origin" \ GIT_DEPLOY_REPO="origin" \
./scripts/push_folder_to_branch.sh ./scripts/push_folder_to_branch.sh
build_vs: ####### Visual studio build shortcut commands #######
$(CC) build/kompute.sln
run_tests: build_all:
$(MSBUILD_BIN) build/kompute.sln
build_docs:
$(MSBUILD_BIN) build/docs/gendoxygen.vcxproj
$(MSBUILD_BIN) build/docs/gensphinx.vcxproj
build_kompute:
$(MSBUILD_BIN) build/src/kompute.vcxproj
build_tests:
$(MSBUILD_BIN) build/test/test_kompute.vcxproj
run_docs: build_docs
(cd build/docs/sphinx && python2.7 -m SimpleHTTPServer)
run_tests: build_tests
./build/test/Debug/test_kompute.exe ./build/test/Debug/test_kompute.exe
clean_cmake: clean_cmake:
@ -46,7 +59,7 @@ install_python_reqs:
build_shaders: build_shaders:
python scripts/convert_shaders.py \ python scripts/convert_shaders.py \
--shader-path shaders/glsl \ --shader-path shaders/glsl \
--shader-binary $(SCMP) \ --shader-binary $(SCMP_BIN) \
--header-path src/include/kompute/shaders/ \ --header-path src/include/kompute/shaders/ \
-v -v
@ -85,7 +98,7 @@ build_single_header:
"single_include/kompute/Kompute.hpp" "single_include/kompute/Kompute.hpp"
format: format:
clang-format -i -style="{BasedOnStyle: mozilla, IndentWidth: 4}" src/*.cpp src/include/kompute/*.hpp $(CLANG_FORMAT_BIN) -i -style="{BasedOnStyle: mozilla, IndentWidth: 4}" src/*.cpp src/include/kompute/*.hpp
clean: clean:
find src -name "*gch" -exec rm {} \; || "No ghc files" find src -name "*gch" -exec rm {} \; || "No ghc files"

View file

@ -22,6 +22,9 @@
</tr> </tr>
</table> </table>
🔋 [Documentation]() 💻 [Import to your project]() ⌨ [Tutorials]() 💾
## Principles & Features ## Principles & Features
* Single header easy to import static library * Single header easy to import static library

View file

@ -150,6 +150,8 @@ static unsigned const int shaders_glsl_opmult_comp_spv_len = 1308;
} }
#endif // define SHADEROP_SHADEROPMULT_HPP #endif // define SHADEROP_SHADEROPMULT_HPP
#include <unordered_map>
#define KP_MAX_DIM_SIZE 1 #define KP_MAX_DIM_SIZE 1
namespace kp { namespace kp {
@ -234,42 +236,81 @@ class Tensor
namespace kp { namespace kp {
/** /**
Base Operation * Base Operation which provides the high level interface that Kompute
*/ * operations implement in order to perform a set of actions in the GPU.
*
* Operations can perform actions on tensors, and optionally can also own an
* Algorithm with respective parameters. kp::Operations with kp::Algorithms
* would inherit from kp::OpBaseAlgo.
*/
class OpBase class OpBase
{ {
private:
public: public:
/** /**
Constructor * Base constructor, should not be used unless explicitly intended.
*/ */
OpBase() { SPDLOG_DEBUG("Compute OpBase base constructor"); } OpBase() { SPDLOG_DEBUG("Compute OpBase base constructor"); }
/**
* Default constructor with parameters that provides the bare minimum
* requirements for the operations to be able to create and manage their
* sub-components.
*/
OpBase(std::shared_ptr<vk::PhysicalDevice> physicalDevice, OpBase(std::shared_ptr<vk::PhysicalDevice> physicalDevice,
std::shared_ptr<vk::Device> device, std::shared_ptr<vk::Device> device,
std::shared_ptr<vk::CommandBuffer> commandBuffer) std::shared_ptr<vk::CommandBuffer> commandBuffer,
std::vector<std::shared_ptr<Tensor>>& tensors,
bool freeTensors)
{ {
SPDLOG_DEBUG("Compute OpBase constructor with params"); SPDLOG_DEBUG("Compute OpBase constructor with params");
this->mPhysicalDevice = physicalDevice; this->mPhysicalDevice = physicalDevice;
this->mDevice = device; this->mDevice = device;
this->mCommandBuffer = commandBuffer; this->mCommandBuffer = commandBuffer;
this->mTensors = tensors;
} }
~OpBase() { /**
SPDLOG_DEBUG("Compute OpBase destructor started"); * Default destructor for OpBase class. This OpBase destructor class should
} * always be called to destroy and free owned resources unless it is
* intended to destroy the resources in the parent class. This can be done
virtual void init(std::vector<std::shared_ptr<Tensor>> tensors) * by passing the mFreeTensors=false.
*/
~OpBase()
{ {
SPDLOG_DEBUG("Kompute OpBase init called"); SPDLOG_DEBUG("Kompute OpBase destructor started");
if (!this->mDevice) {
spdlog::warn("Kompute OpBase destructor called with empty device");
return;
}
if (this->mFreeTensors) {
SPDLOG_DEBUG("Kompute OpBase freeing tensors");
for (std::shared_ptr<Tensor> tensor : this->mTensors) {
if (tensor && tensor->isInit()) {
tensor->freeMemoryDestroyGPUResources();
} else {
spdlog::error("Kompute OpBase expected to free "
"tensor but has already been freed.");
}
}
}
} }
virtual void record() { SPDLOG_DEBUG("Kompute OpBase record called"); } virtual void init() = 0;
virtual void postSubmit() { SPDLOG_DEBUG("Kompute OpBase init called"); } virtual void record() = 0;
virtual void postSubmit() = 0;
protected: protected:
// Sometimes owned resources
std::vector<std::shared_ptr<Tensor>> mTensors;
bool mFreeTensors =
false; // TODO: Provide granularity to specify which to free
// Always external resources
std::shared_ptr<vk::PhysicalDevice> mPhysicalDevice; std::shared_ptr<vk::PhysicalDevice> mPhysicalDevice;
std::shared_ptr<vk::Device> mDevice; std::shared_ptr<vk::Device> mDevice;
std::shared_ptr<vk::CommandBuffer> mCommandBuffer; std::shared_ptr<vk::CommandBuffer> mCommandBuffer;
@ -295,6 +336,9 @@ class Sequence
uint32_t queueIndex); uint32_t queueIndex);
~Sequence(); ~Sequence();
// Initialiser
void init();
// Record command functions // Record command functions
void begin(); void begin();
void end(); void end();
@ -310,15 +354,15 @@ class Sequence
SPDLOG_DEBUG("Kompute Sequence record function started"); SPDLOG_DEBUG("Kompute Sequence record function started");
SPDLOG_DEBUG("Kompute Sequence creating OpBase derived class instance"); SPDLOG_DEBUG("Kompute Sequence creating OpBase derived class instance");
T* op = T* op = new T(
new T(this->mPhysicalDevice, this->mDevice, this->mCommandBuffer); this->mPhysicalDevice, this->mDevice, this->mCommandBuffer, tensors);
OpBase* baseOp = dynamic_cast<OpBase*>(op); OpBase* baseOp = dynamic_cast<OpBase*>(op);
std::unique_ptr<OpBase> baseOpPtr{ baseOp }; std::unique_ptr<OpBase> baseOpPtr{ baseOp };
SPDLOG_DEBUG( SPDLOG_DEBUG(
"Kompute Sequence running init on OpBase derived class instance"); "Kompute Sequence running init on OpBase derived class instance");
baseOpPtr->init(tensors); baseOpPtr->init();
SPDLOG_DEBUG( SPDLOG_DEBUG(
"Kompute Sequence running record on OpBase derived class instance"); "Kompute Sequence running record on OpBase derived class instance");
@ -350,6 +394,8 @@ class Sequence
} // End namespace kp } // End namespace kp
#define KP_DEFAULT_SESSION "DEFAULT"
namespace kp { namespace kp {
/** /**
@ -370,28 +416,34 @@ class Manager
~Manager(); ~Manager();
std::weak_ptr<Sequence> managedSequence(); std::weak_ptr<Sequence> getOrCreateManagedSequence(std::string sessionName);
template<typename T, typename... TArgs> template<typename T, typename... TArgs>
void evalOp(std::vector<std::shared_ptr<Tensor>> tensors) void evalOp(std::vector<std::shared_ptr<Tensor>> tensors, std::string sessionName = KP_DEFAULT_SESSION)
{ {
SPDLOG_DEBUG("Kompute Manager evalOp triggered"); SPDLOG_DEBUG("Kompute Manager evalOp triggered");
Sequence sq(this->mPhysicalDevice, std::weak_ptr<Sequence> sqWeakPtr =
this->mDevice, this->getOrCreateManagedSequence(sessionName);
this->mComputeQueue,
this->mComputeQueueFamilyIndex); if (std::shared_ptr<kp::Sequence> sq = sqWeakPtr.lock())
SPDLOG_DEBUG("Kompute Manager evalOp running sequence BEGIN"); {
sq.begin(); SPDLOG_DEBUG("Kompute Manager evalOp running sequence BEGIN");
SPDLOG_DEBUG("Kompute Manager evalOp running sequence RECORD"); sq->begin();
sq.record<T>(tensors);
SPDLOG_DEBUG("Kompute Manager evalOp running sequence END"); SPDLOG_DEBUG("Kompute Manager evalOp running sequence RECORD");
sq.end(); sq->record<T>(tensors);
SPDLOG_DEBUG("Kompute Manager evalOp running sequence EVAL");
sq.eval(); SPDLOG_DEBUG("Kompute Manager evalOp running sequence END");
sq->end();
SPDLOG_DEBUG("Kompute Manager evalOp running sequence EVAL");
sq->eval();
}
SPDLOG_DEBUG("Kompute Manager evalOp running sequence SUCCESS"); SPDLOG_DEBUG("Kompute Manager evalOp running sequence SUCCESS");
} }
private: private:
std::shared_ptr<vk::Instance> mInstance = nullptr; std::shared_ptr<vk::Instance> mInstance = nullptr;
bool mFreeInstance = false; bool mFreeInstance = false;
std::shared_ptr<vk::PhysicalDevice> mPhysicalDevice = nullptr; std::shared_ptr<vk::PhysicalDevice> mPhysicalDevice = nullptr;
@ -402,7 +454,7 @@ class Manager
std::shared_ptr<vk::Queue> mComputeQueue = nullptr; std::shared_ptr<vk::Queue> mComputeQueue = nullptr;
// Always owned resources // Always owned resources
std::vector<std::shared_ptr<Sequence>> mManagedSequences; std::unordered_map<std::string, std::shared_ptr<Sequence>> mManagedSequences;
#if DEBUG #if DEBUG
vk::DebugReportCallbackEXT mDebugReportCallback; vk::DebugReportCallbackEXT mDebugReportCallback;
@ -439,15 +491,16 @@ class Algorithm
void recordDispatch(uint32_t x = 1, uint32_t y = 1, uint32_t z = 1); void recordDispatch(uint32_t x = 1, uint32_t y = 1, uint32_t z = 1);
private: private:
// Shared resources // Never Owned Resources
std::shared_ptr<vk::Device> mDevice; std::shared_ptr<vk::Device> mDevice;
std::shared_ptr<vk::CommandBuffer> mCommandBuffer; std::shared_ptr<vk::CommandBuffer> mCommandBuffer;
// Resources owned by default // Optionally owned resources
std::shared_ptr<vk::DescriptorSetLayout> mDescriptorSetLayout; std::shared_ptr<vk::DescriptorSetLayout> mDescriptorSetLayout;
bool mFreeDescriptorSetLayout = false; bool mFreeDescriptorSetLayout = false;
std::shared_ptr<vk::DescriptorPool> mDescriptorPool; std::shared_ptr<vk::DescriptorPool> mDescriptorPool;
bool mFreeDescriptorPool = false; bool mFreeDescriptorPool = false;
// TODO: Explore design for multiple descriptor sets // TODO: Explore design for multiple descriptor sets
std::shared_ptr<vk::DescriptorSet> mDescriptorSet; std::shared_ptr<vk::DescriptorSet> mDescriptorSet;
bool mFreeDescriptorSet = false; bool mFreeDescriptorSet = false;
@ -463,6 +516,7 @@ class Algorithm
// Create util functions // Create util functions
void createShaderModule(const std::vector<char>& shaderFileData); void createShaderModule(const std::vector<char>& shaderFileData);
void createPipeline(); void createPipeline();
// Parameters // Parameters
void createParameters(std::vector<std::shared_ptr<Tensor>>& tensorParams); void createParameters(std::vector<std::shared_ptr<Tensor>>& tensorParams);
void createDescriptorPool(); void createDescriptorPool();
@ -486,11 +540,13 @@ class OpMult : public OpBase
OpMult(std::shared_ptr<vk::PhysicalDevice> physicalDevice, OpMult(std::shared_ptr<vk::PhysicalDevice> physicalDevice,
std::shared_ptr<vk::Device> device, std::shared_ptr<vk::Device> device,
std::shared_ptr<vk::CommandBuffer> commandBuffer); std::shared_ptr<vk::CommandBuffer> commandBuffer,
std::vector<std::shared_ptr<Tensor>>& tensors,
bool freeTensors = false);
~OpMult(); ~OpMult();
void init(std::vector<std::shared_ptr<Tensor>> tensors) override; void init() override;
void record() override; void record() override;
@ -532,8 +588,10 @@ OpMult<tX, tY, tZ>::OpMult()
template<uint32_t tX, uint32_t tY, uint32_t tZ> template<uint32_t tX, uint32_t tY, uint32_t tZ>
OpMult<tX, tY, tZ>::OpMult(std::shared_ptr<vk::PhysicalDevice> physicalDevice, OpMult<tX, tY, tZ>::OpMult(std::shared_ptr<vk::PhysicalDevice> physicalDevice,
std::shared_ptr<vk::Device> device, std::shared_ptr<vk::Device> device,
std::shared_ptr<vk::CommandBuffer> commandBuffer) std::shared_ptr<vk::CommandBuffer> commandBuffer,
: OpBase(physicalDevice, device, commandBuffer) std::vector<std::shared_ptr<Tensor>>& tensors,
bool freeTensors)
: OpBase(physicalDevice, device, commandBuffer, tensors, freeTensors)
{ {
SPDLOG_DEBUG("Kompute OpMult constructor with params"); SPDLOG_DEBUG("Kompute OpMult constructor with params");
@ -548,20 +606,20 @@ OpMult<tX, tY, tZ>::~OpMult()
template<uint32_t tX, uint32_t tY, uint32_t tZ> template<uint32_t tX, uint32_t tY, uint32_t tZ>
void void
OpMult<tX, tY, tZ>::init(std::vector<std::shared_ptr<Tensor>> tensors) OpMult<tX, tY, tZ>::init()
{ {
SPDLOG_DEBUG("Kompute OpMult init called"); SPDLOG_DEBUG("Kompute OpMult init called");
if (tensors.size() < 3) { if (this->mTensors.size() < 3) {
throw std::runtime_error( throw std::runtime_error(
"Kompute OpMult called with less than 1 tensor"); "Kompute OpMult called with less than 1 tensor");
} else if (tensors.size() > 3) { } else if (this->mTensors.size() > 3) {
spdlog::warn("Kompute OpMult called with more than 3 tensors"); spdlog::warn("Kompute OpMult called with more than 3 this->mTensors");
} }
this->mTensorLHS = tensors[0]; this->mTensorLHS = this->mTensors[0];
this->mTensorRHS = tensors[1]; this->mTensorRHS = this->mTensors[1];
this->mTensorOutput = tensors[2]; this->mTensorOutput = this->mTensors[2];
// The dispatch size is set up based on either explicitly provided template // 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 // parameters or by default it would take the shape and size of the tensors
@ -635,7 +693,7 @@ OpMult<tX, tY, tZ>::init(std::vector<std::shared_ptr<Tensor>> tensors)
SPDLOG_DEBUG("Kompute OpMult Initialising algorithm component"); SPDLOG_DEBUG("Kompute OpMult Initialising algorithm component");
this->mAlgorithm->init(shaderFileData, tensors); this->mAlgorithm->init(shaderFileData, this->mTensors);
} }
template<uint32_t tX, uint32_t tY, uint32_t tZ> template<uint32_t tX, uint32_t tY, uint32_t tZ>
@ -709,21 +767,22 @@ class OpCreateTensor : public OpBase
OpCreateTensor(std::shared_ptr<vk::PhysicalDevice> physicalDevice, OpCreateTensor(std::shared_ptr<vk::PhysicalDevice> physicalDevice,
std::shared_ptr<vk::Device> device, std::shared_ptr<vk::Device> device,
std::shared_ptr<vk::CommandBuffer> commandBuffer); std::shared_ptr<vk::CommandBuffer> commandBuffer,
std::vector<std::shared_ptr<Tensor>>& tensors,
bool freeTensors = true);
~OpCreateTensor(); ~OpCreateTensor();
void init(std::vector<std::shared_ptr<Tensor>> tensors) override; void init() override;
void record() override; void record() override;
void postSubmit() override; void postSubmit() override;
private: private:
// Never owned resources
std::shared_ptr<Tensor> mPrimaryTensor; std::shared_ptr<Tensor> mPrimaryTensor;
bool mFreePrimaryTensorResources = false;
std::shared_ptr<Tensor> mStagingTensor; std::shared_ptr<Tensor> mStagingTensor;
bool mFreeStagingTensorResources = false;
}; };
} // End namespace kp } // End namespace kp

View file

@ -71,16 +71,25 @@ Manager::~Manager()
} }
std::weak_ptr<Sequence> std::weak_ptr<Sequence>
Manager::managedSequence() Manager::getOrCreateManagedSequence(std::string sessionName)
{ {
SPDLOG_DEBUG("Kompute Manager creating Sequence object"); SPDLOG_DEBUG("Kompute Manager creating Sequence object");
std::shared_ptr<Sequence> sq = std::make_shared<Sequence>( std::unordered_map<std::string, std::shared_ptr<Sequence>>::iterator
this->mPhysicalDevice, found = this->mManagedSequences.find(sessionName);
this->mDevice,
this->mComputeQueue, if (found == this->mManagedSequences.end()) {
this->mComputeQueueFamilyIndex); std::shared_ptr<Sequence> sq =
this->mManagedSequences.push_back(sq); std::make_shared<Sequence>(this->mPhysicalDevice,
return sq; this->mDevice,
this->mComputeQueue,
this->mComputeQueueFamilyIndex);
sq->init();
this->mManagedSequences.insert({sessionName, sq});
return sq;
}
else {
return found->second;
}
} }
void void

View file

@ -13,8 +13,10 @@ OpCreateTensor::OpCreateTensor()
OpCreateTensor::OpCreateTensor( OpCreateTensor::OpCreateTensor(
std::shared_ptr<vk::PhysicalDevice> physicalDevice, std::shared_ptr<vk::PhysicalDevice> physicalDevice,
std::shared_ptr<vk::Device> device, std::shared_ptr<vk::Device> device,
std::shared_ptr<vk::CommandBuffer> commandBuffer) std::shared_ptr<vk::CommandBuffer> commandBuffer,
: OpBase(physicalDevice, device, commandBuffer) std::vector<std::shared_ptr<Tensor>>& tensors,
bool freeTensors)
: OpBase(physicalDevice, device, commandBuffer, tensors, freeTensors)
{ {
SPDLOG_DEBUG("Kompute OpCreateTensor constructor with params"); SPDLOG_DEBUG("Kompute OpCreateTensor constructor with params");
} }
@ -22,47 +24,21 @@ OpCreateTensor::OpCreateTensor(
OpCreateTensor::~OpCreateTensor() OpCreateTensor::~OpCreateTensor()
{ {
SPDLOG_DEBUG("Kompute OpCreateTensor destructor started"); SPDLOG_DEBUG("Kompute OpCreateTensor destructor started");
if(!this->mDevice) {
spdlog::warn("Kompute OpCreateTensor destructor called with empty device");
return;
}
if (!this->mFreePrimaryTensorResources) {
SPDLOG_DEBUG("Kompute OpCreateTensor removing primary tensor");
if (this->mPrimaryTensor && this->mPrimaryTensor->isInit()) {
this->mPrimaryTensor->freeMemoryDestroyGPUResources();
} else {
spdlog::error("Kompute OpCreateTensor expected to free primary tensor but has already been freed.");
}
}
if (!this->mFreeStagingTensorResources) {
SPDLOG_DEBUG("Kompute OpCreateTensor removing primary tensor");
if (this->mStagingTensor && this->mStagingTensor->isInit()) {
this->mStagingTensor->freeMemoryDestroyGPUResources();
} else {
spdlog::error("Kompute OpCreateTensor expected to free secondary tensor but has already been freed.");
}
}
} }
void void
OpCreateTensor::init(std::vector<std::shared_ptr<Tensor>> tensors) OpCreateTensor::init()
{ {
SPDLOG_DEBUG("Kompute OpCreateTensor init called"); SPDLOG_DEBUG("Kompute OpCreateTensor init called");
if (tensors.size() < 1) { if (this->mTensors.size() < 1) {
throw std::runtime_error( throw std::runtime_error(
"Kompute OpCreateTensor called with less than 1 tensor"); "Kompute OpCreateTensor called with less than 1 tensor");
} else if (tensors.size() > 1) { } else if (this->mTensors.size() > 1) {
spdlog::warn("Kompute OpCreateTensor called with more than 1 tensor"); spdlog::warn("Kompute OpCreateTensor called with more than 1 tensor");
} }
this->mFreePrimaryTensorResources = true; this->mPrimaryTensor = this->mTensors[0];
this->mFreeStagingTensorResources = true;
this->mPrimaryTensor = tensors[0];
if (this->mPrimaryTensor->tensorType() == Tensor::TensorTypes::eDevice) { if (this->mPrimaryTensor->tensorType() == Tensor::TensorTypes::eDevice) {
this->mPrimaryTensor->init( this->mPrimaryTensor->init(
@ -76,6 +52,9 @@ OpCreateTensor::init(std::vector<std::shared_ptr<Tensor>> tensors)
this->mStagingTensor->mapDataIntoHostMemory(); this->mStagingTensor->mapDataIntoHostMemory();
// Adding to the OpBase owned resource so they are freed
this->mTensors.push_back(this->mStagingTensor);
} else { } else {
this->mPrimaryTensor->init( this->mPrimaryTensor->init(
this->mPhysicalDevice, this->mDevice, this->mCommandBuffer); this->mPhysicalDevice, this->mDevice, this->mCommandBuffer);

View file

@ -19,9 +19,6 @@ Sequence::Sequence(std::shared_ptr<vk::PhysicalDevice> physicalDevice,
this->mDevice = device; this->mDevice = device;
this->mComputeQueue = computeQueue; this->mComputeQueue = computeQueue;
this->mQueueIndex = queueIndex; this->mQueueIndex = queueIndex;
this->createCommandPool();
this->createCommandBuffer();
} }
Sequence::~Sequence() Sequence::~Sequence()
@ -58,10 +55,17 @@ Sequence::~Sequence()
} }
} }
void
Sequence::init()
{
this->createCommandPool();
this->createCommandBuffer();
}
void void
Sequence::begin() Sequence::begin()
{ {
if (this->mCommandPool == nullptr) { if (!this->mCommandPool) {
throw std::runtime_error("Kompute Sequence command pool is null"); throw std::runtime_error("Kompute Sequence command pool is null");
} }
@ -78,7 +82,7 @@ Sequence::begin()
void void
Sequence::end() Sequence::end()
{ {
if (this->mCommandPool == nullptr) { if (!this->mCommandPool) {
throw std::runtime_error("Kompute Sequence command pool is null"); throw std::runtime_error("Kompute Sequence command pool is null");
} }
@ -125,7 +129,7 @@ Sequence::createCommandPool()
{ {
SPDLOG_DEBUG("Kompute Sequence creating command pool"); SPDLOG_DEBUG("Kompute Sequence creating command pool");
if (this->mDevice == nullptr) { if (!this->mDevice) {
throw std::runtime_error("Kompute Sequence device is null"); throw std::runtime_error("Kompute Sequence device is null");
} }
if (this->mQueueIndex < 0) { if (this->mQueueIndex < 0) {
@ -146,10 +150,10 @@ void
Sequence::createCommandBuffer() Sequence::createCommandBuffer()
{ {
SPDLOG_DEBUG("Kompute Sequence creating command buffer"); SPDLOG_DEBUG("Kompute Sequence creating command buffer");
if (this->mDevice == nullptr) { if (!this->mDevice) {
throw std::runtime_error("Kompute Sequence device is null"); throw std::runtime_error("Kompute Sequence device is null");
} }
if (this->mCommandPool == nullptr) { if (!this->mCommandPool) {
throw std::runtime_error("Kompute Sequence command pool is null"); throw std::runtime_error("Kompute Sequence command pool is null");
} }

View file

@ -323,7 +323,9 @@ Tensor::createBuffer()
SPDLOG_DEBUG("Kompute Tensor buffer & memory creation successful"); SPDLOG_DEBUG("Kompute Tensor buffer & memory creation successful");
} }
void Tensor::freeMemoryDestroyGPUResources() { void
Tensor::freeMemoryDestroyGPUResources()
{
SPDLOG_DEBUG("Kompute Tensor started freeMemoryDestroyGPUResources"); SPDLOG_DEBUG("Kompute Tensor started freeMemoryDestroyGPUResources");
this->mIsInit = false; this->mIsInit = false;
@ -355,7 +357,6 @@ void Tensor::freeMemoryDestroyGPUResources() {
} }
SPDLOG_DEBUG("Kompute Tensor successful freeMemoryDestroyGPUResources"); SPDLOG_DEBUG("Kompute Tensor successful freeMemoryDestroyGPUResources");
} }
} }

View file

@ -25,15 +25,16 @@ class Algorithm
void recordDispatch(uint32_t x = 1, uint32_t y = 1, uint32_t z = 1); void recordDispatch(uint32_t x = 1, uint32_t y = 1, uint32_t z = 1);
private: private:
// Shared resources // Never Owned Resources
std::shared_ptr<vk::Device> mDevice; std::shared_ptr<vk::Device> mDevice;
std::shared_ptr<vk::CommandBuffer> mCommandBuffer; std::shared_ptr<vk::CommandBuffer> mCommandBuffer;
// Resources owned by default // Optionally owned resources
std::shared_ptr<vk::DescriptorSetLayout> mDescriptorSetLayout; std::shared_ptr<vk::DescriptorSetLayout> mDescriptorSetLayout;
bool mFreeDescriptorSetLayout = false; bool mFreeDescriptorSetLayout = false;
std::shared_ptr<vk::DescriptorPool> mDescriptorPool; std::shared_ptr<vk::DescriptorPool> mDescriptorPool;
bool mFreeDescriptorPool = false; bool mFreeDescriptorPool = false;
// TODO: Explore design for multiple descriptor sets // TODO: Explore design for multiple descriptor sets
std::shared_ptr<vk::DescriptorSet> mDescriptorSet; std::shared_ptr<vk::DescriptorSet> mDescriptorSet;
bool mFreeDescriptorSet = false; bool mFreeDescriptorSet = false;
@ -49,6 +50,7 @@ class Algorithm
// Create util functions // Create util functions
void createShaderModule(const std::vector<char>& shaderFileData); void createShaderModule(const std::vector<char>& shaderFileData);
void createPipeline(); void createPipeline();
// Parameters // Parameters
void createParameters(std::vector<std::shared_ptr<Tensor>>& tensorParams); void createParameters(std::vector<std::shared_ptr<Tensor>>& tensorParams);
void createDescriptorPool(); void createDescriptorPool();

View file

@ -1,9 +1,13 @@
#pragma once #pragma once
#include <unordered_map>
#include "kompute/Core.hpp" #include "kompute/Core.hpp"
#include "kompute/Sequence.hpp" #include "kompute/Sequence.hpp"
#define KP_DEFAULT_SESSION "DEFAULT"
namespace kp { namespace kp {
/** /**
@ -24,28 +28,34 @@ class Manager
~Manager(); ~Manager();
std::weak_ptr<Sequence> managedSequence(); std::weak_ptr<Sequence> getOrCreateManagedSequence(std::string sessionName);
template<typename T, typename... TArgs> template<typename T, typename... TArgs>
void evalOp(std::vector<std::shared_ptr<Tensor>> tensors) void evalOp(std::vector<std::shared_ptr<Tensor>> tensors, std::string sessionName = KP_DEFAULT_SESSION)
{ {
SPDLOG_DEBUG("Kompute Manager evalOp triggered"); SPDLOG_DEBUG("Kompute Manager evalOp triggered");
Sequence sq(this->mPhysicalDevice, std::weak_ptr<Sequence> sqWeakPtr =
this->mDevice, this->getOrCreateManagedSequence(sessionName);
this->mComputeQueue,
this->mComputeQueueFamilyIndex); if (std::shared_ptr<kp::Sequence> sq = sqWeakPtr.lock())
SPDLOG_DEBUG("Kompute Manager evalOp running sequence BEGIN"); {
sq.begin(); SPDLOG_DEBUG("Kompute Manager evalOp running sequence BEGIN");
SPDLOG_DEBUG("Kompute Manager evalOp running sequence RECORD"); sq->begin();
sq.record<T>(tensors);
SPDLOG_DEBUG("Kompute Manager evalOp running sequence END"); SPDLOG_DEBUG("Kompute Manager evalOp running sequence RECORD");
sq.end(); sq->record<T>(tensors);
SPDLOG_DEBUG("Kompute Manager evalOp running sequence EVAL");
sq.eval(); SPDLOG_DEBUG("Kompute Manager evalOp running sequence END");
sq->end();
SPDLOG_DEBUG("Kompute Manager evalOp running sequence EVAL");
sq->eval();
}
SPDLOG_DEBUG("Kompute Manager evalOp running sequence SUCCESS"); SPDLOG_DEBUG("Kompute Manager evalOp running sequence SUCCESS");
} }
private: private:
std::shared_ptr<vk::Instance> mInstance = nullptr; std::shared_ptr<vk::Instance> mInstance = nullptr;
bool mFreeInstance = false; bool mFreeInstance = false;
std::shared_ptr<vk::PhysicalDevice> mPhysicalDevice = nullptr; std::shared_ptr<vk::PhysicalDevice> mPhysicalDevice = nullptr;
@ -56,7 +66,7 @@ class Manager
std::shared_ptr<vk::Queue> mComputeQueue = nullptr; std::shared_ptr<vk::Queue> mComputeQueue = nullptr;
// Always owned resources // Always owned resources
std::vector<std::shared_ptr<Sequence>> mManagedSequences; std::unordered_map<std::string, std::shared_ptr<Sequence>> mManagedSequences;
#if DEBUG #if DEBUG
vk::DebugReportCallbackEXT mDebugReportCallback; vk::DebugReportCallbackEXT mDebugReportCallback;

View file

@ -7,42 +7,81 @@
namespace kp { namespace kp {
/** /**
Base Operation * Base Operation which provides the high level interface that Kompute
*/ * operations implement in order to perform a set of actions in the GPU.
*
* Operations can perform actions on tensors, and optionally can also own an
* Algorithm with respective parameters. kp::Operations with kp::Algorithms
* would inherit from kp::OpBaseAlgo.
*/
class OpBase class OpBase
{ {
private:
public: public:
/** /**
Constructor * Base constructor, should not be used unless explicitly intended.
*/ */
OpBase() { SPDLOG_DEBUG("Compute OpBase base constructor"); } OpBase() { SPDLOG_DEBUG("Compute OpBase base constructor"); }
/**
* Default constructor with parameters that provides the bare minimum
* requirements for the operations to be able to create and manage their
* sub-components.
*/
OpBase(std::shared_ptr<vk::PhysicalDevice> physicalDevice, OpBase(std::shared_ptr<vk::PhysicalDevice> physicalDevice,
std::shared_ptr<vk::Device> device, std::shared_ptr<vk::Device> device,
std::shared_ptr<vk::CommandBuffer> commandBuffer) std::shared_ptr<vk::CommandBuffer> commandBuffer,
std::vector<std::shared_ptr<Tensor>>& tensors,
bool freeTensors)
{ {
SPDLOG_DEBUG("Compute OpBase constructor with params"); SPDLOG_DEBUG("Compute OpBase constructor with params");
this->mPhysicalDevice = physicalDevice; this->mPhysicalDevice = physicalDevice;
this->mDevice = device; this->mDevice = device;
this->mCommandBuffer = commandBuffer; this->mCommandBuffer = commandBuffer;
this->mTensors = tensors;
} }
~OpBase() { /**
SPDLOG_DEBUG("Compute OpBase destructor started"); * Default destructor for OpBase class. This OpBase destructor class should
} * always be called to destroy and free owned resources unless it is
* intended to destroy the resources in the parent class. This can be done
virtual void init(std::vector<std::shared_ptr<Tensor>> tensors) * by passing the mFreeTensors=false.
*/
~OpBase()
{ {
SPDLOG_DEBUG("Kompute OpBase init called"); SPDLOG_DEBUG("Kompute OpBase destructor started");
if (!this->mDevice) {
spdlog::warn("Kompute OpBase destructor called with empty device");
return;
}
if (this->mFreeTensors) {
SPDLOG_DEBUG("Kompute OpBase freeing tensors");
for (std::shared_ptr<Tensor> tensor : this->mTensors) {
if (tensor && tensor->isInit()) {
tensor->freeMemoryDestroyGPUResources();
} else {
spdlog::error("Kompute OpBase expected to free "
"tensor but has already been freed.");
}
}
}
} }
virtual void record() { SPDLOG_DEBUG("Kompute OpBase record called"); } virtual void init() = 0;
virtual void postSubmit() { SPDLOG_DEBUG("Kompute OpBase init called"); } virtual void record() = 0;
virtual void postSubmit() = 0;
protected: protected:
// Sometimes owned resources
std::vector<std::shared_ptr<Tensor>> mTensors;
bool mFreeTensors =
false; // TODO: Provide granularity to specify which to free
// Always external resources
std::shared_ptr<vk::PhysicalDevice> mPhysicalDevice; std::shared_ptr<vk::PhysicalDevice> mPhysicalDevice;
std::shared_ptr<vk::Device> mDevice; std::shared_ptr<vk::Device> mDevice;
std::shared_ptr<vk::CommandBuffer> mCommandBuffer; std::shared_ptr<vk::CommandBuffer> mCommandBuffer;

View file

@ -15,21 +15,22 @@ class OpCreateTensor : public OpBase
OpCreateTensor(std::shared_ptr<vk::PhysicalDevice> physicalDevice, OpCreateTensor(std::shared_ptr<vk::PhysicalDevice> physicalDevice,
std::shared_ptr<vk::Device> device, std::shared_ptr<vk::Device> device,
std::shared_ptr<vk::CommandBuffer> commandBuffer); std::shared_ptr<vk::CommandBuffer> commandBuffer,
std::vector<std::shared_ptr<Tensor>>& tensors,
bool freeTensors = true);
~OpCreateTensor(); ~OpCreateTensor();
void init(std::vector<std::shared_ptr<Tensor>> tensors) override; void init() override;
void record() override; void record() override;
void postSubmit() override; void postSubmit() override;
private: private:
// Never owned resources
std::shared_ptr<Tensor> mPrimaryTensor; std::shared_ptr<Tensor> mPrimaryTensor;
bool mFreePrimaryTensorResources = false;
std::shared_ptr<Tensor> mStagingTensor; std::shared_ptr<Tensor> mStagingTensor;
bool mFreeStagingTensorResources = false;
}; };
} // End namespace kp } // End namespace kp

View file

@ -27,11 +27,13 @@ class OpMult : public OpBase
OpMult(std::shared_ptr<vk::PhysicalDevice> physicalDevice, OpMult(std::shared_ptr<vk::PhysicalDevice> physicalDevice,
std::shared_ptr<vk::Device> device, std::shared_ptr<vk::Device> device,
std::shared_ptr<vk::CommandBuffer> commandBuffer); std::shared_ptr<vk::CommandBuffer> commandBuffer,
std::vector<std::shared_ptr<Tensor>>& tensors,
bool freeTensors = false);
~OpMult(); ~OpMult();
void init(std::vector<std::shared_ptr<Tensor>> tensors) override; void init() override;
void record() override; void record() override;
@ -73,8 +75,10 @@ OpMult<tX, tY, tZ>::OpMult()
template<uint32_t tX, uint32_t tY, uint32_t tZ> template<uint32_t tX, uint32_t tY, uint32_t tZ>
OpMult<tX, tY, tZ>::OpMult(std::shared_ptr<vk::PhysicalDevice> physicalDevice, OpMult<tX, tY, tZ>::OpMult(std::shared_ptr<vk::PhysicalDevice> physicalDevice,
std::shared_ptr<vk::Device> device, std::shared_ptr<vk::Device> device,
std::shared_ptr<vk::CommandBuffer> commandBuffer) std::shared_ptr<vk::CommandBuffer> commandBuffer,
: OpBase(physicalDevice, device, commandBuffer) std::vector<std::shared_ptr<Tensor>>& tensors,
bool freeTensors)
: OpBase(physicalDevice, device, commandBuffer, tensors, freeTensors)
{ {
SPDLOG_DEBUG("Kompute OpMult constructor with params"); SPDLOG_DEBUG("Kompute OpMult constructor with params");
@ -89,20 +93,20 @@ OpMult<tX, tY, tZ>::~OpMult()
template<uint32_t tX, uint32_t tY, uint32_t tZ> template<uint32_t tX, uint32_t tY, uint32_t tZ>
void void
OpMult<tX, tY, tZ>::init(std::vector<std::shared_ptr<Tensor>> tensors) OpMult<tX, tY, tZ>::init()
{ {
SPDLOG_DEBUG("Kompute OpMult init called"); SPDLOG_DEBUG("Kompute OpMult init called");
if (tensors.size() < 3) { if (this->mTensors.size() < 3) {
throw std::runtime_error( throw std::runtime_error(
"Kompute OpMult called with less than 1 tensor"); "Kompute OpMult called with less than 1 tensor");
} else if (tensors.size() > 3) { } else if (this->mTensors.size() > 3) {
spdlog::warn("Kompute OpMult called with more than 3 tensors"); spdlog::warn("Kompute OpMult called with more than 3 this->mTensors");
} }
this->mTensorLHS = tensors[0]; this->mTensorLHS = this->mTensors[0];
this->mTensorRHS = tensors[1]; this->mTensorRHS = this->mTensors[1];
this->mTensorOutput = tensors[2]; this->mTensorOutput = this->mTensors[2];
// The dispatch size is set up based on either explicitly provided template // 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 // parameters or by default it would take the shape and size of the tensors
@ -176,7 +180,7 @@ OpMult<tX, tY, tZ>::init(std::vector<std::shared_ptr<Tensor>> tensors)
SPDLOG_DEBUG("Kompute OpMult Initialising algorithm component"); SPDLOG_DEBUG("Kompute OpMult Initialising algorithm component");
this->mAlgorithm->init(shaderFileData, tensors); this->mAlgorithm->init(shaderFileData, this->mTensors);
} }
template<uint32_t tX, uint32_t tY, uint32_t tZ> template<uint32_t tX, uint32_t tY, uint32_t tZ>

View file

@ -22,6 +22,9 @@ class Sequence
uint32_t queueIndex); uint32_t queueIndex);
~Sequence(); ~Sequence();
// Initialiser
void init();
// Record command functions // Record command functions
void begin(); void begin();
void end(); void end();
@ -37,15 +40,15 @@ class Sequence
SPDLOG_DEBUG("Kompute Sequence record function started"); SPDLOG_DEBUG("Kompute Sequence record function started");
SPDLOG_DEBUG("Kompute Sequence creating OpBase derived class instance"); SPDLOG_DEBUG("Kompute Sequence creating OpBase derived class instance");
T* op = T* op = new T(
new T(this->mPhysicalDevice, this->mDevice, this->mCommandBuffer); this->mPhysicalDevice, this->mDevice, this->mCommandBuffer, tensors);
OpBase* baseOp = dynamic_cast<OpBase*>(op); OpBase* baseOp = dynamic_cast<OpBase*>(op);
std::unique_ptr<OpBase> baseOpPtr{ baseOp }; std::unique_ptr<OpBase> baseOpPtr{ baseOp };
SPDLOG_DEBUG( SPDLOG_DEBUG(
"Kompute Sequence running init on OpBase derived class instance"); "Kompute Sequence running init on OpBase derived class instance");
baseOpPtr->init(tensors); baseOpPtr->init();
SPDLOG_DEBUG( SPDLOG_DEBUG(
"Kompute Sequence running record on OpBase derived class instance"); "Kompute Sequence running record on OpBase derived class instance");

View file

@ -57,7 +57,6 @@ class Tensor
void mapDataFromHostMemory(); void mapDataFromHostMemory();
void mapDataIntoHostMemory(); void mapDataIntoHostMemory();
private: private:
std::shared_ptr<vk::PhysicalDevice> mPhysicalDevice; std::shared_ptr<vk::PhysicalDevice> mPhysicalDevice;
std::shared_ptr<vk::Device> mDevice; std::shared_ptr<vk::Device> mDevice;

View file

@ -74,8 +74,8 @@ TEST_CASE("End to end OpMult Flow should execute correctly from sequence") {
kp::Manager mgr; kp::Manager mgr;
std::weak_ptr<kp::Sequence> sq_ref = mgr.managedSequence(); std::weak_ptr<kp::Sequence> sqWeakPtr = mgr.getOrCreateManagedSequence("newSequence");
if (std::shared_ptr<kp::Sequence> sq = sq_ref.lock()) { if (std::shared_ptr<kp::Sequence> sq = sqWeakPtr.lock()) {
sq->begin(); sq->begin();
sq->record<kp::OpCreateTensor>({ tensorLHS }); sq->record<kp::OpCreateTensor>({ tensorLHS });
@ -93,7 +93,7 @@ TEST_CASE("End to end OpMult Flow should execute correctly from sequence") {
sq->end(); sq->end();
sq->eval(); sq->eval();
} }
sq_ref.reset(); sqWeakPtr.reset();
spdlog::info("OpMult call success"); spdlog::info("OpMult call success");
spdlog::info("Tensor output: {}", tensorOutput->data()); spdlog::info("Tensor output: {}", tensorOutput->data());