From b61f3f22975621a1f0aca8845a4523ea428ad623 Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Sun, 7 Feb 2021 22:00:58 +0000 Subject: [PATCH] Added initial iteration of tensor with two memory compoennts --- src/Tensor.cpp | 184 +++++++++++++++++++++++---------- src/include/kompute/Tensor.hpp | 24 +++-- 2 files changed, 144 insertions(+), 64 deletions(-) diff --git a/src/Tensor.cpp b/src/Tensor.cpp index 63e667053..b26132e9d 100644 --- a/src/Tensor.cpp +++ b/src/Tensor.cpp @@ -47,7 +47,7 @@ Tensor::init(std::shared_ptr physicalDevice, this->mIsInit = true; - this->createBuffer(); + this->allocateMemoryCreateGPUResources(); } std::vector& @@ -89,7 +89,7 @@ Tensor::tensorType() bool Tensor::isInit() { - return this->mIsInit && this->mBuffer && this->mMemory; + return this->mIsInit && this->mPrimaryBuffer && this->mPrimaryMemory; } void @@ -120,7 +120,7 @@ Tensor::recordCopyFrom(std::shared_ptr commandBuffer, SPDLOG_DEBUG("Kompute Tensor copying data size {}.", bufferSize); commandBuffer->copyBuffer( - *copyFromTensor->mBuffer, *this->mBuffer, copyRegion); + *copyFromTensor->mPrimaryBuffer, *this->mPrimaryBuffer, copyRegion); if (createBarrier) { // Buffer to ensure wait until data is copied to staging buffer @@ -145,7 +145,7 @@ Tensor::recordBufferMemoryBarrier( vk::DeviceSize bufferSize = this->memorySize(); vk::BufferMemoryBarrier bufferMemoryBarrier; - bufferMemoryBarrier.buffer = *this->mBuffer; + bufferMemoryBarrier.buffer = *this->mPrimaryBuffer; bufferMemoryBarrier.size = bufferSize; bufferMemoryBarrier.srcAccessMask = srcAccessMask; bufferMemoryBarrier.dstAccessMask = dstAccessMask; @@ -164,7 +164,7 @@ vk::DescriptorBufferInfo Tensor::constructDescriptorBufferInfo() { vk::DeviceSize bufferSize = this->memorySize(); - return vk::DescriptorBufferInfo(*this->mBuffer, + return vk::DescriptorBufferInfo(*this->mPrimaryBuffer, 0, // offset bufferSize); } @@ -174,20 +174,22 @@ Tensor::mapDataFromHostMemory() { SPDLOG_DEBUG("Kompute Tensor mapping data from host buffer"); - if (this->mTensorType != TensorTypes::eStaging) { - SPDLOG_ERROR( - "Mapping tensor data manually from DEVICE buffer instead of " - "using record GPU command with staging buffer"); - return; + std::shared_ptr hostVisibleMemory = nullptr; + + if (this->mTensorType == TensorTypes::eHost) { + hostVisibleMemory = this->mPrimaryMemory; + } + else { + hostVisibleMemory = this->mStagingMemory; } vk::DeviceSize bufferSize = this->memorySize(); void* mapped = this->mDevice->mapMemory( - *this->mMemory, 0, bufferSize, vk::MemoryMapFlags()); - vk::MappedMemoryRange mappedMemoryRange(*this->mMemory, 0, bufferSize); + *hostVisibleMemory, 0, bufferSize, vk::MemoryMapFlags()); + vk::MappedMemoryRange mappedMemoryRange(*hostVisibleMemory, 0, bufferSize); this->mDevice->invalidateMappedMemoryRanges(mappedMemoryRange); memcpy(this->mData.data(), mapped, bufferSize); - this->mDevice->unmapMemory(*this->mMemory); + this->mDevice->unmapMemory(*hostVisibleMemory); } void @@ -196,24 +198,27 @@ Tensor::mapDataIntoHostMemory() SPDLOG_DEBUG("Kompute Tensor local mapping tensor data to host buffer"); - if (this->mTensorType != TensorTypes::eStaging) { - SPDLOG_ERROR("Mapping tensor data manually to DEVICE memory instead of " - "using record GPU command with staging buffer"); - return; + std::shared_ptr hostVisibleMemory = nullptr; + + if (this->mTensorType == TensorTypes::eHost) { + hostVisibleMemory = this->mPrimaryMemory; + } + else { + hostVisibleMemory = this->mStagingMemory; } vk::DeviceSize bufferSize = this->memorySize(); void* mapped = this->mDevice->mapMemory( - *this->mMemory, 0, bufferSize, vk::MemoryMapFlags()); + *hostVisibleMemory, 0, bufferSize, vk::MemoryMapFlags()); memcpy(mapped, this->mData.data(), bufferSize); - vk::MappedMemoryRange mappedRange(*this->mMemory, 0, bufferSize); + vk::MappedMemoryRange mappedRange(*hostVisibleMemory, 0, bufferSize); this->mDevice->flushMappedMemoryRanges(1, &mappedRange); - this->mDevice->unmapMemory(*this->mMemory); + this->mDevice->unmapMemory(*hostVisibleMemory); } vk::BufferUsageFlags -Tensor::getBufferUsageFlags() +Tensor::getPrimaryBufferUsageFlags() { switch (this->mTensorType) { case TensorTypes::eDevice: @@ -221,8 +226,9 @@ Tensor::getBufferUsageFlags() vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst; break; - case TensorTypes::eStaging: - return vk::BufferUsageFlagBits::eTransferSrc | + case TensorTypes::eHost: + return vk::BufferUsageFlagBits::eStorageBuffer | + vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst; break; case TensorTypes::eStorage: @@ -234,13 +240,13 @@ Tensor::getBufferUsageFlags() } vk::MemoryPropertyFlags -Tensor::getMemoryPropertyFlags() +Tensor::getPrimaryMemoryPropertyFlags() { switch (this->mTensorType) { case TensorTypes::eDevice: return vk::MemoryPropertyFlagBits::eDeviceLocal; break; - case TensorTypes::eStaging: + case TensorTypes::eHost: return vk::MemoryPropertyFlagBits::eHostVisible; break; case TensorTypes::eStorage: @@ -251,8 +257,33 @@ Tensor::getMemoryPropertyFlags() } } +vk::BufferUsageFlags +Tensor::getStagingBufferUsageFlags() +{ + switch (this->mTensorType) { + case TensorTypes::eDevice: + return vk::BufferUsageFlagBits::eTransferSrc | + vk::BufferUsageFlagBits::eTransferDst; + break; + default: + throw std::runtime_error("Kompute Tensor invalid tensor type"); + } +} + +vk::MemoryPropertyFlags +Tensor::getStagingMemoryPropertyFlags() +{ + switch (this->mTensorType) { + case TensorTypes::eDevice: + return vk::MemoryPropertyFlagBits::eDeviceLocal; + break; + default: + throw std::runtime_error("Kompute Tensor invalid tensor type"); + } +} + void -Tensor::createBuffer() +Tensor::allocateMemoryCreateGPUResources() { SPDLOG_DEBUG("Kompute Tensor creating buffer"); @@ -268,44 +299,64 @@ Tensor::createBuffer() throw std::runtime_error("Kompute Tensor device is null"); } + this->mPrimaryBuffer = std::make_shared(); + this->createBuffer(this->mPrimaryBuffer, this->getPrimaryBufferUsageFlags()); + this->mFreePrimaryBuffer = true; + this->allocateBindMemory(this->mPrimaryBuffer, this->mPrimaryMemory, this->getPrimaryMemoryPropertyFlags()); + this->mFreePrimaryMemory = true; + + if (this->mTensorType == TensorTypes::eDevice) { + this->mStagingBuffer = std::make_shared(); + this->createBuffer(this->mStagingBuffer, this->getStagingBufferUsageFlags()); + this->mFreeStagingBuffer = true; + this->allocateBindMemory(this->mStagingBuffer, this->mStagingMemory, this->getStagingMemoryPropertyFlags()); + this->mFreeStagingMemory = true; + } + + SPDLOG_DEBUG("Kompute Tensor buffer & memory creation successful"); +} + +void +Tensor::createBuffer(std::shared_ptr buffer, vk::BufferUsageFlags bufferUsageFlags) { + - vk::BufferUsageFlags usageFlags = this->getBufferUsageFlags(); vk::DeviceSize bufferSize = this->memorySize(); + if(bufferSize<1){ throw std::runtime_error("Kompute Tensor attempted to create a zero-sized buffer"); } - this->mFreeBuffer = true; SPDLOG_DEBUG("Kompute Tensor creating buffer with memory size: {}, and " "usage flags: {}", bufferSize, vk::to_string(usageFlags)); + // TODO: Explore having concurrent sharing mode (with option) vk::BufferCreateInfo bufferInfo(vk::BufferCreateFlags(), bufferSize, - usageFlags, + bufferUsageFlags, vk::SharingMode::eExclusive); - this->mBuffer = std::make_shared(); - this->mDevice->createBuffer(&bufferInfo, nullptr, this->mBuffer.get()); + this->mDevice->createBuffer(&bufferInfo, nullptr, buffer.get()); - SPDLOG_DEBUG("Kompute Tensor buffer created now creating memory"); +} + +void +Tensor::allocateBindMemory(std::shared_ptr buffer, std::shared_ptr memory, vk::MemoryPropertyFlags memoryPropertyFlags) { + + SPDLOG_DEBUG("Kompute Tensor allocating and binding memory"); vk::PhysicalDeviceMemoryProperties memoryProperties = this->mPhysicalDevice->getMemoryProperties(); vk::MemoryRequirements memoryRequirements = - this->mDevice->getBufferMemoryRequirements(*this->mBuffer); - - vk::MemoryPropertyFlags memoryPropertyFlags = - this->getMemoryPropertyFlags(); + this->mDevice->getBufferMemoryRequirements(*buffer); 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) { + if (((memoryProperties.memoryTypes[i]).propertyFlags & memoryPropertyFlags) == memoryPropertyFlags) { memoryTypeIndex = i; break; } @@ -316,8 +367,6 @@ Tensor::createBuffer() "Memory type index for buffer creation not found"); } - this->mFreeMemory = true; - SPDLOG_DEBUG( "Kompute Tensor allocating memory index: {}, size {}, flags: {}", memoryTypeIndex, @@ -327,13 +376,10 @@ Tensor::createBuffer() vk::MemoryAllocateInfo memoryAllocateInfo(memoryRequirements.size, memoryTypeIndex); - this->mMemory = std::make_shared(); this->mDevice->allocateMemory( - &memoryAllocateInfo, nullptr, this->mMemory.get()); + &memoryAllocateInfo, nullptr, memory.get()); - this->mDevice->bindBufferMemory(*this->mBuffer, *this->mMemory, 0); - - SPDLOG_DEBUG("Kompute Tensor buffer & memory creation successful"); + this->mDevice->bindBufferMemory(*buffer, *memory, 0); } void @@ -349,27 +395,53 @@ Tensor::freeMemoryDestroyGPUResources() return; } - if (this->mFreeBuffer) { - if (!this->mBuffer) { + if (this->mFreePrimaryBuffer) { + if (!this->mPrimaryBuffer) { SPDLOG_ERROR( - "Kompose Tensor expected to free buffer but got null buffer"); + "Kompose Tensor expected to destroy primary buffer but got null buffer"); } else { - SPDLOG_DEBUG("Kompose Tensor destroying buffer"); + SPDLOG_DEBUG("Kompose Tensor destroying primary buffer"); this->mDevice->destroy( - *this->mBuffer, + *this->mPrimaryBuffer, (vk::Optional)nullptr); - this->mBuffer = nullptr; + this->mPrimaryBuffer = nullptr; } } - if (this->mFreeMemory) { - if (!this->mMemory) { + if (this->mFreeStagingBuffer) { + if (!this->mStagingBuffer) { SPDLOG_ERROR( - "Kompose Tensor expected to free buffer but got null memory"); + "Kompose Tensor expected to destroy staging buffer but got null buffer"); } else { - SPDLOG_DEBUG("Kompose Tensor freeing memory"); + SPDLOG_DEBUG("Kompose Tensor destroying staging buffer"); + this->mDevice->destroy( + *this->mStagingBuffer, + (vk::Optional)nullptr); + this->mStagingBuffer = nullptr; + } + } + + if (this->mFreePrimaryMemory) { + if (!this->mPrimaryMemory) { + SPDLOG_ERROR( + "Kompose Tensor expected to free primary memory but got null memory"); + } else { + SPDLOG_DEBUG("Kompose Tensor freeing primary memory"); this->mDevice->freeMemory( - *this->mMemory, + *this->mPrimaryMemory, + (vk::Optional)nullptr); + this->mDevice = nullptr; + } + } + + if (this->mFreeStagingMemory) { + if (!this->mStagingMemory) { + SPDLOG_ERROR( + "Kompose Tensor expected to free staging memory but got null memory"); + } else { + SPDLOG_DEBUG("Kompose Tensor freeing staging memory"); + this->mDevice->freeMemory( + *this->mStagingMemory, (vk::Optional)nullptr); this->mDevice = nullptr; } diff --git a/src/include/kompute/Tensor.hpp b/src/include/kompute/Tensor.hpp index d7b7e8f8e..7ab6f4e02 100644 --- a/src/include/kompute/Tensor.hpp +++ b/src/include/kompute/Tensor.hpp @@ -26,7 +26,7 @@ class Tensor enum class TensorTypes { eDevice = 0, ///< Type is device memory, source and destination - eStaging = 1, ///< Type is host memory, source and destination + eHost = 1, ///< Type is host memory, source and destination eStorage = 2, ///< Type is Device memory (only) }; @@ -173,10 +173,14 @@ class Tensor std::shared_ptr mDevice; // -------------- OPTIONALLY OWNED RESOURCES - std::shared_ptr mBuffer; - bool mFreeBuffer; - std::shared_ptr mMemory; - bool mFreeMemory; + std::shared_ptr mPrimaryBuffer; + bool mFreePrimaryBuffer; + std::shared_ptr mStagingBuffer; + bool mFreeStagingBuffer; + std::shared_ptr mPrimaryMemory; + bool mFreePrimaryMemory; + std::shared_ptr mStagingMemory; + bool mFreeStagingMemory; // -------------- ALWAYS OWNED RESOURCES std::vector mData; @@ -186,11 +190,15 @@ class Tensor std::array mShape; bool mIsInit = false; - void createBuffer(); // Creates the vulkan buffer + void allocateMemoryCreateGPUResources(); // Creates the vulkan buffer + void createBuffer(std::shared_ptr buffer, vk::BufferUsageFlags bufferUsageFlags); + void allocateBindMemory(std::shared_ptr buffer, std::shared_ptr memory, vk::MemoryPropertyFlags memoryPropertyFlags); // Private util functions - vk::BufferUsageFlags getBufferUsageFlags(); - vk::MemoryPropertyFlags getMemoryPropertyFlags(); + vk::BufferUsageFlags getPrimaryBufferUsageFlags(); + vk::MemoryPropertyFlags getPrimaryMemoryPropertyFlags(); + vk::BufferUsageFlags getStagingBufferUsageFlags(); + vk::MemoryPropertyFlags getStagingMemoryPropertyFlags(); uint64_t memorySize(); };