blob: e429902ce4efc9456ae4d2f0a6c323b03751e92d [file] [log] [blame]
Colm Donelana9bea1a2023-04-24 21:51:44 +01001//
2// Copyright © 2023 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include <backendsCommon/WorkloadUtils.hpp>
7#include <armnnTestUtils/MockMemoryManager.hpp>
8#include <armnnTestUtils/MockTensorHandle.hpp>
9#include <doctest/doctest.h>
10
11TEST_SUITE("WorkloadUtilsTest")
12{
13using namespace armnn;
14
15TEST_CASE("CopyTensorContents")
16{
17 // Two tensors of 1 float. Set source to a value and destination to 0.
18 // Copy source to destination and make sure destination is copied.
19 std::shared_ptr<MockMemoryManager> memoryManager = std::make_shared<MockMemoryManager>();
20 TensorInfo info({ 1, 1, 1, 1 }, DataType::Float32);
21 MockTensorHandle srcTensorHandle(info, memoryManager);
22 MockTensorHandle destTensorHandle(info, memoryManager);
23 srcTensorHandle.Allocate();
24 float* buffer = reinterpret_cast<float*>(srcTensorHandle.Map());
25 buffer[0] = 2.5f;
26
27 destTensorHandle.Allocate();
28 buffer = reinterpret_cast<float*>(destTensorHandle.Map());
29 buffer[0] = 0.0f;
30
31 auto copyFunc = [](void* dst, const void* src, size_t size)
32 {
33 memcpy(dst, src, size);
34 };
35 CopyTensorContentsGeneric(&srcTensorHandle, &destTensorHandle, copyFunc);
36 // After copy the destination should be 2.5.
37 buffer = reinterpret_cast<float*>(destTensorHandle.Map());
38 CHECK(buffer[0] == 2.5f);
39 // Also make sure the first buffer hasn't changed.
40 buffer = reinterpret_cast<float*>(srcTensorHandle.Map());
41 CHECK(buffer[0] == 2.5f);
42}
43
44TEST_CASE("CopyTensorContents_UnallocatedTensors")
45{
46 // Standard copy lambda
47 auto copyFunc = [](void* dst, const void* src, size_t size)
48 {
49 memcpy(dst, src, size);
50 };
51
52 // Two tensors of 1 float. The source will be managed but unallocated. This should throw an exception.
53 std::shared_ptr<MockMemoryManager> memoryManager = std::make_shared<MockMemoryManager>();
54 TensorInfo info({ 1, 1, 1, 1 }, DataType::Float32);
55 MockTensorHandle unallocatedSource(info, memoryManager);
56 unallocatedSource.Manage();
57 MockTensorHandle destTensorHandle(info, memoryManager);
58 destTensorHandle.Allocate();
59 CHECK_THROWS_AS(CopyTensorContentsGeneric(&unallocatedSource, &destTensorHandle, copyFunc),
60 const armnn::MemoryValidationException&);
61
62 // Same test for destination tensor.
63 MockTensorHandle unallocatedDest(info, memoryManager);
64 unallocatedDest.Manage();
65 MockTensorHandle srcTensorHandle(info, memoryManager);
66 srcTensorHandle.Allocate();
67 CHECK_THROWS_AS(CopyTensorContentsGeneric(&srcTensorHandle, &unallocatedDest, copyFunc),
68 const armnn::MemoryValidationException&);
69
70}
71
72TEST_CASE("CopyTensorContents_DifferentTensorSizes")
73{
74 std::shared_ptr<MockMemoryManager> memoryManager = std::make_shared<MockMemoryManager>();
75 // Standard copy lambda
76 auto copyFunc = [](void* dst, const void* src, size_t size)
77 {
78 memcpy(dst, src, size);
79 };
80
81 // This is an odd test case. We'll make the destination tensor 1 element smaller than the source.
82 // In this case the tensor will be truncated.
83 TensorInfo largerInfo({ 1, 1, 1, 6 }, DataType::Float32);
84 TensorInfo smallerInfo({ 1, 1, 1, 5 }, DataType::Float32);
85 MockTensorHandle srcLargerTensorHandle(largerInfo, memoryManager);
86 srcLargerTensorHandle.Allocate();
87 float* buffer = reinterpret_cast<float*>(srcLargerTensorHandle.Map());
88 // We'll set a value in the 5th elements, this should be copied over.
89 buffer[4] = 5.1f;
90 MockTensorHandle destSmallerTensorHandle(smallerInfo, memoryManager);
91 destSmallerTensorHandle.Allocate();
92 buffer = reinterpret_cast<float*>(destSmallerTensorHandle.Map());
93 buffer[4] = 5.2f; // This should be overwritten.
94 CopyTensorContentsGeneric(&srcLargerTensorHandle, &destSmallerTensorHandle, copyFunc);
95 CHECK(buffer[4] == 5.1f);
96
97 // Same test case but with destination being larger than source.
98 MockTensorHandle srcSmallerTensorHandle(smallerInfo, memoryManager);
99 srcSmallerTensorHandle.Allocate();
100 buffer = reinterpret_cast<float*>(srcSmallerTensorHandle.Map());
101 // We'll set a value in the 5th elements, this should be copied over.
102 buffer[4] = 5.1f;
103 MockTensorHandle destLargerTensorHandle(largerInfo, memoryManager);
104 destLargerTensorHandle.Allocate();
105 buffer = reinterpret_cast<float*>(destLargerTensorHandle.Map());
106 buffer[4] = 5.2f; // This should be overwritten.
107 buffer[5] = 6.2f; // This should NOT be overwritten.
108 CopyTensorContentsGeneric(&srcSmallerTensorHandle, &destLargerTensorHandle, copyFunc);
109 CHECK(buffer[4] == 5.1f); // Has been copied.
110 CHECK(buffer[5] == 6.2f); // Should be untouched.
111}
112
113TEST_CASE("CopyTensorContents_MixedDataTypes")
114{
115 // This is almost a pointless test, but it may detect problems with future changes.
116 // We'll copy a float tensor into a uint8 tensor of the same size. It should
117 // work without error.
118 std::shared_ptr<MockMemoryManager> memoryManager = std::make_shared<MockMemoryManager>();
119 // Standard copy lambda
120 auto copyFunc = [](void* dst, const void* src, size_t size)
121 {
122 memcpy(dst, src, size);
123 };
124
125 TensorInfo floatInfo({ 1, 1, 1, 2 }, DataType::Float32);
126 TensorInfo intInfo({ 1, 1, 1, 8 }, DataType::QAsymmU8);
127 MockTensorHandle floatTensorHandle(floatInfo, memoryManager);
128 floatTensorHandle.Allocate();
129 float* floatBuffer = reinterpret_cast<float*>(floatTensorHandle.Map());
130 floatBuffer[0] = 1.1f; // This should be 0x3f8ccccd or something very close.
131 MockTensorHandle uintTensorHandle(intInfo, memoryManager);
132 uintTensorHandle.Allocate();
133 uint8_t* intBuffer = reinterpret_cast<uint8_t*>(uintTensorHandle.Map());
134 intBuffer[0] = 0;
135
136 CopyTensorContentsGeneric(&floatTensorHandle, &uintTensorHandle, copyFunc);
137 CHECK(intBuffer[0] == 0xcd); // Make sure the data has been copied over.
138}
139
140}