Chromium Code Reviews| Index: media/base/audio_renderer_mixer_unittest.cc |
| diff --git a/media/base/audio_renderer_mixer_unittest.cc b/media/base/audio_renderer_mixer_unittest.cc |
| index 51d06e0d63fc4da7626600972a3189f8028c14c2..6be81dba23e5d24de12576ce1839ff2737282fcc 100644 |
| --- a/media/base/audio_renderer_mixer_unittest.cc |
| +++ b/media/base/audio_renderer_mixer_unittest.cc |
| @@ -8,8 +8,11 @@ |
| #include "base/bind.h" |
| #include "base/bind_helpers.h" |
| +#include "base/command_line.h" |
| +#include "base/memory/aligned_memory.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/memory/scoped_vector.h" |
| +#include "base/string_number_conversions.h" |
| #include "media/base/audio_renderer_mixer.h" |
| #include "media/base/audio_renderer_mixer_input.h" |
| #include "media/base/fake_audio_render_callback.h" |
| @@ -17,6 +20,11 @@ |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| +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.
|
| +// Allows runtime adjustment of iterations for the VectorFMACBenchmark test. |
| +const char kVectorFMACIterations[] = "vector-fmac-iterations"; |
| +} // namespace switches |
| + |
| namespace media { |
| // Parameters which control the many input case tests. |
| @@ -28,10 +36,131 @@ static const int kBitsPerChannel = 16; |
| static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO; |
| static const int kHighLatencyBufferSize = 8192; |
| static const int kLowLatencyBufferSize = 256; |
| +static const int kSampleRate = 48000; |
| // Number of full sine wave cycles for each Render() call. |
| static const int kSineCycles = 4; |
| +// 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.
|
| +TEST(AudioRendererMixerTest, VectorFMAC) { |
| + // Initialize a dummy mixer. |
| + scoped_refptr<MockAudioRendererSink> sink = new MockAudioRendererSink(); |
| + EXPECT_CALL(*sink, Start()); |
| + EXPECT_CALL(*sink, Stop()); |
| + AudioParameters params( |
| + AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, |
| + kBitsPerChannel, kHighLatencyBufferSize); |
| + AudioRendererMixer mixer(params, params, sink); |
| + |
| + // Initialize input and output vectors. |
| + scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> input_vector( |
| + static_cast<float*>( |
| + base::AlignedAlloc(sizeof(float) * kHighLatencyBufferSize, 16))); |
| + scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> output_vector( |
| + static_cast<float*>( |
| + base::AlignedAlloc(sizeof(float) * kHighLatencyBufferSize, 16))); |
| + |
| + static const float kScale = 0.5; |
| + static const float kFillValue = 1.0; |
| + |
| + // Fill input vector with 1.0, zero output vector |
| + std::fill(input_vector.get(), input_vector.get() + kHighLatencyBufferSize, |
| + kFillValue); |
| + 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.
|
| + mixer.VectorFMAC_C( |
| + input_vector.get(), kScale, kHighLatencyBufferSize, output_vector.get()); |
| + for(int i = 0; i < kHighLatencyBufferSize; ++i) |
| + ASSERT_FLOAT_EQ(output_vector.get()[i], kScale); |
| + |
| +#if defined(ARCH_CPU_X86_FAMILY) && defined(__SSE__) |
| + // Reset vectors, and try with SSE. |
| + 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
|
| + kFillValue); |
| + 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.
|
| + mixer.VectorFMAC_SSE( |
| + input_vector.get(), kScale, kHighLatencyBufferSize, output_vector.get()); |
| + for(int i = 0; i < kHighLatencyBufferSize; ++i) |
| + ASSERT_FLOAT_EQ(output_vector.get()[i], kScale); |
| +#endif |
| +} |
| + |
| +// Benchmark for the various VectorFMAC() methods. Make sure to build with |
| +// branding=Chrome so that DCHECKs are compiled out when benchmarking. Original |
| +// benchmarks were run with --vector-fmac-iterations=200000. |
| +TEST(AudioRendererMixerTest, VectorFMACBenchmark) { |
| + // Initialize a dummy mixer. |
| + scoped_refptr<MockAudioRendererSink> sink = new MockAudioRendererSink(); |
| + EXPECT_CALL(*sink, Start()); |
| + EXPECT_CALL(*sink, Stop()); |
| + AudioParameters params( |
| + AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, |
| + kBitsPerChannel, kHighLatencyBufferSize); |
| + AudioRendererMixer mixer(params, params, sink); |
| + |
| + // Initialize input and output vectors. |
| + scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> input_vector( |
| + static_cast<float*>( |
| + base::AlignedAlloc(sizeof(float) * kHighLatencyBufferSize, 16))); |
| + scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> output_vector( |
| + static_cast<float*>( |
| + base::AlignedAlloc(sizeof(float) * kHighLatencyBufferSize, 16))); |
| + |
| + // Retrieve benchmark iterations from command line. |
| + int vector_fmac_iterations = 10; |
| + std::string iterations(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| + switches::kVectorFMACIterations)); |
| + if (!iterations.empty()) |
| + base::StringToInt(iterations, &vector_fmac_iterations); |
| + |
| + printf("Benchmarking %d iterations:\n", vector_fmac_iterations); |
| + |
| + // Benchmark VectorFMAC_C(). |
| + 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
|
| + memset(output_vector.get(), 0, sizeof(float) * kHighLatencyBufferSize); |
| + base::TimeTicks start = base::TimeTicks::HighResNow(); |
| + for (int i = 0; i < vector_fmac_iterations; ++i) { |
| + mixer.VectorFMAC_C(input_vector.get(), M_PI, kHighLatencyBufferSize, |
| + output_vector.get()); |
| + } |
| + double total_time_c_ms = |
| + (base::TimeTicks::HighResNow() - start).InMillisecondsF(); |
| + printf("VectorFMAC_C took %.2fms.\n", total_time_c_ms); |
| + |
| +#if defined(ARCH_CPU_X86_FAMILY) && defined(__SSE__) |
| + // 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
|
| + ASSERT_NE((kHighLatencyBufferSize - 1) % 4, 0); |
| + 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.
|
| + memset(output_vector.get(), 0, sizeof(float) * kHighLatencyBufferSize); |
| + start = base::TimeTicks::HighResNow(); |
| + for (int j = 0; j < vector_fmac_iterations; ++j) { |
| + mixer.VectorFMAC_SSE(input_vector.get(), M_PI, kHighLatencyBufferSize - 1, |
| + output_vector.get()); |
| + } |
| + double total_time_sse_unaligned_ms = |
| + (base::TimeTicks::HighResNow() - start).InMillisecondsF(); |
| + printf("VectorFMAC_SSE (unaligned size) took %.2fms; which is %.2fx faster" |
| + " than VectorFMAC_C.\n", total_time_sse_unaligned_ms, |
| + total_time_c_ms / total_time_sse_unaligned_ms); |
| + |
| + // Benchmark VectorFMAC_SSE() with aligned size; I.e., size % 4 == 0. |
| + ASSERT_EQ(kHighLatencyBufferSize % 4, 0); |
| + 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.
|
| + memset(output_vector.get(), 0, sizeof(float) * kHighLatencyBufferSize); |
| + start = base::TimeTicks::HighResNow(); |
| + for (int j = 0; j < vector_fmac_iterations; ++j) { |
| + mixer.VectorFMAC_SSE(input_vector.get(), M_PI, kHighLatencyBufferSize, |
| + output_vector.get()); |
| + } |
| + double total_time_sse_aligned_ms = |
| + (base::TimeTicks::HighResNow() - start).InMillisecondsF(); |
| + printf("VectorFMAC_SSE (aligned size) took %.2fms; which is %.2fx faster than" |
| + " VectorFMAC_C and %.2fx faster than VectorFMAC_SSE (unaligned size)." |
| + "\n", |
| + total_time_sse_aligned_ms, total_time_c_ms / total_time_sse_aligned_ms, |
| + total_time_sse_unaligned_ms / total_time_sse_aligned_ms); |
| +#endif |
| +} |
| + |
| // Tuple of <input sampling rate, output sampling rate, epsilon>. |
| typedef std::tr1::tuple<int, int, double> AudioRendererMixerTestData; |
| class AudioRendererMixerTest |