Chromium Code Reviews| 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 |
| 23 namespace switches { | |
|
Ami GONE FROM CHROMIUM
2012/07/27 17:33:11
why?
DaleCurtis
2012/07/27 21:23:42
Saw it done this way elsewhere. Changed.
| |
| 24 // Allows runtime adjustment of iterations for the VectorFMACBenchmark test. | |
| 25 const char kVectorFMACIterations[] = "vector-fmac-iterations"; | |
| 26 } // namespace switches | |
| 27 | |
| 20 namespace media { | 28 namespace media { |
| 21 | 29 |
| 22 // Parameters which control the many input case tests. | 30 // Parameters which control the many input case tests. |
| 23 static const int kMixerInputs = 8; | 31 static const int kMixerInputs = 8; |
| 24 static const int kMixerCycles = 3; | 32 static const int kMixerCycles = 3; |
| 25 | 33 |
| 26 // Parameters used for testing. | 34 // Parameters used for testing. |
| 27 static const int kBitsPerChannel = 16; | 35 static const int kBitsPerChannel = 16; |
| 28 static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO; | 36 static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO; |
| 29 static const int kHighLatencyBufferSize = 8192; | 37 static const int kHighLatencyBufferSize = 8192; |
| 30 static const int kLowLatencyBufferSize = 256; | 38 static const int kLowLatencyBufferSize = 256; |
| 39 static const int kSampleRate = 48000; | |
| 31 | 40 |
| 32 // Number of full sine wave cycles for each Render() call. | 41 // Number of full sine wave cycles for each Render() call. |
| 33 static const int kSineCycles = 4; | 42 static const int kSineCycles = 4; |
| 34 | 43 |
| 44 // Ensure various optimized VectorFMAC() methods return the right value. | |
|
Ami GONE FROM CHROMIUM
2012/07/27 17:33:11
s/right/same/
DaleCurtis
2012/07/27 21:23:42
Done.
| |
| 45 TEST(AudioRendererMixerTest, VectorFMAC) { | |
| 46 // Initialize a dummy mixer. | |
| 47 scoped_refptr<MockAudioRendererSink> sink = new MockAudioRendererSink(); | |
| 48 EXPECT_CALL(*sink, Start()); | |
| 49 EXPECT_CALL(*sink, Stop()); | |
| 50 AudioParameters params( | |
| 51 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, | |
| 52 kBitsPerChannel, kHighLatencyBufferSize); | |
| 53 AudioRendererMixer mixer(params, params, sink); | |
| 54 | |
| 55 // Initialize input and output vectors. | |
| 56 scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> input_vector( | |
| 57 static_cast<float*>( | |
| 58 base::AlignedAlloc(sizeof(float) * kHighLatencyBufferSize, 16))); | |
| 59 scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> output_vector( | |
| 60 static_cast<float*>( | |
| 61 base::AlignedAlloc(sizeof(float) * kHighLatencyBufferSize, 16))); | |
| 62 | |
| 63 static const float kScale = 0.5; | |
| 64 static const float kFillValue = 1.0; | |
| 65 | |
| 66 // Fill input vector with 1.0, zero output vector | |
| 67 std::fill(input_vector.get(), input_vector.get() + kHighLatencyBufferSize, | |
| 68 kFillValue); | |
| 69 memset(output_vector.get(), 0, sizeof(float) * kHighLatencyBufferSize); | |
|
Ami GONE FROM CHROMIUM
2012/07/27 17:33:11
By init'd output with 0 you're avoiding testing th
DaleCurtis
2012/07/27 21:23:42
Done.
| |
| 70 mixer.VectorFMAC_C( | |
| 71 input_vector.get(), kScale, kHighLatencyBufferSize, output_vector.get()); | |
| 72 for(int i = 0; i < kHighLatencyBufferSize; ++i) | |
| 73 ASSERT_FLOAT_EQ(output_vector.get()[i], kScale); | |
| 74 | |
| 75 #if defined(ARCH_CPU_X86_FAMILY) && defined(__SSE__) | |
| 76 // Reset vectors, and try with SSE. | |
| 77 std::fill(input_vector.get(), input_vector.get() + kHighLatencyBufferSize, | |
|
Ami GONE FROM CHROMIUM
2012/07/27 17:33:11
Why is this necessary?
DaleCurtis
2012/07/27 21:23:42
Whoops, don't need to reset input vector, but outp
| |
| 78 kFillValue); | |
| 79 memset(output_vector.get(), 0, sizeof(float) * kHighLatencyBufferSize); | |
|
Ami GONE FROM CHROMIUM
2012/07/27 17:33:11
ditto
DaleCurtis
2012/07/27 21:23:42
Done.
| |
| 80 mixer.VectorFMAC_SSE( | |
| 81 input_vector.get(), kScale, kHighLatencyBufferSize, output_vector.get()); | |
| 82 for(int i = 0; i < kHighLatencyBufferSize; ++i) | |
| 83 ASSERT_FLOAT_EQ(output_vector.get()[i], kScale); | |
| 84 #endif | |
| 85 } | |
| 86 | |
| 87 // Benchmark for the various VectorFMAC() methods. Make sure to build with | |
| 88 // branding=Chrome so that DCHECKs are compiled out when benchmarking. Original | |
| 89 // benchmarks were run with --vector-fmac-iterations=200000. | |
| 90 TEST(AudioRendererMixerTest, VectorFMACBenchmark) { | |
| 91 // Initialize a dummy mixer. | |
| 92 scoped_refptr<MockAudioRendererSink> sink = new MockAudioRendererSink(); | |
| 93 EXPECT_CALL(*sink, Start()); | |
| 94 EXPECT_CALL(*sink, Stop()); | |
| 95 AudioParameters params( | |
| 96 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, | |
| 97 kBitsPerChannel, kHighLatencyBufferSize); | |
| 98 AudioRendererMixer mixer(params, params, sink); | |
| 99 | |
| 100 // Initialize input and output vectors. | |
| 101 scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> input_vector( | |
| 102 static_cast<float*>( | |
| 103 base::AlignedAlloc(sizeof(float) * kHighLatencyBufferSize, 16))); | |
| 104 scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> output_vector( | |
| 105 static_cast<float*>( | |
| 106 base::AlignedAlloc(sizeof(float) * kHighLatencyBufferSize, 16))); | |
| 107 | |
| 108 // Retrieve benchmark iterations from command line. | |
| 109 int vector_fmac_iterations = 10; | |
| 110 std::string iterations(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | |
| 111 switches::kVectorFMACIterations)); | |
| 112 if (!iterations.empty()) | |
| 113 base::StringToInt(iterations, &vector_fmac_iterations); | |
| 114 | |
| 115 printf("Benchmarking %d iterations:\n", vector_fmac_iterations); | |
| 116 | |
| 117 // Benchmark VectorFMAC_C(). | |
| 118 memset(input_vector.get(), 1, sizeof(float) * kHighLatencyBufferSize); | |
|
Ami GONE FROM CHROMIUM
2012/07/27 17:33:11
Are you intentionally testing inputs of inputs tha
DaleCurtis
2012/07/27 21:23:42
Yeah, just needed to initialize the array with som
| |
| 119 memset(output_vector.get(), 0, sizeof(float) * kHighLatencyBufferSize); | |
| 120 base::TimeTicks start = base::TimeTicks::HighResNow(); | |
| 121 for (int i = 0; i < vector_fmac_iterations; ++i) { | |
| 122 mixer.VectorFMAC_C(input_vector.get(), M_PI, kHighLatencyBufferSize, | |
| 123 output_vector.get()); | |
| 124 } | |
| 125 double total_time_c_ms = | |
| 126 (base::TimeTicks::HighResNow() - start).InMillisecondsF(); | |
| 127 printf("VectorFMAC_C took %.2fms.\n", total_time_c_ms); | |
| 128 | |
| 129 #if defined(ARCH_CPU_X86_FAMILY) && defined(__SSE__) | |
| 130 // Benchmark VectorFMAC_SSE() with unaligned size; I.e., size % 4 != 0. | |
|
Ami GONE FROM CHROMIUM
2012/07/27 17:33:11
Comment here that the API insists the head *is* al
DaleCurtis
2012/07/27 21:23:42
Seems redundant at this point, it's already in the
| |
| 131 ASSERT_NE((kHighLatencyBufferSize - 1) % 4, 0); | |
| 132 memset(input_vector.get(), 1, sizeof(float) * kHighLatencyBufferSize); | |
|
Ami GONE FROM CHROMIUM
2012/07/27 17:33:11
ditto
DaleCurtis
2012/07/27 21:23:42
Done.
| |
| 133 memset(output_vector.get(), 0, sizeof(float) * kHighLatencyBufferSize); | |
| 134 start = base::TimeTicks::HighResNow(); | |
| 135 for (int j = 0; j < vector_fmac_iterations; ++j) { | |
| 136 mixer.VectorFMAC_SSE(input_vector.get(), M_PI, kHighLatencyBufferSize - 1, | |
| 137 output_vector.get()); | |
| 138 } | |
| 139 double total_time_sse_unaligned_ms = | |
| 140 (base::TimeTicks::HighResNow() - start).InMillisecondsF(); | |
| 141 printf("VectorFMAC_SSE (unaligned size) took %.2fms; which is %.2fx faster" | |
| 142 " than VectorFMAC_C.\n", total_time_sse_unaligned_ms, | |
| 143 total_time_c_ms / total_time_sse_unaligned_ms); | |
| 144 | |
| 145 // Benchmark VectorFMAC_SSE() with aligned size; I.e., size % 4 == 0. | |
| 146 ASSERT_EQ(kHighLatencyBufferSize % 4, 0); | |
| 147 memset(input_vector.get(), 1, sizeof(float) * kHighLatencyBufferSize); | |
|
Ami GONE FROM CHROMIUM
2012/07/27 17:33:11
ditto
DaleCurtis
2012/07/27 21:23:42
Done.
| |
| 148 memset(output_vector.get(), 0, sizeof(float) * kHighLatencyBufferSize); | |
| 149 start = base::TimeTicks::HighResNow(); | |
| 150 for (int j = 0; j < vector_fmac_iterations; ++j) { | |
| 151 mixer.VectorFMAC_SSE(input_vector.get(), M_PI, kHighLatencyBufferSize, | |
| 152 output_vector.get()); | |
| 153 } | |
| 154 double total_time_sse_aligned_ms = | |
| 155 (base::TimeTicks::HighResNow() - start).InMillisecondsF(); | |
| 156 printf("VectorFMAC_SSE (aligned size) took %.2fms; which is %.2fx faster than" | |
| 157 " VectorFMAC_C and %.2fx faster than VectorFMAC_SSE (unaligned size)." | |
| 158 "\n", | |
| 159 total_time_sse_aligned_ms, total_time_c_ms / total_time_sse_aligned_ms, | |
| 160 total_time_sse_unaligned_ms / total_time_sse_aligned_ms); | |
| 161 #endif | |
| 162 } | |
| 163 | |
| 35 // Tuple of <input sampling rate, output sampling rate, epsilon>. | 164 // Tuple of <input sampling rate, output sampling rate, epsilon>. |
| 36 typedef std::tr1::tuple<int, int, double> AudioRendererMixerTestData; | 165 typedef std::tr1::tuple<int, int, double> AudioRendererMixerTestData; |
| 37 class AudioRendererMixerTest | 166 class AudioRendererMixerTest |
| 38 : public testing::TestWithParam<AudioRendererMixerTestData> { | 167 : public testing::TestWithParam<AudioRendererMixerTestData> { |
| 39 public: | 168 public: |
| 40 AudioRendererMixerTest() | 169 AudioRendererMixerTest() |
| 41 : epsilon_(std::tr1::get<2>(GetParam())), | 170 : epsilon_(std::tr1::get<2>(GetParam())), |
| 42 half_fill_(false) { | 171 half_fill_(false) { |
| 43 // Create input and output parameters based on test parameters. | 172 // Create input and output parameters based on test parameters. |
| 44 input_parameters_ = AudioParameters( | 173 input_parameters_ = AudioParameters( |
| (...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 412 // No resampling. | 541 // No resampling. |
| 413 std::tr1::make_tuple(44100, 44100, 0.00000048), | 542 std::tr1::make_tuple(44100, 44100, 0.00000048), |
| 414 | 543 |
| 415 // Upsampling. | 544 // Upsampling. |
| 416 std::tr1::make_tuple(44100, 48000, 0.033), | 545 std::tr1::make_tuple(44100, 48000, 0.033), |
| 417 | 546 |
| 418 // Downsampling. | 547 // Downsampling. |
| 419 std::tr1::make_tuple(48000, 41000, 0.042))); | 548 std::tr1::make_tuple(48000, 41000, 0.042))); |
| 420 | 549 |
| 421 } // namespace media | 550 } // namespace media |
| OLD | NEW |