OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // MSVC++ requires this to be set before any other includes to get M_PI. | 5 // MSVC++ requires this to be set before any other includes to get M_PI. |
6 #define _USE_MATH_DEFINES | 6 #define _USE_MATH_DEFINES |
7 #include <cmath> | 7 #include <cmath> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
| 11 #include "base/command_line.h" |
| 12 #include "base/memory/aligned_memory.h" |
11 #include "base/memory/scoped_ptr.h" | 13 #include "base/memory/scoped_ptr.h" |
12 #include "base/memory/scoped_vector.h" | 14 #include "base/memory/scoped_vector.h" |
| 15 #include "base/string_number_conversions.h" |
13 #include "media/base/audio_renderer_mixer.h" | 16 #include "media/base/audio_renderer_mixer.h" |
14 #include "media/base/audio_renderer_mixer_input.h" | 17 #include "media/base/audio_renderer_mixer_input.h" |
15 #include "media/base/fake_audio_render_callback.h" | 18 #include "media/base/fake_audio_render_callback.h" |
16 #include "media/base/mock_audio_renderer_sink.h" | 19 #include "media/base/mock_audio_renderer_sink.h" |
17 #include "testing/gmock/include/gmock/gmock.h" | 20 #include "testing/gmock/include/gmock/gmock.h" |
18 #include "testing/gtest/include/gtest/gtest.h" | 21 #include "testing/gtest/include/gtest/gtest.h" |
19 | 22 |
20 namespace media { | 23 namespace media { |
21 | 24 |
22 // Parameters which control the many input case tests. | 25 // Parameters which control the many input case tests. |
23 static const int kMixerInputs = 8; | 26 static const int kMixerInputs = 8; |
24 static const int kMixerCycles = 3; | 27 static const int kMixerCycles = 3; |
25 | 28 |
26 // Parameters used for testing. | 29 // Parameters used for testing. |
27 static const int kBitsPerChannel = 16; | 30 static const int kBitsPerChannel = 16; |
28 static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO; | 31 static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO; |
29 static const int kHighLatencyBufferSize = 8192; | 32 static const int kHighLatencyBufferSize = 8192; |
30 static const int kLowLatencyBufferSize = 256; | 33 static const int kLowLatencyBufferSize = 256; |
| 34 static const int kSampleRate = 48000; |
31 | 35 |
32 // Number of full sine wave cycles for each Render() call. | 36 // Number of full sine wave cycles for each Render() call. |
33 static const int kSineCycles = 4; | 37 static const int kSineCycles = 4; |
34 | 38 |
| 39 // Command line switch for runtime adjustment of VectorFMACBenchmark iterations. |
| 40 static const char kVectorFMACIterations[] = "vector-fmac-iterations"; |
| 41 |
| 42 // Test parameters for VectorFMAC tests. |
| 43 static const float kScale = 0.5; |
| 44 static const float kInputFillValue = 1.0; |
| 45 static const float kOutputFillValue = 3.0; |
| 46 |
| 47 // Ensure various optimized VectorFMAC() methods return the same value. |
| 48 TEST(AudioRendererMixerTest, VectorFMAC) { |
| 49 // Initialize a dummy mixer. |
| 50 scoped_refptr<MockAudioRendererSink> sink = new MockAudioRendererSink(); |
| 51 EXPECT_CALL(*sink, Start()); |
| 52 EXPECT_CALL(*sink, Stop()); |
| 53 AudioParameters params( |
| 54 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, |
| 55 kBitsPerChannel, kHighLatencyBufferSize); |
| 56 AudioRendererMixer mixer(params, params, sink); |
| 57 |
| 58 // Initialize input and output vectors. |
| 59 scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> input_vector( |
| 60 static_cast<float*>( |
| 61 base::AlignedAlloc(sizeof(float) * kHighLatencyBufferSize, 16))); |
| 62 scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> output_vector( |
| 63 static_cast<float*>( |
| 64 base::AlignedAlloc(sizeof(float) * kHighLatencyBufferSize, 16))); |
| 65 |
| 66 // Setup input and output vectors. |
| 67 std::fill(input_vector.get(), input_vector.get() + kHighLatencyBufferSize, |
| 68 kInputFillValue); |
| 69 std::fill(output_vector.get(), output_vector.get() + kHighLatencyBufferSize, |
| 70 kOutputFillValue); |
| 71 mixer.VectorFMAC_C( |
| 72 *input_vector.get(), kScale, kHighLatencyBufferSize, output_vector.get()); |
| 73 for(int i = 0; i < kHighLatencyBufferSize; ++i) { |
| 74 ASSERT_FLOAT_EQ(output_vector.get()[i], |
| 75 kInputFillValue * kScale + kOutputFillValue); |
| 76 } |
| 77 |
| 78 #if defined(ARCH_CPU_X86_FAMILY) && defined(__SSE__) |
| 79 // Reset vectors, and try with SSE. |
| 80 std::fill(output_vector.get(), output_vector.get() + kHighLatencyBufferSize, |
| 81 kOutputFillValue); |
| 82 mixer.VectorFMAC_SSE( |
| 83 *input_vector.get(), kScale, kHighLatencyBufferSize, output_vector.get()); |
| 84 for(int i = 0; i < kHighLatencyBufferSize; ++i) { |
| 85 ASSERT_FLOAT_EQ(output_vector.get()[i], |
| 86 kInputFillValue * kScale + kOutputFillValue); |
| 87 } |
| 88 #endif |
| 89 } |
| 90 |
| 91 // Benchmark for the various VectorFMAC() methods. Make sure to build with |
| 92 // branding=Chrome so that DCHECKs are compiled out when benchmarking. Original |
| 93 // benchmarks were run with --vector-fmac-iterations=200000. |
| 94 TEST(AudioRendererMixerTest, VectorFMACBenchmark) { |
| 95 // Initialize a dummy mixer. |
| 96 scoped_refptr<MockAudioRendererSink> sink = new MockAudioRendererSink(); |
| 97 EXPECT_CALL(*sink, Start()); |
| 98 EXPECT_CALL(*sink, Stop()); |
| 99 AudioParameters params( |
| 100 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, |
| 101 kBitsPerChannel, kHighLatencyBufferSize); |
| 102 AudioRendererMixer mixer(params, params, sink); |
| 103 |
| 104 // Initialize input and output vectors. |
| 105 scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> input_vector( |
| 106 static_cast<float*>( |
| 107 base::AlignedAlloc(sizeof(float) * kHighLatencyBufferSize, 16))); |
| 108 scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> output_vector( |
| 109 static_cast<float*>( |
| 110 base::AlignedAlloc(sizeof(float) * kHighLatencyBufferSize, 16))); |
| 111 |
| 112 // Retrieve benchmark iterations from command line. |
| 113 int vector_fmac_iterations = 10; |
| 114 std::string iterations(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| 115 kVectorFMACIterations)); |
| 116 if (!iterations.empty()) |
| 117 base::StringToInt(iterations, &vector_fmac_iterations); |
| 118 |
| 119 printf("Benchmarking %d iterations:\n", vector_fmac_iterations); |
| 120 |
| 121 // Benchmark VectorFMAC_C(). |
| 122 std::fill(input_vector.get(), input_vector.get() + kHighLatencyBufferSize, |
| 123 kInputFillValue); |
| 124 std::fill(output_vector.get(), output_vector.get() + kHighLatencyBufferSize, |
| 125 kOutputFillValue); |
| 126 base::TimeTicks start = base::TimeTicks::HighResNow(); |
| 127 for (int i = 0; i < vector_fmac_iterations; ++i) { |
| 128 mixer.VectorFMAC_C(*input_vector.get(), M_PI, kHighLatencyBufferSize, |
| 129 output_vector.get()); |
| 130 } |
| 131 double total_time_c_ms = |
| 132 (base::TimeTicks::HighResNow() - start).InMillisecondsF(); |
| 133 printf("VectorFMAC_C took %.2fms.\n", total_time_c_ms); |
| 134 |
| 135 #if defined(ARCH_CPU_X86_FAMILY) && defined(__SSE__) |
| 136 // Benchmark VectorFMAC_SSE() with unaligned size; I.e., size % 4 != 0. |
| 137 ASSERT_NE((kHighLatencyBufferSize - 1) % 4, 0); |
| 138 std::fill(output_vector.get(), output_vector.get() + kHighLatencyBufferSize, |
| 139 kOutputFillValue); |
| 140 start = base::TimeTicks::HighResNow(); |
| 141 for (int j = 0; j < vector_fmac_iterations; ++j) { |
| 142 mixer.VectorFMAC_SSE(*input_vector.get(), M_PI, kHighLatencyBufferSize - 1, |
| 143 output_vector.get()); |
| 144 } |
| 145 double total_time_sse_unaligned_ms = |
| 146 (base::TimeTicks::HighResNow() - start).InMillisecondsF(); |
| 147 printf("VectorFMAC_SSE (unaligned size) took %.2fms; which is %.2fx faster" |
| 148 " than VectorFMAC_C.\n", total_time_sse_unaligned_ms, |
| 149 total_time_c_ms / total_time_sse_unaligned_ms); |
| 150 |
| 151 // Benchmark VectorFMAC_SSE() with aligned size; I.e., size % 4 == 0. |
| 152 ASSERT_EQ(kHighLatencyBufferSize % 4, 0); |
| 153 std::fill(output_vector.get(), output_vector.get() + kHighLatencyBufferSize, |
| 154 kOutputFillValue); |
| 155 start = base::TimeTicks::HighResNow(); |
| 156 for (int j = 0; j < vector_fmac_iterations; ++j) { |
| 157 mixer.VectorFMAC_SSE(*input_vector.get(), M_PI, kHighLatencyBufferSize, |
| 158 output_vector.get()); |
| 159 } |
| 160 double total_time_sse_aligned_ms = |
| 161 (base::TimeTicks::HighResNow() - start).InMillisecondsF(); |
| 162 printf("VectorFMAC_SSE (aligned size) took %.2fms; which is %.2fx faster than" |
| 163 " VectorFMAC_C and %.2fx faster than VectorFMAC_SSE (unaligned size)." |
| 164 "\n", |
| 165 total_time_sse_aligned_ms, total_time_c_ms / total_time_sse_aligned_ms, |
| 166 total_time_sse_unaligned_ms / total_time_sse_aligned_ms); |
| 167 #endif |
| 168 } |
| 169 |
35 // Tuple of <input sampling rate, output sampling rate, epsilon>. | 170 // Tuple of <input sampling rate, output sampling rate, epsilon>. |
36 typedef std::tr1::tuple<int, int, double> AudioRendererMixerTestData; | 171 typedef std::tr1::tuple<int, int, double> AudioRendererMixerTestData; |
37 class AudioRendererMixerTest | 172 class AudioRendererMixerTest |
38 : public testing::TestWithParam<AudioRendererMixerTestData> { | 173 : public testing::TestWithParam<AudioRendererMixerTestData> { |
39 public: | 174 public: |
40 AudioRendererMixerTest() | 175 AudioRendererMixerTest() |
41 : epsilon_(std::tr1::get<2>(GetParam())), | 176 : epsilon_(std::tr1::get<2>(GetParam())), |
42 half_fill_(false) { | 177 half_fill_(false) { |
43 // Create input and output parameters based on test parameters. | 178 // Create input and output parameters based on test parameters. |
44 input_parameters_ = AudioParameters( | 179 input_parameters_ = AudioParameters( |
(...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
412 // No resampling. | 547 // No resampling. |
413 std::tr1::make_tuple(44100, 44100, 0.00000048), | 548 std::tr1::make_tuple(44100, 44100, 0.00000048), |
414 | 549 |
415 // Upsampling. | 550 // Upsampling. |
416 std::tr1::make_tuple(44100, 48000, 0.033), | 551 std::tr1::make_tuple(44100, 48000, 0.033), |
417 | 552 |
418 // Downsampling. | 553 // Downsampling. |
419 std::tr1::make_tuple(48000, 41000, 0.042))); | 554 std::tr1::make_tuple(48000, 41000, 0.042))); |
420 | 555 |
421 } // namespace media | 556 } // namespace media |
OLD | NEW |