From e7985da9950bf75f00799f73b0e1d4ea7c24f0b2 Mon Sep 17 00:00:00 2001 From: tnie Date: Wed, 21 Aug 2024 00:11:32 -0500 Subject: [PATCH 1/2] fix fmt include in Manager Signed-off-by: tnie --- src/Manager.cpp | 3 ++- src/include/kompute/Manager.hpp | 4 ---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Manager.cpp b/src/Manager.cpp index 301b4a6f..138b314c 100644 --- a/src/Manager.cpp +++ b/src/Manager.cpp @@ -1,13 +1,14 @@ // SPDX-License-Identifier: Apache-2.0 #include "kompute/Manager.hpp" -#include "fmt/format.h" #include "kompute/logger/Logger.hpp" #include +#include #include #include #include #include +#include namespace kp { diff --git a/src/include/kompute/Manager.hpp b/src/include/kompute/Manager.hpp index 5458dda7..166b59fb 100644 --- a/src/include/kompute/Manager.hpp +++ b/src/include/kompute/Manager.hpp @@ -1,11 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 #pragma once -#include -#include - #include "kompute/Core.hpp" - #include "kompute/Sequence.hpp" #include "logger/Logger.hpp" From 5bd5bef9fdc38cbfc8c20efa43c52c73f491dfb4 Mon Sep 17 00:00:00 2001 From: Robert Quill Date: Wed, 21 Aug 2024 13:49:37 +0100 Subject: [PATCH 2/2] Add tests for using uninitialised tensors. Modify the ReserveData test to test some different ways of creating uninitialised tensors. Remove the test which tests that the size of an uninitialised tensor is zero, as the tensor does have a size it just has no data. Signed-off-by: Robert Quill --- src/Tensor.cpp | 6 ++- src/include/kompute/Manager.hpp | 24 ++++++++++ src/include/kompute/Tensor.hpp | 17 ++++++- test/TestOpTensorCopy.cpp | 85 +++++++++++++++++++++++++++++++++ test/TestTensor.cpp | 41 ++++++++++++++-- 5 files changed, 166 insertions(+), 7 deletions(-) diff --git a/src/Tensor.cpp b/src/Tensor.cpp index 1a6970a2..da62bd43 100644 --- a/src/Tensor.cpp +++ b/src/Tensor.cpp @@ -139,8 +139,7 @@ Tensor::tensorType() bool Tensor::isInit() { - return this->mDevice && this->mPrimaryBuffer && this->mPrimaryMemory && - this->mRawData; + return this->mDevice && this->mPrimaryBuffer && this->mPrimaryMemory; } uint32_t @@ -176,6 +175,9 @@ Tensor::rawData() void Tensor::setRawData(const void* data) { + if (!this->mRawData) { + this->mapRawData(); + } memcpy(this->mRawData, data, this->memorySize()); } diff --git a/src/include/kompute/Manager.hpp b/src/include/kompute/Manager.hpp index 5458dda7..137ca6ff 100644 --- a/src/include/kompute/Manager.hpp +++ b/src/include/kompute/Manager.hpp @@ -95,6 +95,30 @@ class Manager return tensor; } + /** + * Create a managed tensor that will be destroyed by this manager + * if it hasn't been destroyed by its reference count going to zero. + * + * @param size The number of element in this tensor + * @param tensorType The type of tensor to initialize + * @returns Shared pointer with initialised tensor + */ + template + std::shared_ptr> tensorT( + size_t size, + Tensor::TensorTypes tensorType = Tensor::TensorTypes::eDevice) + { + KP_LOG_DEBUG("Kompute Manager tensor creation triggered"); + + std::shared_ptr> tensor{ new kp::TensorT( + this->mPhysicalDevice, this->mDevice, size, tensorType) }; + + if (this->mManageResources) { + this->mManagedTensors.push_back(tensor); + } + + return tensor; + } std::shared_ptr> tensor( const std::vector& data, Tensor::TensorTypes tensorType = Tensor::TensorTypes::eDevice) diff --git a/src/include/kompute/Tensor.hpp b/src/include/kompute/Tensor.hpp index 3fd00244..e09a2a13 100644 --- a/src/include/kompute/Tensor.hpp +++ b/src/include/kompute/Tensor.hpp @@ -255,6 +255,10 @@ class Tensor template T* data() { + if (this->mRawData == nullptr) { + this->mapRawData(); + } + return (T*)this->mRawData; } @@ -268,6 +272,10 @@ class Tensor template std::vector vector() { + if (this->mRawData == nullptr) { + this->mapRawData(); + } + return { (T*)this->mRawData, ((T*)this->mRawData) + this->size() }; } @@ -277,7 +285,9 @@ class Tensor TensorDataTypes mDataType; uint32_t mSize; uint32_t mDataTypeMemorySize; - void* mRawData; + void* mRawData = nullptr; + + void mapRawData(); private: // -------------- NEVER OWNED RESOURCES @@ -318,7 +328,6 @@ class Tensor vk::BufferUsageFlags getStagingBufferUsageFlags(); vk::MemoryPropertyFlags getStagingMemoryPropertyFlags(); - void mapRawData(); void unmapRawData(); }; @@ -363,6 +372,10 @@ class TensorT : public Tensor std::vector vector() { + if (this->mRawData == nullptr) { + this->mapRawData(); + } + return { (T*)this->mRawData, ((T*)this->mRawData) + this->size() }; } diff --git a/test/TestOpTensorCopy.cpp b/test/TestOpTensorCopy.cpp index 60e0c485..262d2a41 100644 --- a/test/TestOpTensorCopy.cpp +++ b/test/TestOpTensorCopy.cpp @@ -244,3 +244,88 @@ TEST(TestOpTensorCopy, CopyTensorThroughStorageViaAlgorithms) // Making sure the GPU holds the same vector EXPECT_EQ(tensorIn->vector(), tensorOut->vector()); } + +TEST(TestOpTensorCopy, CopyDeviceToDeviceTensorUninitialised) +{ + kp::Manager mgr; + + std::vector testVecA{ 1, 2, 3 }; + + std::shared_ptr tensorA = mgr.tensor(testVecA); + std::shared_ptr> tensorB = mgr.tensorT(testVecA.size()); + + EXPECT_TRUE(tensorA->isInit()); + EXPECT_TRUE(tensorB->isInit()); + + mgr.sequence() + ->eval({ tensorA, tensorB }) + ->eval({ tensorA, tensorB }) + ->eval({ tensorA, tensorB }); + + // Making sure the GPU holds the same vector + EXPECT_EQ(tensorA->vector(), tensorB->vector()); +} + +TEST(TestOpTensorCopy, CopyTensorThroughStorageViaAlgorithmsUninitialisedOutput) +{ + kp::Manager mgr; + + std::vector testVecIn{ 9, 1, 3 }; + + std::shared_ptr tensorIn = mgr.tensor(testVecIn); + std::shared_ptr> tensorOut = + mgr.tensorT(testVecIn.size()); + // Tensor storage requires a vector to be passed only to reflect size + std::shared_ptr> tensorStorage = + mgr.tensorT(testVecIn.size(), kp::Tensor::TensorTypes::eStorage); + + EXPECT_TRUE(tensorIn->isInit()); + EXPECT_TRUE(tensorOut->isInit()); + + // Copy to storage tensor through algorithm + std::string shaderA = (R"( + #version 450 + + layout (local_size_x = 1) in; + + // The input tensors bind index is relative to index in parameter passed + layout(set = 0, binding = 0) buffer buf_in { float t_in[]; }; + layout(set = 0, binding = 1) buffer buf_st { float t_st[]; }; + + void main() { + uint index = gl_GlobalInvocationID.x; + t_st[index] = t_in[index]; + } + )"); + + auto algoA = + mgr.algorithm({ tensorIn, tensorStorage }, compileSource(shaderA)); + + // Copy from storage tensor to output tensor + std::string shaderB = (R"( + #version 450 + + layout (local_size_x = 1) in; + + // The input tensors bind index is relative to index in parameter passed + layout(set = 0, binding = 0) buffer buf_st { float t_st[]; }; + layout(set = 0, binding = 1) buffer buf_out { float t_out[]; }; + + void main() { + uint index = gl_GlobalInvocationID.x; + t_out[index] = t_st[index]; + } + )"); + + auto algoB = + mgr.algorithm({ tensorStorage, tensorOut }, compileSource(shaderB)); + + mgr.sequence() + ->eval({ tensorIn }) + ->eval(algoA) + ->eval(algoB) + ->eval({ tensorOut }); + + // Making sure the GPU holds the same vector + EXPECT_EQ(tensorIn->vector(), tensorOut->vector()); +} diff --git a/test/TestTensor.cpp b/test/TestTensor.cpp index 0aaeb995..9c62333f 100644 --- a/test/TestTensor.cpp +++ b/test/TestTensor.cpp @@ -5,6 +5,27 @@ #include "kompute/Kompute.hpp" #include "kompute/logger/Logger.hpp" +// Introducing custom struct that can be used for tensors +struct TestStruct +{ + float x; + uint32_t y; + int32_t z; + + // Creating an == operator overload for the comparison below + bool operator==(const TestStruct rhs) const + { + return this->x == rhs.x && this->y == rhs.y && this->z == rhs.z; + } +}; +// Custom struct needs to be mapped the eCustom datatype +template<> +kp::Tensor::TensorDataTypes +kp::TensorT::dataType() +{ + return Tensor::TensorDataTypes::eCustom; +} + TEST(TestTensor, ConstructorData) { kp::Manager mgr; @@ -18,9 +39,23 @@ TEST(TestTensor, ConstructorData) TEST(TestTensor, ReserveData) { kp::Manager mgr; - std::shared_ptr> tensor = mgr.tensor(3, sizeof(uint32_t), Tensor::TensorDataType::eUnsignedInt); - EXPECT_EQ(tensor->size(), 0); - EXPECT_EQ(tensor->dataTypeMemorySize(), sizeof(uint32_t)); + std::shared_ptr tensor = mgr.tensor( + nullptr, 3, sizeof(float), kp::Tensor::TensorDataTypes::eFloat); + EXPECT_EQ(tensor->size(), 3); + EXPECT_EQ(tensor->dataTypeMemorySize(), sizeof(float)); + + std::shared_ptr tensor2 = + mgr.tensor(3, sizeof(float), kp::Tensor::TensorDataTypes::eFloat); + EXPECT_EQ(tensor2->size(), 3); + EXPECT_EQ(tensor2->dataTypeMemorySize(), sizeof(float)); + + std::shared_ptr> tensor3 = mgr.tensorT(3); + EXPECT_EQ(tensor3->size(), 3); + EXPECT_EQ(tensor3->dataTypeMemorySize(), sizeof(float)); + + std::shared_ptr> tensor4 = mgr.tensorT(3); + EXPECT_EQ(tensor3->size(), 3); + EXPECT_EQ(tensor3->dataTypeMemorySize(), sizeof(TestStruct)); } TEST(TestTensor, DataTypes)