From 014f15d552d4865eef8cd7791afb21e42749b94e Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Tue, 18 Aug 2020 21:13:33 +0100 Subject: [PATCH] Added initial base for opcreatetensor --- .ccls | 2 +- Makefile | 5 +- README.md | 32 ++++++- src/BaseOp.cpp | 27 +++--- src/BaseOp.hpp | 30 +++++- src/Manager.cpp | 3 + src/Manager.hpp | 10 +- src/OpCreateTensor.cpp | 43 ++++++++- src/OpCreateTensor.hpp | 17 +++- src/Sequence.cpp | 29 +++--- src/Sequence.hpp | 4 +- src/Tensor.cpp | 204 +++++++++++++++++++++++++++++++++++++++++ src/Tensor.hpp | 65 ++++++++++++- src/main.cpp | 12 ++- 14 files changed, 422 insertions(+), 61 deletions(-) create mode 100644 src/Tensor.cpp diff --git a/.ccls b/.ccls index e9776a234..bc4e5017a 100644 --- a/.ccls +++ b/.ccls @@ -5,7 +5,7 @@ -fms-extensions -Wall -Wextra --std=c++11 +-std=c++17 %h -x %h c++-header diff --git a/Makefile b/Makefile index 44e3196d5..b2059ee00 100644 --- a/Makefile +++ b/Makefile @@ -14,9 +14,10 @@ SCMP=/c/VulkanSDK/1.2.141.2/Bin32/glslangValidator.exe build: build_shaders $(CC) \ - -g -fexceptions -fPIC \ src/* \ - -std=c++14 \ + -std=c++17 \ + -g -fexceptions -fPIC \ + -static-libgcc -static-libstdc++ \ -DDEBUG=1 \ -I"./external/" \ -I"./src/" \ diff --git a/README.md b/README.md index 094666300..4f146074a 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,21 @@ Use default equations +```c++ +int main() { + kp::Manager kManager(); // Chooses device 0 + + kp::Tensor inputOne = kp::Tensor({0, 1, 2, 3}); + + kp::Tensor inputTwo; + inputTwo = kManager.eval(&inputTwo); + + kp::Tensor output = kManager.eval(inputOne, inputTwo); + + std::cout << output << std::endl; +} +``` + ```c++ int main() { kp::Manager kManager(); // Chooses device 0 @@ -18,6 +33,13 @@ int main() { kp::Tensor inputOne = kManager.eval({0, 1, 2, 3}); // Mounts to device and binds to 0 kp::Tensor inputTwo = kManager.eval({0, 1, 2, 3}); // Mounts to device and binds to 1 + + kp::Tensor inputOne({0, 1, 2, 3}); + kManager.eval(&inputOne); // Mounts to device and binds to 0 + + kp::Tensor inputOne({0, 1, 2, 3}); + kManager.eval(&inputTwo); // Mounts to device and binds to 0 + kp::Tensor output = kManager.eval(inputOne, inputTwo); std::cout << output << std::endl; @@ -42,11 +64,9 @@ class CustomOp : kp::BaseOperator { int main() { kp::Manager kManager(); // Chooses device 0 - kp::Tensor inputOne; - kManager.eval(&inputOne, {0, 1, 2, 3}); // Mounts to device and binds to 0 + kp::Tensor inputOne({0, 1, 2, 3}); - kp::Tensor inputTwo; - kManager.eval(&inputTwo, {0, 1, 2, 3}); // Mounts to device and binds to 1 + kp::Tensor inputTwo({0, 1, 2, 3}); kp::Tensor output; kManager.eval(&inputOne, &inputTwo, &output); @@ -63,7 +83,8 @@ int main() { kp::Sequence sq; kManager.createSequence(&sq); - //kManager.createSequence(); + + sq.begin(); kp::Tensor inputOne; sq.record(&inputOne, {0, 1, 2, 3}); // Mounts to device and binds to 0 @@ -74,6 +95,7 @@ int main() { kp::Tensor output; sq.record(&inputOne, &inputTwo, &output); + sq.end(); sq.eval(); std::cout << output << std::endl; diff --git a/src/BaseOp.cpp b/src/BaseOp.cpp index c9421512f..650d1dc4b 100644 --- a/src/BaseOp.cpp +++ b/src/BaseOp.cpp @@ -10,29 +10,26 @@ namespace kp { -BaseOp::BaseOp() {} +template +BaseOp::BaseOp() +{} -BaseOp::BaseOp(std::shared_ptr commandBuffer) +template +BaseOp::BaseOp(std::shared_ptr physicalDevice, + std::shared_ptr device, + std::shared_ptr commandBuffer) { SPDLOG_DEBUG("Compute BaseOp constructor started"); + + this->mPhysicalDevice = physicalDevice; + this->mDevice = device; this->mCommandBuffer = commandBuffer; } -BaseOp::~BaseOp() +template +BaseOp::~BaseOp() { SPDLOG_DEBUG("Compute BaseOp destructor started"); } -void -BaseOp::init(std::string one, std::string two) -{ - SPDLOG_DEBUG("Compute BaseOp init started"); -} - -void -BaseOp::record() -{ - SPDLOG_DEBUG("Compute BaseOp record started"); -} - } diff --git a/src/BaseOp.hpp b/src/BaseOp.hpp index b13e1f677..018fb5161 100644 --- a/src/BaseOp.hpp +++ b/src/BaseOp.hpp @@ -5,20 +5,42 @@ #include #include +// SPDLOG_ACTIVE_LEVEL must be defined before spdlog.h import +#if DEBUG +#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG +#endif + +#include + namespace kp { +template class BaseOp { private: public: BaseOp(); - BaseOp(std::shared_ptr commandBuffer); + BaseOp(std::shared_ptr physicalDevice, + std::shared_ptr device, + std::shared_ptr commandBuffer); virtual ~BaseOp(); - void init(std::string one, std::string two); - void record(); + template + void init(TArgs&&... args) + { + SPDLOG_DEBUG("Compute BaseOp init started"); + static_cast(this)->init(std::forward(args)...); + } - private: + template + void record(TArgs&&... args) + { + SPDLOG_DEBUG("Compute BaseOp record started"); + static_cast(this)->record(std::forward(args)...); + } + + protected: + std::shared_ptr mPhysicalDevice; std::shared_ptr mDevice; std::shared_ptr mCommandBuffer; }; diff --git a/src/Manager.cpp b/src/Manager.cpp index 857d5d68e..ce0fd74d6 100644 --- a/src/Manager.cpp +++ b/src/Manager.cpp @@ -166,6 +166,9 @@ Manager::createDevice() vk::PhysicalDevice physicalDevice = physicalDevices[this->mPhysicalDeviceIndex]; + this->mPhysicalDevice = + std::make_shared(physicalDevice); + vk::PhysicalDeviceProperties physicalDeviceProperties = physicalDevice.getProperties(); diff --git a/src/Manager.hpp b/src/Manager.hpp index 351754ec8..5d65e6013 100644 --- a/src/Manager.hpp +++ b/src/Manager.hpp @@ -20,18 +20,19 @@ class Manager public: Manager(); - // Manager(std::shared_ptr instance, - // std::shared_ptr, uint32_t queueIndex); + Manager(std::shared_ptr instance, + std::shared_ptr, + uint32_t queueIndex); ~Manager(); // Evaluate actions template - void eval(TArgs&&... args) + void evalOp(TArgs&&... args) { SPDLOG_DEBUG("Kompute Manager eval triggered"); Sequence sq( - this->mDevice, this->mComputeQueue, this->mComputeQueueFamilyIndex); + this->mPhysicalDevice, this->mDevice, this->mComputeQueue, this->mComputeQueueFamilyIndex); SPDLOG_DEBUG("Kompute Manager created sequence"); sq.begin(); SPDLOG_DEBUG("Kompute Manager sequence begin"); @@ -46,6 +47,7 @@ class Manager private: std::shared_ptr mInstance = nullptr; bool mFreeInstance = false; + std::shared_ptr mPhysicalDevice = nullptr; uint32_t mPhysicalDeviceIndex = -1; std::shared_ptr mDevice = nullptr; bool mFreeDevice = false; diff --git a/src/OpCreateTensor.cpp b/src/OpCreateTensor.cpp index 2d5354321..7a1247272 100644 --- a/src/OpCreateTensor.cpp +++ b/src/OpCreateTensor.cpp @@ -1,15 +1,48 @@ +#include "Tensor.hpp" + #include "OpCreateTensor.hpp" namespace kp { OpCreateTensor::OpCreateTensor() {} -OpCreateTensor::OpCreateTensor(std::shared_ptr commandBuffer) +OpCreateTensor::OpCreateTensor(std::shared_ptr physicalDevice, + std::shared_ptr device, + std::shared_ptr commandBuffer) + : BaseOp(physicalDevice, device, commandBuffer) { - this->mCommandBuffer = commandBuffer; -} - -OpCreateTensor::~OpCreateTensor() {} + +} + +OpCreateTensor::~OpCreateTensor() { + +} + +void +OpCreateTensor::init(std::shared_ptr tensor, std::vector data) +{ + this->mPrimaryTensor = tensor; + + if (tensor->tensorType() == Tensor::TensorTypes::eDevice) { + tensor->init(this->mPhysicalDevice, this->mDevice, this->mCommandBuffer); + + this->mStagingTensor = std::make_unique(tensor->shape(), Tensor::TensorTypes::eStaging); + + this->mStagingTensor->init(this->mPhysicalDevice, this->mDevice, this->mCommandBuffer, data); + + } + else { + tensor->init(this->mPhysicalDevice, this->mDevice, this->mCommandBuffer, data); + } +} + +void +OpCreateTensor::record() +{ + if (this->mPrimaryTensor->tensorType() == Tensor::TensorTypes::eDevice) { + this->mPrimaryTensor->recordCopyFrom(this->mStagingTensor); + } +} } diff --git a/src/OpCreateTensor.hpp b/src/OpCreateTensor.hpp index f736f5b0d..50e2ecb67 100644 --- a/src/OpCreateTensor.hpp +++ b/src/OpCreateTensor.hpp @@ -10,22 +10,31 @@ #include +#include "Tensor.hpp" + #include "BaseOp.hpp" namespace kp { -class OpCreateTensor : BaseOp +class OpCreateTensor : BaseOp { - private: public: OpCreateTensor(); - OpCreateTensor(std::shared_ptr commandBuffer); + OpCreateTensor(std::shared_ptr physicalDevice, + std::shared_ptr device, + std::shared_ptr commandBuffer); ~OpCreateTensor(); + void init(std::shared_ptr tensor, std::vector data); + + void record(); + private: - std::shared_ptr mCommandBuffer; + + std::shared_ptr mPrimaryTensor; + std::shared_ptr mStagingTensor; }; } // End namespace kp diff --git a/src/Sequence.cpp b/src/Sequence.cpp index abb119195..44cd7ed01 100644 --- a/src/Sequence.cpp +++ b/src/Sequence.cpp @@ -8,12 +8,14 @@ Sequence::Sequence() SPDLOG_DEBUG("Kompute Sequence base constructor"); } -Sequence::Sequence(std::shared_ptr device, +Sequence::Sequence(std::shared_ptr physicalDevice, + std::shared_ptr device, std::shared_ptr computeQueue, uint32_t queueIndex) { SPDLOG_DEBUG("Kompute Sequence Constructor with existing device & queue"); + this->mPhysicalDevice = physicalDevice; this->mDevice = device; this->mComputeQueue = computeQueue; this->mQueueIndex = queueIndex; @@ -26,33 +28,32 @@ Sequence::~Sequence() { SPDLOG_DEBUG("Kompute Sequence Destructor started"); - if (this->mDevice == nullptr) { + if (!this->mDevice) { spdlog::error( "Kompute Sequence destructor reached with null Device pointer"); return; } - if (this->mCommandBuffer == nullptr) { - spdlog::error( - "Kompute Sequence destructor reached with null CommandPool pointer"); - return; - } if (this->mFreeCommandBuffer) { spdlog::info("Freeing CommandBuffer"); + if (!this->mCommandBuffer) { + spdlog::error( + "Kompute Sequence destructor reached with null CommandPool pointer"); + return; + } this->mDevice->freeCommandBuffers( *this->mCommandPool, 1, this->mCommandBuffer.get()); SPDLOG_DEBUG("Kompute Manager Freed CommandBuffer"); } - if (this->mCommandPool == nullptr) { - spdlog::error( - "Kompute Sequence destructor reached with null CommandPool pointer"); - return; - } - if (this->mFreeCommandPool) { spdlog::info("Destroying CommandPool"); + if (this->mCommandPool == nullptr) { + spdlog::error( + "Kompute Sequence destructor reached with null CommandPool pointer"); + return; + } this->mDevice->destroy(*this->mCommandPool); SPDLOG_DEBUG("Kompute Manager Destroyed CommandPool"); } @@ -120,11 +121,9 @@ Sequence::createCommandPool() { SPDLOG_DEBUG("Kompute Sequence creating command pool"); if (this->mDevice == nullptr) { - spdlog::info("cmdpoolinfo"); throw std::runtime_error("Kompute Sequence device is null"); } if (this->mQueueIndex < 0) { - spdlog::info("Queue index {}", this->mQueueIndex); throw std::runtime_error("Kompute Sequence queue index not provided"); } diff --git a/src/Sequence.hpp b/src/Sequence.hpp index bb68fac8e..cf20e1dd0 100644 --- a/src/Sequence.hpp +++ b/src/Sequence.hpp @@ -17,7 +17,8 @@ class Sequence private: public: Sequence(); - Sequence(std::shared_ptr device, + Sequence(std::shared_ptr physicalDevice, + std::shared_ptr device, std::shared_ptr computeQueue, uint32_t queueIndex); ~Sequence(); @@ -37,6 +38,7 @@ class Sequence } private: + std::shared_ptr mPhysicalDevice = nullptr; std::shared_ptr mDevice = nullptr; std::shared_ptr mComputeQueue = nullptr; uint32_t mQueueIndex = -1; diff --git a/src/Tensor.cpp b/src/Tensor.cpp new file mode 100644 index 000000000..3b8fd070d --- /dev/null +++ b/src/Tensor.cpp @@ -0,0 +1,204 @@ + +#include "Tensor.hpp" + +namespace kp { + +Tensor::Tensor() { + this->mTensorType = TensorTypes::eDevice; +} + +Tensor::Tensor(std::vector shape, TensorTypes tensorType) +{ + SPDLOG_DEBUG("Kompute Tensor init with data"); + + if (shape.size() > KP_MAX_DIM_SIZE) { + spdlog::warn("Kompute Tensor created with more dimensions than supported. Max: {}, Provided: {}.", KP_MAX_DIM_SIZE, shape.size()); + } + + std::copy_n(shape.begin(), KP_MAX_DIM_SIZE, this->mShape.begin()); + this->mTensorType = tensorType; +} + +Tensor::~Tensor() +{ + SPDLOG_DEBUG("Kompute Tensor destructor started"); + + if (!this->mDevice) { + spdlog::error( + "Kompute Sequence destructor reached with null Device pointer"); + return; + } + + if (this->mFreeBuffer) { + if (!this->mBuffer) { + spdlog::error("Kompose Tensor expected to free buffer but got null buffer"); + } else { + this->mDevice->destroy(*this->mBuffer); + } + } + + if (this->mFreeMemory) { + if (!this->mMemory) { + spdlog::error("Kompose Tensor expected to free buffer but got null memory"); + } else { + this->mDevice->freeMemory(*this->mMemory); + } + } +} + +void Tensor::init(std::shared_ptr physicalDevice, std::shared_ptr device, std::shared_ptr commandBuffer, std::vector data) { + SPDLOG_DEBUG("Kompute Tensor running init with physicalDevice and logical device"); + + this->mPhysicalDevice = physicalDevice; + this->mDevice = device; + this->mCommandBuffer = commandBuffer; + + this->mIsInit = true; + + this->createBuffer(data.data()); +} + +std::vector Tensor::data() { + return this->mData; +} + +uint64_t Tensor::memorySize() { + return this->size() * sizeof(uint32_t); +} + +uint32_t Tensor::size() { + return this->mShape[0]; +} + +std::array Tensor::shape() { + return this->mShape; +} + + +Tensor::TensorTypes Tensor::tensorType() { + return this->mTensorType; +} + +bool Tensor::isInit() { + return this->mIsInit; +} + +void Tensor::recordCopyFrom(std::shared_ptr copyFromTensor) { + SPDLOG_DEBUG("Kompute Tensor recordCopyFrom called"); + + // TODO: Allow for dst and src offsets to be configured + // TODO: Test and ensure sizes for tensors are compatible + vk::DeviceSize bufferSize(this->memorySize()); + vk::BufferCopy copyRegion(0, 0, bufferSize); + // TODO: Ensure command buffer is in same device from buffer + this->mCommandBuffer->copyBuffer(*copyFromTensor->mBuffer, *this->mBuffer, copyRegion); + + this->mData = copyFromTensor->mData; +} + +vk::BufferUsageFlags Tensor::getBufferUsageFlags() { + switch (this->mTensorType) { + case TensorTypes::eDevice: + return vk::BufferUsageFlagBits::eStorageBuffer | + vk::BufferUsageFlagBits::eTransferSrc | + vk::BufferUsageFlagBits::eTransferDst; + break; + case TensorTypes::eStaging: + return vk::BufferUsageFlagBits::eTransferSrc| + vk::BufferUsageFlagBits::eTransferDst; + break; + case TensorTypes::eStorage: + return vk::BufferUsageFlagBits::eStorageBuffer; + break; + default: + throw std::runtime_error("Invalid tensor type"); + } +} + +vk::MemoryPropertyFlags Tensor::getMemoryPropertyFlags() { + switch (this->mTensorType) { + case TensorTypes::eDevice: + return vk::MemoryPropertyFlagBits::eDeviceLocal; + break; + case TensorTypes::eStaging: + return vk::MemoryPropertyFlagBits::eHostVisible; + break; + case TensorTypes::eStorage: + return vk::MemoryPropertyFlagBits::eDeviceLocal; + break; + default: + throw std::runtime_error("Invalid tensor type"); + } +} + +void +Tensor::createBuffer(void* data) +{ + SPDLOG_DEBUG("Kompute Tensor creating buffer"); + + if (!this->mIsInit) { + throw std::runtime_error("Kompute Tensor attempted to run createBuffer without init"); + } + + if (!this->mPhysicalDevice) { + throw std::runtime_error("Kompute Tensor phyisical device is null"); + } + if (!this->mDevice) { + throw std::runtime_error("Kompute Tensor device is null"); + } + + this->mFreeBuffer = true; + + vk::BufferUsageFlags usageFlags = this->getBufferUsageFlags(); + vk::DeviceSize bufferSize = this->memorySize(); + vk::BufferCreateInfo bufferInfo(vk::BufferCreateFlags(), bufferSize, usageFlags, vk::SharingMode::eExclusive); + + this->mBuffer = std::make_shared(); + this->mDevice->createBuffer(&bufferInfo, nullptr, this->mBuffer.get()); + + vk::PhysicalDeviceMemoryProperties memoryProperties = this->mPhysicalDevice->getMemoryProperties(); + + vk::MemoryRequirements memoryRequirements = this->mDevice->getBufferMemoryRequirements(*this->mBuffer); + + vk::MemoryPropertyFlags memoryPropertyFlags = + this->getMemoryPropertyFlags(); + + uint32_t memoryTypeIndex = -1; + for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++) { + if (memoryRequirements.memoryTypeBits & (1 << i)) { + if ((memoryProperties.memoryTypes[i].propertyFlags & memoryPropertyFlags) == memoryPropertyFlags) { + memoryTypeIndex = i; + break; + } + } + } + if (memoryTypeIndex < 0) { + throw std::runtime_error("Memory type index for buffer creation not found"); + } + + this->mFreeMemory = true; + + vk::MemoryAllocateInfo memoryAllocateInfo(memoryRequirements.size, memoryTypeIndex); + + this->mMemory = std::make_shared(); + this->mDevice->allocateMemory(&memoryAllocateInfo, nullptr, this->mMemory.get()); + + this->mDevice->bindBufferMemory(*this->mBuffer, *this->mMemory, 0); + + SPDLOG_DEBUG("Kompute Tensor buffer & memory creation successful"); + + if (data != nullptr) { + SPDLOG_DEBUG("Kompute Tensor copying data to buffer"); + + // TODO: Verify if flushed memory ranges should happend in sequence + void* mapped = this->mDevice->mapMemory(*this->mMemory, 0, bufferSize, vk::MemoryMapFlags()); + memcpy(mapped, data, bufferSize); + vk::MappedMemoryRange mappedRange(*this->mMemory, 0, bufferSize); + this->mDevice->flushMappedMemoryRanges(1, &mappedRange); + this->mDevice->unmapMemory(*this->mMemory); + + SPDLOG_DEBUG("Kompute Tensor successful copy data to tensor"); + } +} + +} diff --git a/src/Tensor.hpp b/src/Tensor.hpp index 88eb720e4..1e51a6019 100644 --- a/src/Tensor.hpp +++ b/src/Tensor.hpp @@ -1,13 +1,74 @@ #pragma once +#include +#include + +// SPDLOG_ACTIVE_LEVEL must be defined before spdlog.h import +#if DEBUG +#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG +#endif + +#include + +#define KP_MAX_DIM_SIZE 1 + namespace kp { class Tensor { - private: public: + + enum class TensorTypes + { + eDevice = 0, + eStaging = 1, + eStorage = 2, + }; + Tensor(); - virtual ~Tensor(); + + Tensor(std::vector shape, TensorTypes tensorType = TensorTypes::eDevice); + + ~Tensor(); + + void init(std::shared_ptr physicalDevice, std::shared_ptr device, std::shared_ptr commandBuffer, std::vector data = std::vector()); + + // Create functions + void createBuffer(void* data = nullptr); + + // Getter functions + std::vector data(); + uint32_t size(); + std::array shape(); + TensorTypes tensorType(); + bool isInit(); + + // Record functions + void recordCopyFrom(std::shared_ptr copyFromTensor); + + private: + std::shared_ptr mPhysicalDevice; + std::shared_ptr mDevice; + std::shared_ptr mCommandBuffer; + + std::shared_ptr mBuffer; + bool mFreeBuffer; + std::shared_ptr mMemory; + bool mFreeMemory; + + std::vector mData; + + TensorTypes mTensorType = TensorTypes::eDevice; + + std::array mShape; // TODO: Only 1D supported + bool mIsInit = false; + // uint32_t mDataType; + + + // Private util functions + vk::BufferUsageFlags getBufferUsageFlags(); + vk::MemoryPropertyFlags getMemoryPropertyFlags(); + uint64_t memorySize(); }; } // End namespace kp diff --git a/src/main.cpp b/src/main.cpp index 35ea7c747..c7b1a99ac 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,7 +20,8 @@ #include #include -#include "BaseOp.hpp" +#include "OpCreateTensor.hpp" +#include "Tensor.hpp" #include "Manager.hpp" #define BUFFER_ELEMENTS 32 @@ -619,9 +620,14 @@ main() // Run Kompute spdlog::info("Creating manager"); kp::Manager mgr; - spdlog::info("Calling manager eval"); - mgr.eval("one", "two"); + std::vector data = {0.0, 1.0, 2.0}; + kp::Tensor tensor({data.size()}); + spdlog::info("Calling manager eval w opcreatetensor"); + mgr.evalOp(&tensor, data); spdlog::info("Called manager eval success"); + std::vector outData = tensor.data(); + spdlog::info("Output data: {}", outData); + return 0; } catch (const std::exception& exc) { spdlog::error(exc.what());