Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(719)

Side by Side Diff: media/base/audio_renderer_mixer_unittest.cc

Issue 10802005: Add SSE optimizations to AudioRendererMixer. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Comments! Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
OLDNEW
« media/base/audio_renderer_mixer.cc ('K') | « media/base/audio_renderer_mixer.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698