Narumol Prangnawarat | 1a26896 | 2020-07-27 15:52:13 +0100 | [diff] [blame] | 1 | // |
Mike Kelly | 363b572 | 2023-10-11 14:25:50 +0100 | [diff] [blame] | 2 | // Copyright © 2020-2021,2023 Arm Ltd and Contributors. All rights reserved. |
Narumol Prangnawarat | 1a26896 | 2020-07-27 15:52:13 +0100 | [diff] [blame] | 3 | // SPDX-License-Identifier: MIT |
| 4 | // |
Sadik Armagan | 76615a5 | 2020-08-04 14:01:05 +0100 | [diff] [blame] | 5 | #include <Graph.hpp> |
| 6 | #include <Network.hpp> |
| 7 | |
Narumol Prangnawarat | 1a26896 | 2020-07-27 15:52:13 +0100 | [diff] [blame] | 8 | #include <neon/NeonTensorHandle.hpp> |
| 9 | #include <neon/NeonTensorHandleFactory.hpp> |
| 10 | |
Matthew Sloyan | 171214c | 2020-09-09 09:07:37 +0100 | [diff] [blame] | 11 | #include <armnn/utility/NumericCast.hpp> |
Sadik Armagan | 76615a5 | 2020-08-04 14:01:05 +0100 | [diff] [blame] | 12 | #include <armnn/utility/PolymorphicDowncast.hpp> |
| 13 | |
Sadik Armagan | a097d2a | 2021-11-24 15:47:28 +0000 | [diff] [blame] | 14 | #include <GraphUtils.hpp> |
Narumol Prangnawarat | b8d771a | 2020-08-14 11:51:12 +0100 | [diff] [blame] | 15 | #include <arm_compute/runtime/Allocator.h> |
Sadik Armagan | a097d2a | 2021-11-24 15:47:28 +0000 | [diff] [blame] | 16 | #include <CommonTestUtils.hpp> |
Sadik Armagan | 76615a5 | 2020-08-04 14:01:05 +0100 | [diff] [blame] | 17 | |
Sadik Armagan | 1625efc | 2021-06-10 18:24:34 +0100 | [diff] [blame] | 18 | #include <doctest/doctest.h> |
Keith Davis | 3674f14 | 2020-08-16 23:44:15 +0100 | [diff] [blame] | 19 | #include <armnn/utility/Assert.hpp> |
Narumol Prangnawarat | 1a26896 | 2020-07-27 15:52:13 +0100 | [diff] [blame] | 20 | |
Sadik Armagan | 1625efc | 2021-06-10 18:24:34 +0100 | [diff] [blame] | 21 | TEST_SUITE("NeonTensorHandleTests") |
| 22 | { |
Narumol Prangnawarat | 1a26896 | 2020-07-27 15:52:13 +0100 | [diff] [blame] | 23 | using namespace armnn; |
| 24 | |
Sadik Armagan | 1625efc | 2021-06-10 18:24:34 +0100 | [diff] [blame] | 25 | TEST_CASE("NeonTensorHandleGetCapabilitiesNoPadding") |
Narumol Prangnawarat | 1a26896 | 2020-07-27 15:52:13 +0100 | [diff] [blame] | 26 | { |
| 27 | std::shared_ptr<NeonMemoryManager> memoryManager = std::make_shared<NeonMemoryManager>(); |
| 28 | NeonTensorHandleFactory handleFactory(memoryManager); |
| 29 | |
| 30 | INetworkPtr network(INetwork::Create()); |
| 31 | |
| 32 | // Add the layers |
| 33 | IConnectableLayer* input = network->AddInputLayer(0); |
| 34 | SoftmaxDescriptor descriptor; |
| 35 | descriptor.m_Beta = 1.0f; |
| 36 | IConnectableLayer* softmax = network->AddSoftmaxLayer(descriptor); |
| 37 | IConnectableLayer* output = network->AddOutputLayer(2); |
| 38 | |
| 39 | // Establish connections |
| 40 | input->GetOutputSlot(0).Connect(softmax->GetInputSlot(0)); |
| 41 | softmax->GetOutputSlot(0).Connect(output->GetInputSlot(0)); |
| 42 | |
| 43 | // No padding required for input |
| 44 | std::vector<Capability> capabilities = handleFactory.GetCapabilities(input, |
| 45 | softmax, |
| 46 | CapabilityClass::PaddingRequired); |
Sadik Armagan | 1625efc | 2021-06-10 18:24:34 +0100 | [diff] [blame] | 47 | CHECK(capabilities.empty()); |
Narumol Prangnawarat | 1a26896 | 2020-07-27 15:52:13 +0100 | [diff] [blame] | 48 | |
| 49 | // No padding required for Softmax |
| 50 | capabilities = handleFactory.GetCapabilities(softmax, output, CapabilityClass::PaddingRequired); |
Sadik Armagan | 1625efc | 2021-06-10 18:24:34 +0100 | [diff] [blame] | 51 | CHECK(capabilities.empty()); |
Narumol Prangnawarat | 1a26896 | 2020-07-27 15:52:13 +0100 | [diff] [blame] | 52 | |
| 53 | // No padding required for output |
| 54 | capabilities = handleFactory.GetCapabilities(output, nullptr, CapabilityClass::PaddingRequired); |
Sadik Armagan | 1625efc | 2021-06-10 18:24:34 +0100 | [diff] [blame] | 55 | CHECK(capabilities.empty()); |
Narumol Prangnawarat | 1a26896 | 2020-07-27 15:52:13 +0100 | [diff] [blame] | 56 | } |
| 57 | |
Sadik Armagan | 1625efc | 2021-06-10 18:24:34 +0100 | [diff] [blame] | 58 | TEST_CASE("NeonTensorHandleGetCapabilitiesPadding") |
Narumol Prangnawarat | 1a26896 | 2020-07-27 15:52:13 +0100 | [diff] [blame] | 59 | { |
| 60 | std::shared_ptr<NeonMemoryManager> memoryManager = std::make_shared<NeonMemoryManager>(); |
| 61 | NeonTensorHandleFactory handleFactory(memoryManager); |
| 62 | |
| 63 | INetworkPtr network(INetwork::Create()); |
| 64 | |
| 65 | // Add the layers |
| 66 | IConnectableLayer* input = network->AddInputLayer(0); |
| 67 | Pooling2dDescriptor descriptor; |
| 68 | IConnectableLayer* pooling = network->AddPooling2dLayer(descriptor); |
| 69 | IConnectableLayer* output = network->AddOutputLayer(2); |
| 70 | |
| 71 | // Establish connections |
| 72 | input->GetOutputSlot(0).Connect(pooling->GetInputSlot(0)); |
| 73 | pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0)); |
| 74 | |
| 75 | // No padding required for input |
| 76 | std::vector<Capability> capabilities = handleFactory.GetCapabilities(input, |
| 77 | pooling, |
| 78 | CapabilityClass::PaddingRequired); |
Sadik Armagan | 1625efc | 2021-06-10 18:24:34 +0100 | [diff] [blame] | 79 | CHECK(capabilities.empty()); |
Narumol Prangnawarat | 1a26896 | 2020-07-27 15:52:13 +0100 | [diff] [blame] | 80 | |
| 81 | // No padding required for output |
| 82 | capabilities = handleFactory.GetCapabilities(output, nullptr, CapabilityClass::PaddingRequired); |
Sadik Armagan | 1625efc | 2021-06-10 18:24:34 +0100 | [diff] [blame] | 83 | CHECK(capabilities.empty()); |
Narumol Prangnawarat | 1a26896 | 2020-07-27 15:52:13 +0100 | [diff] [blame] | 84 | |
| 85 | // Padding required for Pooling2d |
| 86 | capabilities = handleFactory.GetCapabilities(pooling, output, CapabilityClass::PaddingRequired); |
Sadik Armagan | 1625efc | 2021-06-10 18:24:34 +0100 | [diff] [blame] | 87 | CHECK(capabilities.size() == 1); |
| 88 | CHECK((capabilities[0].m_CapabilityClass == CapabilityClass::PaddingRequired)); |
| 89 | CHECK(capabilities[0].m_Value); |
Narumol Prangnawarat | 1a26896 | 2020-07-27 15:52:13 +0100 | [diff] [blame] | 90 | } |
| 91 | |
Sadik Armagan | 1625efc | 2021-06-10 18:24:34 +0100 | [diff] [blame] | 92 | TEST_CASE("NeonTensorHandleFactoryMemoryManaged") |
Narumol Prangnawarat | b8d771a | 2020-08-14 11:51:12 +0100 | [diff] [blame] | 93 | { |
| 94 | std::shared_ptr<NeonMemoryManager> memoryManager = std::make_shared<NeonMemoryManager>( |
| 95 | std::make_unique<arm_compute::Allocator>(), |
| 96 | BaseMemoryManager::MemoryAffinity::Offset); |
| 97 | NeonTensorHandleFactory handleFactory(memoryManager); |
| 98 | TensorInfo info({ 1, 1, 2, 1 }, DataType::Float32); |
| 99 | |
| 100 | // create TensorHandle with memory managed |
| 101 | auto handle = handleFactory.CreateTensorHandle(info, true); |
| 102 | handle->Manage(); |
| 103 | handle->Allocate(); |
| 104 | |
| 105 | memoryManager->Acquire(); |
| 106 | { |
| 107 | float* buffer = reinterpret_cast<float*>(handle->Map()); |
Sadik Armagan | 1625efc | 2021-06-10 18:24:34 +0100 | [diff] [blame] | 108 | CHECK(buffer != nullptr); // Yields a valid pointer |
Narumol Prangnawarat | b8d771a | 2020-08-14 11:51:12 +0100 | [diff] [blame] | 109 | buffer[0] = 1.5f; |
| 110 | buffer[1] = 2.5f; |
Sadik Armagan | 1625efc | 2021-06-10 18:24:34 +0100 | [diff] [blame] | 111 | CHECK(buffer[0] == 1.5f); // Memory is writable and readable |
| 112 | CHECK(buffer[1] == 2.5f); // Memory is writable and readable |
Narumol Prangnawarat | b8d771a | 2020-08-14 11:51:12 +0100 | [diff] [blame] | 113 | } |
| 114 | memoryManager->Release(); |
| 115 | |
| 116 | memoryManager->Acquire(); |
| 117 | { |
| 118 | float* buffer = reinterpret_cast<float*>(handle->Map()); |
Sadik Armagan | 1625efc | 2021-06-10 18:24:34 +0100 | [diff] [blame] | 119 | CHECK(buffer != nullptr); // Yields a valid pointer |
Narumol Prangnawarat | b8d771a | 2020-08-14 11:51:12 +0100 | [diff] [blame] | 120 | buffer[0] = 3.5f; |
| 121 | buffer[1] = 4.5f; |
Sadik Armagan | 1625efc | 2021-06-10 18:24:34 +0100 | [diff] [blame] | 122 | CHECK(buffer[0] == 3.5f); // Memory is writable and readable |
| 123 | CHECK(buffer[1] == 4.5f); // Memory is writable and readable |
Narumol Prangnawarat | b8d771a | 2020-08-14 11:51:12 +0100 | [diff] [blame] | 124 | } |
| 125 | memoryManager->Release(); |
| 126 | |
| 127 | float testPtr[2] = { 2.5f, 5.5f }; |
| 128 | // Cannot import as import is disabled |
Sadik Armagan | 1625efc | 2021-06-10 18:24:34 +0100 | [diff] [blame] | 129 | CHECK_THROWS_AS(handle->Import(static_cast<void*>(testPtr), MemorySource::Malloc), MemoryImportException); |
Narumol Prangnawarat | b8d771a | 2020-08-14 11:51:12 +0100 | [diff] [blame] | 130 | } |
| 131 | |
Sadik Armagan | 1625efc | 2021-06-10 18:24:34 +0100 | [diff] [blame] | 132 | TEST_CASE("NeonTensorHandleFactoryImport") |
Narumol Prangnawarat | b8d771a | 2020-08-14 11:51:12 +0100 | [diff] [blame] | 133 | { |
| 134 | std::shared_ptr<NeonMemoryManager> memoryManager = std::make_shared<NeonMemoryManager>( |
| 135 | std::make_unique<arm_compute::Allocator>(), |
| 136 | BaseMemoryManager::MemoryAffinity::Offset); |
| 137 | NeonTensorHandleFactory handleFactory(memoryManager); |
| 138 | TensorInfo info({ 1, 1, 2, 1 }, DataType::Float32); |
| 139 | |
| 140 | // create TensorHandle without memory managed |
| 141 | auto handle = handleFactory.CreateTensorHandle(info, false); |
| 142 | handle->Manage(); |
| 143 | handle->Allocate(); |
| 144 | memoryManager->Acquire(); |
| 145 | |
| 146 | // No buffer allocated when import is enabled |
Sadik Armagan | 1625efc | 2021-06-10 18:24:34 +0100 | [diff] [blame] | 147 | CHECK((PolymorphicDowncast<NeonTensorHandle*>(handle.get()))->GetTensor().buffer() == nullptr); |
Narumol Prangnawarat | b8d771a | 2020-08-14 11:51:12 +0100 | [diff] [blame] | 148 | |
| 149 | float testPtr[2] = { 2.5f, 5.5f }; |
| 150 | // Correctly import |
Sadik Armagan | 1625efc | 2021-06-10 18:24:34 +0100 | [diff] [blame] | 151 | CHECK(handle->Import(static_cast<void*>(testPtr), MemorySource::Malloc)); |
Narumol Prangnawarat | b8d771a | 2020-08-14 11:51:12 +0100 | [diff] [blame] | 152 | float* buffer = reinterpret_cast<float*>(handle->Map()); |
Sadik Armagan | 1625efc | 2021-06-10 18:24:34 +0100 | [diff] [blame] | 153 | CHECK(buffer != nullptr); // Yields a valid pointer after import |
| 154 | CHECK(buffer == testPtr); // buffer is pointing to testPtr |
Narumol Prangnawarat | b8d771a | 2020-08-14 11:51:12 +0100 | [diff] [blame] | 155 | // Memory is writable and readable with correct value |
Sadik Armagan | 1625efc | 2021-06-10 18:24:34 +0100 | [diff] [blame] | 156 | CHECK(buffer[0] == 2.5f); |
| 157 | CHECK(buffer[1] == 5.5f); |
Narumol Prangnawarat | b8d771a | 2020-08-14 11:51:12 +0100 | [diff] [blame] | 158 | buffer[0] = 3.5f; |
| 159 | buffer[1] = 10.0f; |
Sadik Armagan | 1625efc | 2021-06-10 18:24:34 +0100 | [diff] [blame] | 160 | CHECK(buffer[0] == 3.5f); |
| 161 | CHECK(buffer[1] == 10.0f); |
Narumol Prangnawarat | b8d771a | 2020-08-14 11:51:12 +0100 | [diff] [blame] | 162 | memoryManager->Release(); |
| 163 | } |
| 164 | |
David Monahan | 0fa1050 | 2022-01-13 10:48:33 +0000 | [diff] [blame] | 165 | TEST_CASE("NeonTensorHandleCanBeImported") |
| 166 | { |
| 167 | std::shared_ptr<NeonMemoryManager> memoryManager = std::make_shared<NeonMemoryManager>( |
| 168 | std::make_unique<arm_compute::Allocator>(), |
| 169 | BaseMemoryManager::MemoryAffinity::Offset); |
| 170 | NeonTensorHandleFactory handleFactory(memoryManager); |
| 171 | TensorInfo info({ 1, 1, 2, 1 }, DataType::Float32); |
| 172 | |
| 173 | // create TensorHandle (Memory Managed status is irrelevant) |
| 174 | auto handle = handleFactory.CreateTensorHandle(info, false); |
| 175 | |
| 176 | // Create an aligned buffer |
| 177 | float alignedBuffer[2] = { 2.5f, 5.5f }; |
| 178 | // Check aligned buffers return true |
| 179 | CHECK(handle->CanBeImported(&alignedBuffer, MemorySource::Malloc) == true); |
| 180 | |
| 181 | // Create a misaligned buffer from the aligned one |
| 182 | float* misalignedBuffer = reinterpret_cast<float*>(reinterpret_cast<char*>(alignedBuffer) + 1); |
| 183 | // Check misaligned buffers return false |
| 184 | CHECK(handle->CanBeImported(static_cast<void*>(misalignedBuffer), MemorySource::Malloc) == false); |
| 185 | } |
| 186 | |
Sadik Armagan | 1625efc | 2021-06-10 18:24:34 +0100 | [diff] [blame] | 187 | TEST_CASE("NeonTensorHandleSupportsInPlaceComputation") |
Sadik Armagan | ab3bd4d | 2020-08-25 11:48:00 +0100 | [diff] [blame] | 188 | { |
| 189 | std::shared_ptr<NeonMemoryManager> memoryManager = std::make_shared<NeonMemoryManager>(); |
| 190 | NeonTensorHandleFactory handleFactory(memoryManager); |
| 191 | |
| 192 | // NeonTensorHandleFactory supports InPlaceComputation |
| 193 | ARMNN_ASSERT(handleFactory.SupportsInPlaceComputation()); |
| 194 | } |
| 195 | |
Sadik Armagan | 1625efc | 2021-06-10 18:24:34 +0100 | [diff] [blame] | 196 | } |