Add details (where missing) for histograms and remove a few that are not worth provid...
[chromium-blink-merge.git] / media / base / vector_math_unittest.cc
blob95433ca475ed0b5b03b7db52016fc1519c8ac046
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // MSVC++ requires this to be set before any other includes to get M_PI.
6 #define _USE_MATH_DEFINES
7 #include <cmath>
9 #include "base/cpu.h"
10 #include "base/memory/aligned_memory.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/stringize_macros.h"
14 #include "media/base/vector_math.h"
15 #include "media/base/vector_math_testing.h"
16 #include "testing/gtest/include/gtest/gtest.h"
18 using std::fill;
20 namespace media {
22 // Default test values.
23 static const float kScale = 0.5;
24 static const float kInputFillValue = 1.0;
25 static const float kOutputFillValue = 3.0;
26 static const int kVectorSize = 8192;
28 class VectorMathTest : public testing::Test {
29 public:
31 VectorMathTest() {
32 // Initialize input and output vectors.
33 input_vector_.reset(static_cast<float*>(base::AlignedAlloc(
34 sizeof(float) * kVectorSize, vector_math::kRequiredAlignment)));
35 output_vector_.reset(static_cast<float*>(base::AlignedAlloc(
36 sizeof(float) * kVectorSize, vector_math::kRequiredAlignment)));
39 void FillTestVectors(float input, float output) {
40 // Setup input and output vectors.
41 fill(input_vector_.get(), input_vector_.get() + kVectorSize, input);
42 fill(output_vector_.get(), output_vector_.get() + kVectorSize, output);
45 void VerifyOutput(float value) {
46 for (int i = 0; i < kVectorSize; ++i)
47 ASSERT_FLOAT_EQ(output_vector_[i], value);
50 protected:
51 scoped_ptr<float[], base::AlignedFreeDeleter> input_vector_;
52 scoped_ptr<float[], base::AlignedFreeDeleter> output_vector_;
54 DISALLOW_COPY_AND_ASSIGN(VectorMathTest);
57 // Ensure each optimized vector_math::FMAC() method returns the same value.
58 TEST_F(VectorMathTest, FMAC) {
59 static const float kResult = kInputFillValue * kScale + kOutputFillValue;
62 SCOPED_TRACE("FMAC");
63 FillTestVectors(kInputFillValue, kOutputFillValue);
64 vector_math::FMAC(
65 input_vector_.get(), kScale, kVectorSize, output_vector_.get());
66 VerifyOutput(kResult);
70 SCOPED_TRACE("FMAC_C");
71 FillTestVectors(kInputFillValue, kOutputFillValue);
72 vector_math::FMAC_C(
73 input_vector_.get(), kScale, kVectorSize, output_vector_.get());
74 VerifyOutput(kResult);
77 #if defined(ARCH_CPU_X86_FAMILY)
79 ASSERT_TRUE(base::CPU().has_sse());
80 SCOPED_TRACE("FMAC_SSE");
81 FillTestVectors(kInputFillValue, kOutputFillValue);
82 vector_math::FMAC_SSE(
83 input_vector_.get(), kScale, kVectorSize, output_vector_.get());
84 VerifyOutput(kResult);
86 #endif
88 #if defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON)
90 SCOPED_TRACE("FMAC_NEON");
91 FillTestVectors(kInputFillValue, kOutputFillValue);
92 vector_math::FMAC_NEON(
93 input_vector_.get(), kScale, kVectorSize, output_vector_.get());
94 VerifyOutput(kResult);
96 #endif
99 // Ensure each optimized vector_math::FMUL() method returns the same value.
100 TEST_F(VectorMathTest, FMUL) {
101 static const float kResult = kInputFillValue * kScale;
104 SCOPED_TRACE("FMUL");
105 FillTestVectors(kInputFillValue, kOutputFillValue);
106 vector_math::FMUL(
107 input_vector_.get(), kScale, kVectorSize, output_vector_.get());
108 VerifyOutput(kResult);
112 SCOPED_TRACE("FMUL_C");
113 FillTestVectors(kInputFillValue, kOutputFillValue);
114 vector_math::FMUL_C(
115 input_vector_.get(), kScale, kVectorSize, output_vector_.get());
116 VerifyOutput(kResult);
119 #if defined(ARCH_CPU_X86_FAMILY)
121 ASSERT_TRUE(base::CPU().has_sse());
122 SCOPED_TRACE("FMUL_SSE");
123 FillTestVectors(kInputFillValue, kOutputFillValue);
124 vector_math::FMUL_SSE(
125 input_vector_.get(), kScale, kVectorSize, output_vector_.get());
126 VerifyOutput(kResult);
128 #endif
130 #if defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON)
132 SCOPED_TRACE("FMUL_NEON");
133 FillTestVectors(kInputFillValue, kOutputFillValue);
134 vector_math::FMUL_NEON(
135 input_vector_.get(), kScale, kVectorSize, output_vector_.get());
136 VerifyOutput(kResult);
138 #endif
141 TEST_F(VectorMathTest, Crossfade) {
142 FillTestVectors(0, 1);
143 vector_math::Crossfade(
144 input_vector_.get(), kVectorSize, output_vector_.get());
145 for (int i = 0; i < kVectorSize; ++i) {
146 ASSERT_FLOAT_EQ(i / static_cast<float>(kVectorSize), output_vector_[i])
147 << "i=" << i;
151 class EWMATestScenario {
152 public:
153 EWMATestScenario(float initial_value, const float src[], int len,
154 float smoothing_factor)
155 : initial_value_(initial_value),
156 data_(static_cast<float*>(
157 len == 0 ? NULL :
158 base::AlignedAlloc(len * sizeof(float),
159 vector_math::kRequiredAlignment))),
160 data_len_(len),
161 smoothing_factor_(smoothing_factor),
162 expected_final_avg_(initial_value),
163 expected_max_(0.0f) {
164 if (data_len_ > 0)
165 memcpy(data_.get(), src, len * sizeof(float));
168 // Copy constructor and assignment operator for ::testing::Values(...).
169 EWMATestScenario(const EWMATestScenario& other) { *this = other; }
170 EWMATestScenario& operator=(const EWMATestScenario& other) {
171 this->initial_value_ = other.initial_value_;
172 this->smoothing_factor_ = other.smoothing_factor_;
173 if (other.data_len_ == 0) {
174 this->data_.reset();
175 } else {
176 this->data_.reset(static_cast<float*>(
177 base::AlignedAlloc(other.data_len_ * sizeof(float),
178 vector_math::kRequiredAlignment)));
179 memcpy(this->data_.get(), other.data_.get(),
180 other.data_len_ * sizeof(float));
182 this->data_len_ = other.data_len_;
183 this->expected_final_avg_ = other.expected_final_avg_;
184 this->expected_max_ = other.expected_max_;
185 return *this;
188 EWMATestScenario ScaledBy(float scale) const {
189 EWMATestScenario result(*this);
190 float* p = result.data_.get();
191 float* const p_end = p + result.data_len_;
192 for (; p < p_end; ++p)
193 *p *= scale;
194 return result;
197 EWMATestScenario WithImpulse(float value, int offset) const {
198 EWMATestScenario result(*this);
199 result.data_.get()[offset] = value;
200 return result;
203 EWMATestScenario HasExpectedResult(float final_avg_value,
204 float max_value) const {
205 EWMATestScenario result(*this);
206 result.expected_final_avg_ = final_avg_value;
207 result.expected_max_ = max_value;
208 return result;
211 void RunTest() const {
213 SCOPED_TRACE("EWMAAndMaxPower");
214 const std::pair<float, float>& result = vector_math::EWMAAndMaxPower(
215 initial_value_, data_.get(), data_len_, smoothing_factor_);
216 EXPECT_NEAR(expected_final_avg_, result.first, 0.0000001f);
217 EXPECT_NEAR(expected_max_, result.second, 0.0000001f);
221 SCOPED_TRACE("EWMAAndMaxPower_C");
222 const std::pair<float, float>& result = vector_math::EWMAAndMaxPower_C(
223 initial_value_, data_.get(), data_len_, smoothing_factor_);
224 EXPECT_NEAR(expected_final_avg_, result.first, 0.0000001f);
225 EXPECT_NEAR(expected_max_, result.second, 0.0000001f);
228 #if defined(ARCH_CPU_X86_FAMILY)
230 ASSERT_TRUE(base::CPU().has_sse());
231 SCOPED_TRACE("EWMAAndMaxPower_SSE");
232 const std::pair<float, float>& result = vector_math::EWMAAndMaxPower_SSE(
233 initial_value_, data_.get(), data_len_, smoothing_factor_);
234 EXPECT_NEAR(expected_final_avg_, result.first, 0.0000001f);
235 EXPECT_NEAR(expected_max_, result.second, 0.0000001f);
237 #endif
239 #if defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON)
241 SCOPED_TRACE("EWMAAndMaxPower_NEON");
242 const std::pair<float, float>& result = vector_math::EWMAAndMaxPower_NEON(
243 initial_value_, data_.get(), data_len_, smoothing_factor_);
244 EXPECT_NEAR(expected_final_avg_, result.first, 0.0000001f);
245 EXPECT_NEAR(expected_max_, result.second, 0.0000001f);
247 #endif
250 private:
251 float initial_value_;
252 scoped_ptr<float, base::AlignedFreeDeleter> data_;
253 int data_len_;
254 float smoothing_factor_;
255 float expected_final_avg_;
256 float expected_max_;
259 typedef testing::TestWithParam<EWMATestScenario> VectorMathEWMAAndMaxPowerTest;
261 TEST_P(VectorMathEWMAAndMaxPowerTest, Correctness) {
262 GetParam().RunTest();
265 static const float kZeros[] = { // 32 zeros
266 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
267 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
270 static const float kOnes[] = { // 32 ones
271 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
272 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
275 static const float kCheckerboard[] = { // 32 alternating 0, 1
276 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
277 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1
280 static const float kInverseCheckerboard[] = { // 32 alternating 1, 0
281 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
282 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0
285 INSTANTIATE_TEST_CASE_P(
286 Scenarios, VectorMathEWMAAndMaxPowerTest,
287 ::testing::Values(
288 // Zero-length input: Result should equal initial value.
289 EWMATestScenario(0.0f, NULL, 0, 0.0f).HasExpectedResult(0.0f, 0.0f),
290 EWMATestScenario(1.0f, NULL, 0, 0.0f).HasExpectedResult(1.0f, 0.0f),
292 // Smoothing factor of zero: Samples have no effect on result.
293 EWMATestScenario(0.0f, kOnes, 32, 0.0f).HasExpectedResult(0.0f, 1.0f),
294 EWMATestScenario(1.0f, kZeros, 32, 0.0f).HasExpectedResult(1.0f, 0.0f),
296 // Smothing factor of one: Result = last sample squared.
297 EWMATestScenario(0.0f, kCheckerboard, 32, 1.0f)
298 .ScaledBy(2.0f)
299 .HasExpectedResult(4.0f, 4.0f),
300 EWMATestScenario(1.0f, kInverseCheckerboard, 32, 1.0f)
301 .ScaledBy(2.0f)
302 .HasExpectedResult(0.0f, 4.0f),
304 // Smoothing factor of 1/4, muted signal.
305 EWMATestScenario(1.0f, kZeros, 1, 0.25f)
306 .HasExpectedResult(powf(0.75, 1.0f), 0.0f),
307 EWMATestScenario(1.0f, kZeros, 2, 0.25f)
308 .HasExpectedResult(powf(0.75, 2.0f), 0.0f),
309 EWMATestScenario(1.0f, kZeros, 3, 0.25f)
310 .HasExpectedResult(powf(0.75, 3.0f), 0.0f),
311 EWMATestScenario(1.0f, kZeros, 12, 0.25f)
312 .HasExpectedResult(powf(0.75, 12.0f), 0.0f),
313 EWMATestScenario(1.0f, kZeros, 13, 0.25f)
314 .HasExpectedResult(powf(0.75, 13.0f), 0.0f),
315 EWMATestScenario(1.0f, kZeros, 14, 0.25f)
316 .HasExpectedResult(powf(0.75, 14.0f), 0.0f),
317 EWMATestScenario(1.0f, kZeros, 15, 0.25f)
318 .HasExpectedResult(powf(0.75, 15.0f), 0.0f),
320 // Smoothing factor of 1/4, constant full-amplitude signal.
321 EWMATestScenario(0.0f, kOnes, 1, 0.25f).HasExpectedResult(0.25f, 1.0f),
322 EWMATestScenario(0.0f, kOnes, 2, 0.25f)
323 .HasExpectedResult(0.4375f, 1.0f),
324 EWMATestScenario(0.0f, kOnes, 3, 0.25f)
325 .HasExpectedResult(0.578125f, 1.0f),
326 EWMATestScenario(0.0f, kOnes, 12, 0.25f)
327 .HasExpectedResult(0.96832365f, 1.0f),
328 EWMATestScenario(0.0f, kOnes, 13, 0.25f)
329 .HasExpectedResult(0.97624274f, 1.0f),
330 EWMATestScenario(0.0f, kOnes, 14, 0.25f)
331 .HasExpectedResult(0.98218205f, 1.0f),
332 EWMATestScenario(0.0f, kOnes, 15, 0.25f)
333 .HasExpectedResult(0.98663654f, 1.0f),
335 // Smoothing factor of 1/4, checkerboard signal.
336 EWMATestScenario(0.0f, kCheckerboard, 1, 0.25f)
337 .HasExpectedResult(0.0f, 0.0f),
338 EWMATestScenario(0.0f, kCheckerboard, 2, 0.25f)
339 .HasExpectedResult(0.25f, 1.0f),
340 EWMATestScenario(0.0f, kCheckerboard, 3, 0.25f)
341 .HasExpectedResult(0.1875f, 1.0f),
342 EWMATestScenario(0.0f, kCheckerboard, 12, 0.25f)
343 .HasExpectedResult(0.55332780f, 1.0f),
344 EWMATestScenario(0.0f, kCheckerboard, 13, 0.25f)
345 .HasExpectedResult(0.41499585f, 1.0f),
346 EWMATestScenario(0.0f, kCheckerboard, 14, 0.25f)
347 .HasExpectedResult(0.56124689f, 1.0f),
348 EWMATestScenario(0.0f, kCheckerboard, 15, 0.25f)
349 .HasExpectedResult(0.42093517f, 1.0f),
351 // Smoothing factor of 1/4, inverse checkerboard signal.
352 EWMATestScenario(0.0f, kInverseCheckerboard, 1, 0.25f)
353 .HasExpectedResult(0.25f, 1.0f),
354 EWMATestScenario(0.0f, kInverseCheckerboard, 2, 0.25f)
355 .HasExpectedResult(0.1875f, 1.0f),
356 EWMATestScenario(0.0f, kInverseCheckerboard, 3, 0.25f)
357 .HasExpectedResult(0.390625f, 1.0f),
358 EWMATestScenario(0.0f, kInverseCheckerboard, 12, 0.25f)
359 .HasExpectedResult(0.41499585f, 1.0f),
360 EWMATestScenario(0.0f, kInverseCheckerboard, 13, 0.25f)
361 .HasExpectedResult(0.56124689f, 1.0f),
362 EWMATestScenario(0.0f, kInverseCheckerboard, 14, 0.25f)
363 .HasExpectedResult(0.42093517f, 1.0f),
364 EWMATestScenario(0.0f, kInverseCheckerboard, 15, 0.25f)
365 .HasExpectedResult(0.56570137f, 1.0f),
367 // Smoothing factor of 1/4, impluse signal.
368 EWMATestScenario(0.0f, kZeros, 3, 0.25f)
369 .WithImpulse(2.0f, 0)
370 .HasExpectedResult(0.562500f, 4.0f),
371 EWMATestScenario(0.0f, kZeros, 3, 0.25f)
372 .WithImpulse(2.0f, 1)
373 .HasExpectedResult(0.75f, 4.0f),
374 EWMATestScenario(0.0f, kZeros, 3, 0.25f)
375 .WithImpulse(2.0f, 2)
376 .HasExpectedResult(1.0f, 4.0f),
377 EWMATestScenario(0.0f, kZeros, 32, 0.25f)
378 .WithImpulse(2.0f, 0)
379 .HasExpectedResult(0.00013394f, 4.0f),
380 EWMATestScenario(0.0f, kZeros, 32, 0.25f)
381 .WithImpulse(2.0f, 1)
382 .HasExpectedResult(0.00017858f, 4.0f),
383 EWMATestScenario(0.0f, kZeros, 32, 0.25f)
384 .WithImpulse(2.0f, 2)
385 .HasExpectedResult(0.00023811f, 4.0f),
386 EWMATestScenario(0.0f, kZeros, 32, 0.25f)
387 .WithImpulse(2.0f, 3)
388 .HasExpectedResult(0.00031748f, 4.0f)
391 } // namespace media