IVGCVSW-6310 Update ICustomAllocator and add GetDefaultAllocator function to backends

Signed-off-by: Francis Murtagh <francis.murtagh@arm.com>
Change-Id: If2879e8a82692285e7fa3f4d09abd608ca28de12
diff --git a/src/backends/backendsCommon/DefaultAllocator.hpp b/src/backends/backendsCommon/DefaultAllocator.hpp
new file mode 100644
index 0000000..2451db3
--- /dev/null
+++ b/src/backends/backendsCommon/DefaultAllocator.hpp
@@ -0,0 +1,45 @@
+//
+// Copyright © 2021 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include <cstddef>
+#include <memory>
+#include <armnn/MemorySources.hpp>
+#include <armnn/utility/IgnoreUnused.hpp>
+
+namespace armnn
+{
+
+/** Default Memory Allocator class returned from IBackendInternal::GetDefaultAllocator(MemorySource) */
+class DefaultAllocator : public armnn::ICustomAllocator
+{
+public:
+    DefaultAllocator() = default;
+
+    void* allocate(size_t size, size_t alignment = 0) override
+    {
+        IgnoreUnused(alignment);
+        return ::operator new(size);
+    }
+
+    void free(void* ptr) override
+    {
+        std::free(ptr);
+    }
+
+    armnn::MemorySource GetMemorySourceType() override
+    {
+        return armnn::MemorySource::Malloc;
+    }
+
+    void* GetMemoryRegionAtOffset(void* buffer, size_t offset, size_t alignment = 0) override
+    {
+        IgnoreUnused(alignment);
+        return static_cast<char*>(buffer) + offset;
+    }
+};
+
+} // namespace armnn
\ No newline at end of file
diff --git a/src/backends/backendsCommon/test/MockBackend.cpp b/src/backends/backendsCommon/test/MockBackend.cpp
index df1a5c1..4bdb8ce 100644
--- a/src/backends/backendsCommon/test/MockBackend.cpp
+++ b/src/backends/backendsCommon/test/MockBackend.cpp
@@ -10,6 +10,7 @@
 
 #include <armnn/backends/IBackendContext.hpp>
 #include <armnn/backends/IMemoryManager.hpp>
+#include <backendsCommon/DefaultAllocator.hpp>
 
 #include <Optimizer.hpp>
 #include <SubgraphViewSelector.hpp>
@@ -258,4 +259,9 @@
     return optimizationViews;
 }
 
+std::unique_ptr<ICustomAllocator> MockBackend::GetDefaultAllocator() const
+{
+    return std::make_unique<DefaultAllocator>();
+}
+
 } // namespace armnn
diff --git a/src/backends/backendsCommon/test/MockBackend.hpp b/src/backends/backendsCommon/test/MockBackend.hpp
index c062452..6761ce5 100644
--- a/src/backends/backendsCommon/test/MockBackend.hpp
+++ b/src/backends/backendsCommon/test/MockBackend.hpp
@@ -165,6 +165,8 @@
     IBackendInternal::ILayerSupportSharedPtr GetLayerSupport() const override;
 
     OptimizationViews OptimizeSubgraphView(const SubgraphView& subgraph) const override;
+
+    std::unique_ptr<ICustomAllocator> GetDefaultAllocator() const override;
 };
 
 class MockLayerSupport : public LayerSupportBase
diff --git a/src/backends/cl/test/CMakeLists.txt b/src/backends/cl/test/CMakeLists.txt
index 41cbe24..8ee532a 100644
--- a/src/backends/cl/test/CMakeLists.txt
+++ b/src/backends/cl/test/CMakeLists.txt
@@ -17,6 +17,7 @@
     ClOptimizedNetworkTests.cpp
     ClRuntimeTests.cpp
     ClWorkloadFactoryHelper.hpp
+    DefaultAllocatorTests.cpp
     Fp16SupportTest.cpp
     OpenClTimerTest.cpp
 )
diff --git a/src/backends/cl/test/ClCustomAllocatorTests.cpp b/src/backends/cl/test/ClCustomAllocatorTests.cpp
index e614f4c..6014513 100644
--- a/src/backends/cl/test/ClCustomAllocatorTests.cpp
+++ b/src/backends/cl/test/ClCustomAllocatorTests.cpp
@@ -10,13 +10,13 @@
 #include <armnn/IRuntime.hpp>
 #include <armnn/Utils.hpp>
 #include <armnn/BackendRegistry.hpp>
+
 #include <cl/ClBackend.hpp>
 #if defined(ARMCOMPUTENEON_ENABLED)
 #include <neon/NeonBackend.hpp>
 #endif
-
 #include <doctest/doctest.h>
-
+#include <armnn/utility/IgnoreUnused.hpp>
 // Contains the OpenCl interfaces for mapping memory in the Gpu Page Tables
 // Requires the OpenCl backend to be included (GpuAcc)
 #include <arm_compute/core/CL/CLKernelLibrary.h>
@@ -31,7 +31,7 @@
 public:
     SampleClBackendCustomAllocator() = default;
 
-    void* allocate(size_t size, size_t alignment)
+    void* allocate(size_t size, size_t alignment) override
     {
         // If alignment is 0 just use the CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE for alignment
         if (alignment == 0)
@@ -49,12 +49,12 @@
     }
 
     /** Interface to be implemented by the child class to free the allocated tensor */
-    void free(void* ptr)
+    void free(void* ptr) override
     {
         std::free(ptr);
     }
 
-    armnn::MemorySource GetMemorySourceType()
+    armnn::MemorySource GetMemorySourceType() override
     {
         return armnn::MemorySource::Malloc;
     }
diff --git a/src/backends/cl/test/DefaultAllocatorTests.cpp b/src/backends/cl/test/DefaultAllocatorTests.cpp
new file mode 100644
index 0000000..196c0fb
--- /dev/null
+++ b/src/backends/cl/test/DefaultAllocatorTests.cpp
@@ -0,0 +1,124 @@
+//
+// Copyright © 2021 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include <armnn/backends/ICustomAllocator.hpp>
+#include <armnn/Descriptors.hpp>
+#include <armnn/Exceptions.hpp>
+#include <armnn/IRuntime.hpp>
+#include <backendsCommon/TensorHandle.hpp>
+// Requires the OpenCl backend to be included (GpuAcc)
+#include <cl/ClBackend.hpp>
+#include <doctest/doctest.h>
+#include <backendsCommon/DefaultAllocator.hpp>
+#include <backendsCommon/test/MockBackend.hpp>
+
+using namespace armnn;
+
+
+namespace
+{
+
+TEST_SUITE("DefaultAllocatorTests")
+{
+
+TEST_CASE("DefaultAllocatorTest")
+{
+    float number = 3;
+
+    TensorInfo inputTensorInfo(TensorShape({1, 1}), DataType::Float32);
+
+    // Create ArmNN runtime
+    IRuntime::CreationOptions options; // default options
+    auto customAllocator = std::make_shared<DefaultAllocator>();
+    options.m_CustomAllocatorMap = {{"GpuAcc", std::move(customAllocator)}};
+    IRuntimePtr run = IRuntime::Create(options);
+
+    // Creates structures for input & output
+    unsigned int numElements = inputTensorInfo.GetNumElements();
+    size_t totalBytes = numElements * sizeof(float);
+
+    void* alignedInputPtr = options.m_CustomAllocatorMap["GpuAcc"]->allocate(totalBytes, 0);
+
+    auto* inputPtr = reinterpret_cast<float*>(alignedInputPtr);
+    std::fill_n(inputPtr, numElements, number);
+    CHECK(inputPtr[0] == 3);
+
+    auto& backendRegistry = armnn::BackendRegistryInstance();
+    backendRegistry.DeregisterAllocator(ClBackend::GetIdStatic());
+}
+
+TEST_CASE("DefaultAllocatorTestMulti")
+{
+    float number = 3;
+
+    TensorInfo inputTensorInfo(TensorShape({2, 1}), DataType::Float32);
+
+    // Create ArmNN runtime
+    IRuntime::CreationOptions options; // default options
+    auto customAllocator = std::make_shared<DefaultAllocator>();
+    options.m_CustomAllocatorMap = {{"GpuAcc", std::move(customAllocator)}};
+    IRuntimePtr run = IRuntime::Create(options);
+
+    // Creates structures for input & output
+    unsigned int numElements = inputTensorInfo.GetNumElements();
+    size_t totalBytes = numElements * sizeof(float);
+
+    void* alignedInputPtr = options.m_CustomAllocatorMap["GpuAcc"]->allocate(totalBytes, 0);
+    void* alignedInputPtr2 = options.m_CustomAllocatorMap["GpuAcc"]->allocate(totalBytes, 0);
+
+    auto* inputPtr = reinterpret_cast<float*>(alignedInputPtr);
+    std::fill_n(inputPtr, numElements, number);
+    CHECK(inputPtr[0] == 3);
+    CHECK(inputPtr[1] == 3);
+
+    auto* inputPtr2 = reinterpret_cast<float*>(alignedInputPtr2);
+    std::fill_n(inputPtr2, numElements, number);
+    CHECK(inputPtr2[0] == 3);
+    CHECK(inputPtr2[1] == 3);
+
+    // No overlap
+    CHECK(inputPtr[0] == 3);
+    CHECK(inputPtr[1] == 3);
+
+    auto& backendRegistry = armnn::BackendRegistryInstance();
+    backendRegistry.DeregisterAllocator(ClBackend::GetIdStatic());
+}
+
+TEST_CASE("DefaultAllocatorTestMock")
+{
+    // Create ArmNN runtime
+    IRuntime::CreationOptions options; // default options
+    IRuntimePtr run = IRuntime::Create(options);
+
+    // Initialize Mock Backend
+    MockBackendInitialiser initialiser;
+    auto factoryFun = BackendRegistryInstance().GetFactory(MockBackend().GetIdStatic());
+    ARMNN_ASSERT(factoryFun != nullptr);
+    auto backend = factoryFun();
+    auto defaultAllocator = backend->GetDefaultAllocator();
+
+    // GetMemorySourceType
+    CHECK(defaultAllocator->GetMemorySourceType() == MemorySource::Malloc);
+
+    size_t totalBytes = 1 * sizeof(float);
+    // Allocate
+    void* ptr = defaultAllocator->allocate(totalBytes, 0);
+
+    // GetMemoryRegionAtOffset
+    CHECK(defaultAllocator->GetMemoryRegionAtOffset(ptr, 0, 0));
+
+    // Free
+    defaultAllocator->free(ptr);
+
+    // Clean up
+    auto& backendRegistry = armnn::BackendRegistryInstance();
+    backendRegistry.Deregister(MockBackend().GetIdStatic());
+    backendRegistry.DeregisterAllocator(ClBackend::GetIdStatic());
+}
+
+
+}
+
+} // namespace armnn
\ No newline at end of file
diff --git a/src/backends/neon/NeonBackend.cpp b/src/backends/neon/NeonBackend.cpp
index 2c3abfd..0500ee3 100644
--- a/src/backends/neon/NeonBackend.cpp
+++ b/src/backends/neon/NeonBackend.cpp
@@ -22,15 +22,16 @@
 
 #include <armnn/utility/PolymorphicDowncast.hpp>
 
-#include "workloads/NeonAdditionWorkload.hpp"
-#include "workloads/NeonBatchNormalizationWorkload.hpp"
-#include "workloads/NeonConvolution2dWorkload.hpp"
-#include "workloads/NeonDepthwiseConvolutionWorkload.hpp"
-#include "workloads/NeonDivisionWorkload.hpp"
-#include "workloads/NeonFullyConnectedWorkload.hpp"
-#include "workloads/NeonMultiplicationWorkload.hpp"
-#include "workloads/NeonReduceWorkload.hpp"
-#include "workloads/NeonSubtractionWorkload.hpp"
+#include <neon/workloads/NeonAdditionWorkload.hpp>
+#include <neon/workloads/NeonBatchNormalizationWorkload.hpp>
+#include <neon/workloads/NeonConvolution2dWorkload.hpp>
+#include <neon/workloads/NeonDepthwiseConvolutionWorkload.hpp>
+#include <neon/workloads/NeonDivisionWorkload.hpp>
+#include <neon/workloads/NeonFullyConnectedWorkload.hpp>
+#include <neon/workloads/NeonMultiplicationWorkload.hpp>
+#include <neon/workloads/NeonReduceWorkload.hpp>
+#include <neon/workloads/NeonSubtractionWorkload.hpp>
+#include <backendsCommon/DefaultAllocator.hpp>
 
 #include <Optimizer.hpp>
 
@@ -427,4 +428,10 @@
     registry.RegisterFactory(std::make_unique<NeonTensorHandleFactory>(memoryManager));
 }
 
+std::unique_ptr<ICustomAllocator> NeonBackend::GetDefaultAllocator() const
+{
+    return std::make_unique<DefaultAllocator>();
+}
+
+
 } // namespace armnn
diff --git a/src/backends/neon/NeonBackend.hpp b/src/backends/neon/NeonBackend.hpp
index 37e1722..68d60a4 100644
--- a/src/backends/neon/NeonBackend.hpp
+++ b/src/backends/neon/NeonBackend.hpp
@@ -65,6 +65,8 @@
     {
         return cpuAccCapabilities;
     };
+
+    std::unique_ptr<ICustomAllocator> GetDefaultAllocator() const override;
 };
 
 } // namespace armnn
diff --git a/src/backends/reference/RefBackend.cpp b/src/backends/reference/RefBackend.cpp
index a3060f0..ad52434 100644
--- a/src/backends/reference/RefBackend.cpp
+++ b/src/backends/reference/RefBackend.cpp
@@ -13,6 +13,7 @@
 #include <armnn/backends/IBackendContext.hpp>
 #include <armnn/backends/IMemoryManager.hpp>
 #include <armnn/utility/PolymorphicDowncast.hpp>
+#include <backendsCommon/DefaultAllocator.hpp>
 
 #include <Optimizer.hpp>
 
@@ -86,4 +87,9 @@
     registry.RegisterFactory(std::make_unique<RefTensorHandleFactory>(memoryManager));
 }
 
+std::unique_ptr<ICustomAllocator> RefBackend::GetDefaultAllocator() const
+{
+    return std::make_unique<DefaultAllocator>();
+}
+
 } // namespace armnn
diff --git a/src/backends/reference/RefBackend.hpp b/src/backends/reference/RefBackend.hpp
index 4d4aba9..6114ce6 100644
--- a/src/backends/reference/RefBackend.hpp
+++ b/src/backends/reference/RefBackend.hpp
@@ -60,6 +60,8 @@
     {
         return cpuRefCapabilities;
     };
+
+    std::unique_ptr<ICustomAllocator> GetDefaultAllocator() const override;
 };
 
 } // namespace armnn