1 /*
2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "modules/audio_processing/aec3/vector_math.h"
12
13 #include <math.h>
14
15 #include "rtc_base/system/arch.h"
16 #include "system_wrappers/include/cpu_features_wrapper.h"
17 #include "test/gtest.h"
18
19 namespace webrtc {
20
21 #if defined(WEBRTC_HAS_NEON)
22
TEST(VectorMath,Sqrt)23 TEST(VectorMath, Sqrt) {
24 std::array<float, kFftLengthBy2Plus1> x;
25 std::array<float, kFftLengthBy2Plus1> z;
26 std::array<float, kFftLengthBy2Plus1> z_neon;
27
28 for (size_t k = 0; k < x.size(); ++k) {
29 x[k] = (2.f / 3.f) * k;
30 }
31
32 std::copy(x.begin(), x.end(), z.begin());
33 aec3::VectorMath(Aec3Optimization::kNone).Sqrt(z);
34 std::copy(x.begin(), x.end(), z_neon.begin());
35 aec3::VectorMath(Aec3Optimization::kNeon).Sqrt(z_neon);
36 for (size_t k = 0; k < z.size(); ++k) {
37 EXPECT_NEAR(z[k], z_neon[k], 0.0001f);
38 EXPECT_NEAR(sqrtf(x[k]), z_neon[k], 0.0001f);
39 }
40 }
41
TEST(VectorMath,Multiply)42 TEST(VectorMath, Multiply) {
43 std::array<float, kFftLengthBy2Plus1> x;
44 std::array<float, kFftLengthBy2Plus1> y;
45 std::array<float, kFftLengthBy2Plus1> z;
46 std::array<float, kFftLengthBy2Plus1> z_neon;
47
48 for (size_t k = 0; k < x.size(); ++k) {
49 x[k] = k;
50 y[k] = (2.f / 3.f) * k;
51 }
52
53 aec3::VectorMath(Aec3Optimization::kNone).Multiply(x, y, z);
54 aec3::VectorMath(Aec3Optimization::kNeon).Multiply(x, y, z_neon);
55 for (size_t k = 0; k < z.size(); ++k) {
56 EXPECT_FLOAT_EQ(z[k], z_neon[k]);
57 EXPECT_FLOAT_EQ(x[k] * y[k], z_neon[k]);
58 }
59 }
60
TEST(VectorMath,Accumulate)61 TEST(VectorMath, Accumulate) {
62 std::array<float, kFftLengthBy2Plus1> x;
63 std::array<float, kFftLengthBy2Plus1> z;
64 std::array<float, kFftLengthBy2Plus1> z_neon;
65
66 for (size_t k = 0; k < x.size(); ++k) {
67 x[k] = k;
68 z[k] = z_neon[k] = 2.f * k;
69 }
70
71 aec3::VectorMath(Aec3Optimization::kNone).Accumulate(x, z);
72 aec3::VectorMath(Aec3Optimization::kNeon).Accumulate(x, z_neon);
73 for (size_t k = 0; k < z.size(); ++k) {
74 EXPECT_FLOAT_EQ(z[k], z_neon[k]);
75 EXPECT_FLOAT_EQ(x[k] + 2.f * x[k], z_neon[k]);
76 }
77 }
78 #endif
79
80 #if defined(WEBRTC_ARCH_X86_FAMILY)
81
TEST(VectorMath,Sse2Sqrt)82 TEST(VectorMath, Sse2Sqrt) {
83 if (GetCPUInfo(kSSE2) != 0) {
84 std::array<float, kFftLengthBy2Plus1> x;
85 std::array<float, kFftLengthBy2Plus1> z;
86 std::array<float, kFftLengthBy2Plus1> z_sse2;
87
88 for (size_t k = 0; k < x.size(); ++k) {
89 x[k] = (2.f / 3.f) * k;
90 }
91
92 std::copy(x.begin(), x.end(), z.begin());
93 aec3::VectorMath(Aec3Optimization::kNone).Sqrt(z);
94 std::copy(x.begin(), x.end(), z_sse2.begin());
95 aec3::VectorMath(Aec3Optimization::kSse2).Sqrt(z_sse2);
96 EXPECT_EQ(z, z_sse2);
97 for (size_t k = 0; k < z.size(); ++k) {
98 EXPECT_FLOAT_EQ(z[k], z_sse2[k]);
99 EXPECT_FLOAT_EQ(sqrtf(x[k]), z_sse2[k]);
100 }
101 }
102 }
103
TEST(VectorMath,Avx2Sqrt)104 TEST(VectorMath, Avx2Sqrt) {
105 if (GetCPUInfo(kAVX2) != 0) {
106 std::array<float, kFftLengthBy2Plus1> x;
107 std::array<float, kFftLengthBy2Plus1> z;
108 std::array<float, kFftLengthBy2Plus1> z_avx2;
109
110 for (size_t k = 0; k < x.size(); ++k) {
111 x[k] = (2.f / 3.f) * k;
112 }
113
114 std::copy(x.begin(), x.end(), z.begin());
115 aec3::VectorMath(Aec3Optimization::kNone).Sqrt(z);
116 std::copy(x.begin(), x.end(), z_avx2.begin());
117 aec3::VectorMath(Aec3Optimization::kAvx2).Sqrt(z_avx2);
118 EXPECT_EQ(z, z_avx2);
119 for (size_t k = 0; k < z.size(); ++k) {
120 EXPECT_FLOAT_EQ(z[k], z_avx2[k]);
121 EXPECT_FLOAT_EQ(sqrtf(x[k]), z_avx2[k]);
122 }
123 }
124 }
125
TEST(VectorMath,Sse2Multiply)126 TEST(VectorMath, Sse2Multiply) {
127 if (GetCPUInfo(kSSE2) != 0) {
128 std::array<float, kFftLengthBy2Plus1> x;
129 std::array<float, kFftLengthBy2Plus1> y;
130 std::array<float, kFftLengthBy2Plus1> z;
131 std::array<float, kFftLengthBy2Plus1> z_sse2;
132
133 for (size_t k = 0; k < x.size(); ++k) {
134 x[k] = k;
135 y[k] = (2.f / 3.f) * k;
136 }
137
138 aec3::VectorMath(Aec3Optimization::kNone).Multiply(x, y, z);
139 aec3::VectorMath(Aec3Optimization::kSse2).Multiply(x, y, z_sse2);
140 for (size_t k = 0; k < z.size(); ++k) {
141 EXPECT_FLOAT_EQ(z[k], z_sse2[k]);
142 EXPECT_FLOAT_EQ(x[k] * y[k], z_sse2[k]);
143 }
144 }
145 }
146
TEST(VectorMath,Avx2Multiply)147 TEST(VectorMath, Avx2Multiply) {
148 if (GetCPUInfo(kAVX2) != 0) {
149 std::array<float, kFftLengthBy2Plus1> x;
150 std::array<float, kFftLengthBy2Plus1> y;
151 std::array<float, kFftLengthBy2Plus1> z;
152 std::array<float, kFftLengthBy2Plus1> z_avx2;
153
154 for (size_t k = 0; k < x.size(); ++k) {
155 x[k] = k;
156 y[k] = (2.f / 3.f) * k;
157 }
158
159 aec3::VectorMath(Aec3Optimization::kNone).Multiply(x, y, z);
160 aec3::VectorMath(Aec3Optimization::kAvx2).Multiply(x, y, z_avx2);
161 for (size_t k = 0; k < z.size(); ++k) {
162 EXPECT_FLOAT_EQ(z[k], z_avx2[k]);
163 EXPECT_FLOAT_EQ(x[k] * y[k], z_avx2[k]);
164 }
165 }
166 }
167
TEST(VectorMath,Sse2Accumulate)168 TEST(VectorMath, Sse2Accumulate) {
169 if (GetCPUInfo(kSSE2) != 0) {
170 std::array<float, kFftLengthBy2Plus1> x;
171 std::array<float, kFftLengthBy2Plus1> z;
172 std::array<float, kFftLengthBy2Plus1> z_sse2;
173
174 for (size_t k = 0; k < x.size(); ++k) {
175 x[k] = k;
176 z[k] = z_sse2[k] = 2.f * k;
177 }
178
179 aec3::VectorMath(Aec3Optimization::kNone).Accumulate(x, z);
180 aec3::VectorMath(Aec3Optimization::kSse2).Accumulate(x, z_sse2);
181 for (size_t k = 0; k < z.size(); ++k) {
182 EXPECT_FLOAT_EQ(z[k], z_sse2[k]);
183 EXPECT_FLOAT_EQ(x[k] + 2.f * x[k], z_sse2[k]);
184 }
185 }
186 }
187
TEST(VectorMath,Avx2Accumulate)188 TEST(VectorMath, Avx2Accumulate) {
189 if (GetCPUInfo(kAVX2) != 0) {
190 std::array<float, kFftLengthBy2Plus1> x;
191 std::array<float, kFftLengthBy2Plus1> z;
192 std::array<float, kFftLengthBy2Plus1> z_avx2;
193
194 for (size_t k = 0; k < x.size(); ++k) {
195 x[k] = k;
196 z[k] = z_avx2[k] = 2.f * k;
197 }
198
199 aec3::VectorMath(Aec3Optimization::kNone).Accumulate(x, z);
200 aec3::VectorMath(Aec3Optimization::kAvx2).Accumulate(x, z_avx2);
201 for (size_t k = 0; k < z.size(); ++k) {
202 EXPECT_FLOAT_EQ(z[k], z_avx2[k]);
203 EXPECT_FLOAT_EQ(x[k] + 2.f * x[k], z_avx2[k]);
204 }
205 }
206 }
207 #endif
208
209 } // namespace webrtc
210