|
1 | 1 | /* |
2 | | - * Copyright (c) 2017-2021, 2023-2024 Arm Limited. |
| 2 | + * Copyright (c) 2017-2021, 2023-2025 Arm Limited. |
3 | 3 | * |
4 | 4 | * SPDX-License-Identifier: MIT |
5 | 5 | * |
|
33 | 33 | #include "tests/framework/Asserts.h" |
34 | 34 | #include "tests/framework/Fixture.h" |
35 | 35 | #include "tests/validation/reference/SoftmaxLayer.h" |
36 | | - |
37 | 36 | #include <random> |
38 | 37 |
|
| 38 | +#if !defined(BARE_METAL) |
| 39 | +#include <thread> |
| 40 | +#include <vector> |
| 41 | +#endif // !defined(BARE_METAL) |
| 42 | + |
39 | 43 | namespace arm_compute |
40 | 44 | { |
41 | 45 | namespace test |
42 | 46 | { |
43 | 47 | namespace validation |
44 | 48 | { |
| 49 | +namespace |
| 50 | +{ |
| 51 | +constexpr int NUM_THREADS = 3; |
| 52 | +}// namespace |
45 | 53 | template <typename TensorType, typename AccessorType, typename FunctionType, typename T, bool IS_LOG = false> |
46 | | -class CpuSoftmaxValidationFixture : public framework::Fixture |
| 54 | +class CpuSoftmaxValidationGenericFixture : public framework::Fixture |
47 | 55 | { |
48 | 56 | public: |
49 | | - void setup(TensorShape shape, DataType data_type, float beta, size_t axis) |
| 57 | + void setup(TensorShape shape, DataType data_type, float beta, size_t axis, QuantizationInfo qinfo, |
| 58 | + TestType test_type = TestType::ConfigureOnceRunOnce) |
50 | 59 | { |
51 | 60 | if(std::is_same<TensorType, Tensor>::value && // Cpu |
52 | 61 | data_type == DataType::F16 && !CPUInfo::get().has_fp16()) |
53 | 62 | { |
54 | 63 | return; |
55 | 64 | } |
56 | 65 |
|
57 | | - quantization_info_ = QuantizationInfo(); |
| 66 | + quantization_info_ = qinfo; |
| 67 | + test_type_ = test_type; |
| 68 | + num_parallel_runs_ = (test_type_ == TestType::ConfigureOnceRunMultiThreaded ? NUM_THREADS : 1); |
58 | 69 |
|
59 | | - reference_ = compute_reference(shape, data_type, quantization_info_, beta, axis); |
60 | | - target_ = compute_target(shape, data_type, quantization_info_, beta, axis); |
| 70 | + compute_reference(shape, data_type, quantization_info_, beta, axis); |
| 71 | + compute_target(shape, data_type, quantization_info_, beta, axis); |
61 | 72 | } |
62 | 73 |
|
63 | 74 | protected: |
@@ -85,56 +96,140 @@ class CpuSoftmaxValidationFixture : public framework::Fixture |
85 | 96 | } |
86 | 97 | } |
87 | 98 |
|
88 | | - TensorType compute_target(const TensorShape &shape, DataType data_type, |
89 | | - QuantizationInfo quantization_info, float beta, int32_t axis) |
90 | | - { |
91 | | - // Create tensors |
92 | | - TensorType src = create_tensor<TensorType>(shape, data_type, 1, quantization_info); |
93 | | - TensorType dst = create_tensor<TensorType>(shape, data_type, 1, get_softmax_output_quantization_info(data_type, IS_LOG)); |
94 | | - |
95 | | - // Create and configure function |
96 | | - FunctionType softmax; |
97 | | - softmax.configure(src.info(), dst.info(), beta, axis); |
| 99 | + void allocate_and_fill_tensors(TensorType *src, TensorType *dst){ |
| 100 | + for(int i = 0; i < num_parallel_runs_; ++i){ |
98 | 101 |
|
99 | | - ARM_COMPUTE_ASSERT(src.info()->is_resizable()); |
100 | | - ARM_COMPUTE_ASSERT(dst.info()->is_resizable()); |
| 102 | + ARM_COMPUTE_ASSERT(src[i].info()->is_resizable()); |
| 103 | + ARM_COMPUTE_ASSERT(dst[i].info()->is_resizable()); |
101 | 104 |
|
102 | | - // Allocate tensors |
103 | | - src.allocator()->allocate(); |
104 | | - dst.allocator()->allocate(); |
| 105 | + // Allocate tensors |
| 106 | + src[i].allocator()->allocate(); |
| 107 | + dst[i].allocator()->allocate(); |
105 | 108 |
|
106 | | - ARM_COMPUTE_ASSERT(!src.info()->is_resizable()); |
107 | | - ARM_COMPUTE_ASSERT(!dst.info()->is_resizable()); |
| 109 | + ARM_COMPUTE_ASSERT(!src[i].info()->is_resizable()); |
| 110 | + ARM_COMPUTE_ASSERT(!dst[i].info()->is_resizable()); |
108 | 111 |
|
109 | | - // Fill tensors |
110 | | - fill(AccessorType(src)); |
| 112 | + // Fill tensors |
| 113 | + fill(AccessorType(src[i])); |
| 114 | + } |
| 115 | + } |
111 | 116 |
|
112 | | - ITensorPack run_pack{ { arm_compute::TensorType::ACL_SRC_0, &src }}; |
113 | | - run_pack.add_tensor(arm_compute::TensorType::ACL_DST, &dst); |
| 117 | + void compute_target(const TensorShape &shape, DataType data_type, |
| 118 | + QuantizationInfo quantization_info, float beta, int32_t axis) |
| 119 | + { |
| 120 | + TensorType src[NUM_THREADS]; |
| 121 | + TensorType dst[NUM_THREADS]; |
| 122 | + ITensorPack run_pack[NUM_THREADS]; |
| 123 | + TensorType *dst_ptrs[NUM_THREADS]; |
114 | 124 | auto mg = MemoryGroup{}; |
115 | | - auto ws = manage_workspace<Tensor>(softmax.workspace(), mg, run_pack); |
116 | 125 |
|
117 | | - // Compute function |
118 | | - softmax.run(run_pack); |
| 126 | + // Create tensors |
| 127 | + for(int i = 0; i < num_parallel_runs_; ++i){ |
| 128 | + src[i] = create_tensor<TensorType>(shape, data_type, 1, quantization_info); |
| 129 | + dst[i] = create_tensor<TensorType>(shape, data_type, 1, get_softmax_output_quantization_info(data_type, IS_LOG)); |
| 130 | + dst_ptrs[i] = &dst[i]; |
| 131 | + } |
| 132 | + |
| 133 | + // Create and configure function |
| 134 | + FunctionType softmax; |
| 135 | + softmax.configure(src[0].info(), dst[0].info(), beta, axis); |
| 136 | + |
| 137 | + allocate_and_fill_tensors(src, dst); |
119 | 138 |
|
120 | | - return dst; |
| 139 | + if(test_type_ == TestType::ConfigureOnceRunMultiThreaded) |
| 140 | + { |
| 141 | +#ifndef BARE_METAL |
| 142 | + std::vector<std::thread> threads; |
| 143 | + |
| 144 | + threads.reserve(num_parallel_runs_); |
| 145 | + for(int i = 0; i < num_parallel_runs_; ++i) |
| 146 | + { |
| 147 | + // Compute function |
| 148 | + run_pack[i] = {{arm_compute::TensorType::ACL_SRC_0, &src[i]}, |
| 149 | + {arm_compute::TensorType::ACL_DST, dst_ptrs[i]}}; |
| 150 | + |
| 151 | + threads.emplace_back([&,i] |
| 152 | + { |
| 153 | + auto ws = manage_workspace<Tensor>(softmax.workspace(), mg, run_pack[i]); |
| 154 | + softmax.run(run_pack[i]); |
| 155 | + target_[i] = std::move(*(dst_ptrs[i])); |
| 156 | + }); |
| 157 | + } |
| 158 | + for(int i = 0; i < num_parallel_runs_; ++i) |
| 159 | + { |
| 160 | + threads[i].join(); |
| 161 | + } |
| 162 | +#endif // ifndef BARE_METAL |
| 163 | + } |
| 164 | + else |
| 165 | + { |
| 166 | + // Compute function |
| 167 | + ITensorPack run_pack{{arm_compute::TensorType::ACL_SRC_0, &src[0]}, |
| 168 | + {arm_compute::TensorType::ACL_DST, dst_ptrs[0]}}; |
| 169 | + auto ws = manage_workspace<Tensor>(softmax.workspace(), mg, run_pack); |
| 170 | + |
| 171 | + // Compute function |
| 172 | + softmax.run(run_pack); |
| 173 | + target_[0] = std::move(*(dst_ptrs[0])); |
| 174 | + } |
121 | 175 | } |
122 | 176 |
|
123 | | - SimpleTensor<T> compute_reference(const TensorShape &shape, DataType data_type, |
| 177 | + void compute_reference(const TensorShape &shape, DataType data_type, |
124 | 178 | QuantizationInfo quantization_info, float beta, int32_t axis) |
125 | 179 | { |
126 | 180 | // Create reference |
127 | 181 | SimpleTensor<T> src{ shape, data_type, 1, quantization_info }; |
128 | 182 |
|
129 | 183 | // Fill reference |
130 | | - fill(src); |
131 | | - |
132 | | - return reference::softmax_layer<T>(src, beta, axis, IS_LOG); |
| 184 | + for(int i = 0; i < num_parallel_runs_; ++i) |
| 185 | + { |
| 186 | + // Fill reference |
| 187 | + fill(src); |
| 188 | + reference_[i] = reference::softmax_layer<T>(src, beta, axis, IS_LOG); |
| 189 | + } |
133 | 190 | } |
134 | 191 |
|
135 | | - TensorType target_{}; |
136 | | - SimpleTensor<T> reference_{}; |
| 192 | + TensorType target_[NUM_THREADS]; |
| 193 | + SimpleTensor<T> reference_[NUM_THREADS]; |
137 | 194 | QuantizationInfo quantization_info_{}; |
| 195 | + TestType test_type_{}; |
| 196 | + int num_parallel_runs_{}; |
| 197 | +}; |
| 198 | + |
| 199 | +template <typename TensorType, typename AccessorType, typename FunctionType, typename T> |
| 200 | +class CpuSoftmaxValidationFixture |
| 201 | + : public CpuSoftmaxValidationGenericFixture<TensorType, AccessorType, FunctionType, T> |
| 202 | +{ |
| 203 | +public: |
| 204 | + void setup(TensorShape shape, DataType data_type, float beta, size_t axis) |
| 205 | + { |
| 206 | + CpuSoftmaxValidationGenericFixture<TensorType, AccessorType, FunctionType, T>::setup( |
| 207 | + shape, data_type, beta, axis, QuantizationInfo(), TestType::ConfigureOnceRunOnce); |
| 208 | + } |
| 209 | +}; |
| 210 | + |
| 211 | +template <typename TensorType, typename AccessorType, typename FunctionType, typename T> |
| 212 | +class CpuSoftmaxThreadSafeValidationFixture |
| 213 | + : public CpuSoftmaxValidationGenericFixture<TensorType, AccessorType, FunctionType, T> |
| 214 | +{ |
| 215 | +public: |
| 216 | + void setup(TensorShape shape, DataType data_type, float beta, size_t axis) |
| 217 | + { |
| 218 | + CpuSoftmaxValidationGenericFixture<TensorType, AccessorType, FunctionType, T>::setup( |
| 219 | + shape, data_type, beta, axis, QuantizationInfo(), TestType::ConfigureOnceRunMultiThreaded); |
| 220 | + } |
| 221 | +}; |
| 222 | + |
| 223 | +template <typename TensorType, typename AccessorType, typename FunctionType, typename T> |
| 224 | +class CpuSoftmaxQuantizedThreadSafeValidationFixture |
| 225 | + : public CpuSoftmaxValidationGenericFixture<TensorType, AccessorType, FunctionType, T> |
| 226 | +{ |
| 227 | +public: |
| 228 | + void setup(TensorShape shape, DataType data_type, float beta, size_t axis, QuantizationInfo qinfo) |
| 229 | + { |
| 230 | + CpuSoftmaxValidationGenericFixture<TensorType, AccessorType, FunctionType, T>::setup( |
| 231 | + shape, data_type, beta, axis, qinfo, TestType::ConfigureOnceRunMultiThreaded); |
| 232 | + } |
138 | 233 | }; |
139 | 234 |
|
140 | 235 | } // namespace validation |
|
0 commit comments