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 |