Index: webrtc/modules/audio_processing/audio_processing_lock_performance_unittest.cc |
diff --git a/webrtc/modules/audio_processing/audio_processing_lock_performance_unittest.cc b/webrtc/modules/audio_processing/audio_processing_lock_performance_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a2f23535554fbc7dc0eb0e5276b53349a5bcbc77 |
--- /dev/null |
+++ b/webrtc/modules/audio_processing/audio_processing_lock_performance_unittest.cc |
@@ -0,0 +1,672 @@ |
+/* |
+ * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. |
hlundin-webrtc
2015/11/13 12:18:32
2015
peah-webrtc
2015/11/18 10:27:26
Done.
|
+ * |
+ * Use of this source code is governed by a BSD-style license |
+ * that can be found in the LICENSE file in the root of the source |
+ * tree. An additional intellectual property rights grant can be found |
+ * in the file PATENTS. All contributing project authors may |
+ * be found in the AUTHORS file in the root of the source tree. |
+ */ |
+#include "webrtc/modules/audio_processing/audio_processing_impl.h" |
+ |
+#include <math.h> |
+ |
+#include <algorithm> |
+#include <vector> |
+ |
+#include "testing/gtest/include/gtest/gtest.h" |
+#include "webrtc/base/array_view.h" |
+#include "webrtc/base/criticalsection.h" |
+#include "webrtc/config.h" |
+#include "webrtc/modules/audio_processing/test/test_utils.h" |
+#include "webrtc/modules/include/module_common_types.h" |
+#include "webrtc/system_wrappers/include/clock.h" |
+#include "webrtc/system_wrappers/include/event_wrapper.h" |
+#include "webrtc/system_wrappers/include/sleep.h" |
+#include "webrtc/system_wrappers/include/thread_wrapper.h" |
+#include "webrtc/test/random.h" |
+#include "webrtc/test/testsupport/perf_test.h" |
+ |
+namespace webrtc { |
+ |
+namespace { |
+ |
+class CallSimulator; |
+ |
+// Populates a float audio frame with random data. |
hlundin-webrtc
2015/11/13 12:18:31
It seems to populate more than one frame. Make the
peah-webrtc
2015/11/18 10:27:26
It supports multiple channel frames, and I think i
|
+void PopulateAudioFrame(float** frame, |
hlundin-webrtc
2015/11/13 12:18:31
frame is an output parameter, it should go last in
peah-webrtc
2015/11/18 10:27:27
Done.
|
+ float amplitude, |
+ size_t num_channels, |
+ size_t samples_per_channel, |
+ test::Random* rand_gen) { |
+ for (size_t ch = 0; ch < num_channels; ch++) { |
+ for (size_t k = 0; k < samples_per_channel; k++) { |
+ // Store random 16 bit quantized float number between +-amplitude. |
hlundin-webrtc
2015/11/13 12:18:32
Where does the 16-bit quantization happen? Is it i
peah-webrtc
2015/11/18 10:27:27
Sorry, that comment is completely wrong! Removed i
|
+ frame[ch][k] = amplitude * (2 * rand_gen->Rand<float>() - 1); |
+ } |
+ } |
+} |
+ |
+// Variant of echo canceller settings to use in the test. |
+enum class AecType { BasicWebRtcAecSettings, BasicWebRtcAecmSettings }; |
+ |
+// Variables related to the audio data and formats. |
+struct AudioFrameData { |
+ explicit AudioFrameData(int max_frame_size) { |
hlundin-webrtc
2015/11/13 12:18:32
size_t
peah-webrtc
2015/11/18 10:27:26
Done.
|
+ // Set up the two-dimensional arrays needed for the APM API calls. |
+ input_framechannels.resize(2 * max_frame_size); |
+ input_frame.resize(2); |
+ input_frame[0] = &input_framechannels[0]; |
+ input_frame[1] = &input_framechannels[max_frame_size]; |
+ |
+ output_frame_channels.resize(2 * max_frame_size); |
+ output_frame.resize(2); |
+ output_frame[0] = &output_frame_channels[0]; |
+ output_frame[1] = &output_frame_channels[max_frame_size]; |
+ } |
+ |
+ std::vector<float> output_frame_channels; |
+ std::vector<float*> output_frame; |
+ std::vector<float> input_framechannels; |
+ std::vector<float*> input_frame; |
+ StreamConfig input_stream_config; |
+ StreamConfig output_stream_config; |
+}; |
+ |
+// The configuration for the test. |
+struct SimulationConfig { |
+ SimulationConfig(int sample_rate_hz, |
+ AecType aec_type, |
+ int min_number_of_calls, |
+ bool use_realtime_simulation) |
+ : sample_rate_hz(sample_rate_hz), |
+ aec_type(aec_type), |
+ min_number_of_calls(min_number_of_calls), |
+ use_realtime_simulation(use_realtime_simulation) {} |
+ int sample_rate_hz = 16000; |
+ AecType aec_type = AecType::BasicWebRtcAecSettings; |
+ int min_number_of_calls = 300; |
+ bool use_realtime_simulation; |
hlundin-webrtc
2015/11/13 12:18:32
All members but this one has default values.
peah-webrtc
2015/11/18 10:27:26
Done.
|
+}; |
+ |
+// Handler for the frame counters. |
+class FrameCounters { |
+ public: |
+ int IncreaseRenderCounter() { |
+ rtc::CritScope cs(&crit_); |
+ render_count++; |
+ return render_count; |
+ } |
+ |
+ int IncreaseCaptureCounter() { |
+ rtc::CritScope cs(&crit_); |
+ capture_count++; |
+ return capture_count; |
+ } |
+ |
+ int GetCaptureCounter() { |
+ rtc::CritScope cs(&crit_); |
+ return capture_count; |
+ } |
+ |
+ int GetRenderCounter() { |
+ rtc::CritScope cs(&crit_); |
+ return render_count; |
+ } |
+ |
+ int CaptureMinusRenderCounters() { |
+ rtc::CritScope cs(&crit_); |
+ return capture_count - render_count; |
+ } |
+ |
+ int RenderMinusCaptureCounters() { |
hlundin-webrtc
2015/11/13 12:18:32
Do you need both "minus" methods? And if you do, y
peah-webrtc
2015/11/18 10:27:25
It is mainly for convenience and to (tiny) increas
|
+ rtc::CritScope cs(&crit_); |
+ return render_count - capture_count; |
+ } |
+ |
+ bool BothCountersExceedeThreshold(int threshold) { |
+ rtc::CritScope cs(&crit_); |
+ return (render_count > threshold && capture_count > threshold); |
+ } |
+ |
+ private: |
+ rtc::CriticalSection crit_; |
+ int render_count GUARDED_BY(crit_) = 0; |
hlundin-webrtc
2015/11/13 12:18:32
Trailing underscore on both counter variables.
peah-webrtc
2015/11/18 10:27:26
Done.
|
+ int capture_count GUARDED_BY(crit_) = 0; |
+}; |
+ |
+// Checker for whether the capture side has been called. |
+class CaptureSideCalledChecker { |
hlundin-webrtc
2015/11/13 12:18:32
Generalize the name to make it shorter. Nothing wi
peah-webrtc
2015/11/18 10:27:26
Good point! I called it LockedFlag since it is doe
|
+ public: |
+ bool CaptureSideCalled() { |
hlundin-webrtc
2015/11/13 12:18:32
This is a simple "getter" function, albeit with a
peah-webrtc
2015/11/18 10:27:26
Done.
|
+ rtc::CritScope cs(&crit_); |
+ return capture_side_called_; |
+ } |
+ |
+ void FlagCaptureSideCalled() { |
hlundin-webrtc
2015/11/13 12:18:32
This is a "setter" with a lock. Name it such:
void
peah-webrtc
2015/11/18 10:27:26
Done.
|
+ rtc::CritScope cs(&crit_); |
+ capture_side_called_ = true; |
+ } |
+ |
+ private: |
+ rtc::CriticalSection crit_; |
+ bool capture_side_called_ GUARDED_BY(crit_) = false; |
+}; |
+ |
+// Parent class for the thread processors. |
+class TimedThreadApiProcessor { |
+ public: |
+ TimedThreadApiProcessor(int max_frame_size, |
+ test::Random* rand_gen, |
+ FrameCounters* shared_counters_state, |
+ CaptureSideCalledChecker* capture_call_checker, |
+ CallSimulator* test_framework, |
+ SimulationConfig* simulation_config, |
+ AudioProcessing* apm, |
+ int min_number_of_calls, |
+ float input_level); |
+ virtual ~TimedThreadApiProcessor() {} |
+ |
+ bool ProcessClocked10msQuantum(); |
+ std::vector<int64_t> get_api_call_durations() const { |
+ return api_call_durations_; |
+ } |
+ int64_t GetDurationStandardDeviation() const; |
+ int64_t GetDurationAverage() const; |
+ |
+ protected: |
+ static const int kMaxCallDifference = 10; |
+ |
+ void PrepareFrame(); |
+ void AddJitter(int max_jitter_microseconds, bool random_jitter); |
+ virtual int Process() = 0; |
+ virtual bool ReadyToProcess() = 0; |
+ |
+ test::Random* rand_gen_ = nullptr; |
+ FrameCounters* frame_counters_ = nullptr; |
+ CaptureSideCalledChecker* capture_call_checker_ = nullptr; |
+ CallSimulator* test_ = nullptr; |
+ SimulationConfig* simulation_config_ = nullptr; |
+ AudioProcessing* apm_ = nullptr; |
+ AudioFrameData frame_data_; |
+ webrtc::Clock* clock_; |
+ int num_durations_to_store_; |
+ std::vector<int64_t> api_call_durations_; |
+ const float input_level_; |
+}; |
+ |
+// Class for handling the capture side processing. |
+class CaptureProcessor : public TimedThreadApiProcessor { |
hlundin-webrtc
2015/11/13 12:18:31
Mark this class final.
peah-webrtc
2015/11/18 10:27:26
Done.
|
+ public: |
+ CaptureProcessor(int max_frame_size, |
+ test::Random* rand_gen, |
+ FrameCounters* shared_counters_state, |
+ CaptureSideCalledChecker* capture_call_checker, |
+ CallSimulator* test_framework, |
+ SimulationConfig* simulation_config, |
+ AudioProcessing* apm, |
+ int min_number_of_calls, |
+ float input_level); |
+ |
+ private: |
+ // Overrides from TimedThreadApiProcessor. |
+ int Process() override; |
+ bool ReadyToProcess() override; |
+ |
+ bool first_capture_side_call_ = true; |
+}; |
+ |
+// Class for handling the render side processing. |
+class RenderProcessor : public TimedThreadApiProcessor { |
hlundin-webrtc
2015/11/13 12:18:31
Mark this class final.
peah-webrtc
2015/11/18 10:27:26
Done.
|
+ public: |
+ RenderProcessor(int max_frame_size, |
+ test::Random* rand_gen, |
+ FrameCounters* shared_counters_state, |
+ CaptureSideCalledChecker* capture_call_checker, |
+ CallSimulator* test_framework, |
+ SimulationConfig* simulation_config, |
+ AudioProcessing* apm, |
+ int min_number_of_calls, |
+ float input_level); |
+ |
+ private: |
+ // Overrides from TimedThreadApiProcessor |
+ int Process() override; |
+ bool ReadyToProcess() override; |
+ |
+ bool first_render_side_call_ = true; |
+}; |
+ |
+// Class for managing the test simulation. |
+class CallSimulator { |
hlundin-webrtc
2015/11/13 12:18:32
I think this class should be made a gtest fixture
peah-webrtc
2015/11/18 10:27:26
Done.
|
+ public: |
+ explicit CallSimulator(SimulationConfig simulation_config); |
+ EventTypeWrapper Run(int time_out_limit); |
+ |
+ // Tests whether all the required render and capture side calls have been |
+ // done. |
+ void CheckIfSimulationDone() { |
+ if (frame_counters_.BothCountersExceedeThreshold( |
+ simulation_config_.min_number_of_calls)) { |
+ test_complete_->Set(); |
+ } |
+ } |
+ |
+ const CaptureProcessor* GetCapture() const { return &capture_thread_state_; } |
+ const RenderProcessor* GetRender() const { return &render_thread_state_; } |
+ void SetUp(); |
+ void TearDown(); |
+ |
+ private: |
+ static const int kMaxFrameSize = 480; |
+ static const float kCaptureInputFloatLevel; |
+ static const float kRenderInputFloatLevel; |
+ |
+ // Thread callback for the render thread. |
+ static bool RenderProcessorThreadFunc(void* context) { |
+ return reinterpret_cast<CallSimulator*>(context) |
+ ->render_thread_state_.ProcessClocked10msQuantum(); |
+ } |
+ |
+ // Thread callback for the capture thread. |
+ static bool CaptureProcessorThreadFunc(void* context) { |
+ return reinterpret_cast<CallSimulator*>(context) |
+ ->capture_thread_state_.ProcessClocked10msQuantum(); |
+ } |
+ |
+ // Start the threads used in the test. |
+ void StartThreads() { |
+ ASSERT_TRUE(render_thread_->Start()); |
+ render_thread_->SetPriority(kRealtimePriority); |
+ ASSERT_TRUE(capture_thread_->Start()); |
+ capture_thread_->SetPriority(kRealtimePriority); |
+ } |
+ |
+ // Event handler for the test. |
+ const rtc::scoped_ptr<EventWrapper> test_complete_; |
+ |
+ // Thread related variables. |
+ rtc::scoped_ptr<ThreadWrapper> render_thread_; |
+ rtc::scoped_ptr<ThreadWrapper> capture_thread_; |
+ mutable test::Random rand_gen_; |
hlundin-webrtc
2015/11/13 12:18:31
Why is this mutable?
peah-webrtc
2015/11/18 10:27:26
Done.
|
+ |
+ rtc::scoped_ptr<AudioProcessing> apm_; |
+ SimulationConfig simulation_config_; |
+ FrameCounters frame_counters_; |
+ CaptureSideCalledChecker capture_call_checker_; |
+ RenderProcessor render_thread_state_; |
+ CaptureProcessor capture_thread_state_; |
+}; |
+ |
+const float CallSimulator::kRenderInputFloatLevel = 0.5f; |
+const float CallSimulator::kCaptureInputFloatLevel = 0.03125f; |
+ |
+CallSimulator::CallSimulator(SimulationConfig simulation_config) |
+ : test_complete_(EventWrapper::Create()), |
+ render_thread_(ThreadWrapper::CreateThread(RenderProcessorThreadFunc, |
+ this, |
+ "render")), |
+ capture_thread_(ThreadWrapper::CreateThread(CaptureProcessorThreadFunc, |
+ this, |
+ "capture")), |
+ rand_gen_(42U), |
+ apm_(AudioProcessingImpl::Create()), |
hlundin-webrtc
2015/11/13 12:18:31
Create() may return null in case of failure. You c
peah-webrtc
2015/11/18 10:27:26
Done.
|
+ simulation_config_(simulation_config), |
+ render_thread_state_(kMaxFrameSize, |
+ &rand_gen_, |
+ &frame_counters_, |
+ &capture_call_checker_, |
+ this, |
+ &simulation_config_, |
+ apm_.get(), |
+ simulation_config_.min_number_of_calls, |
+ kRenderInputFloatLevel), |
+ capture_thread_state_(kMaxFrameSize, |
+ &rand_gen_, |
+ &frame_counters_, |
+ &capture_call_checker_, |
+ this, |
+ &simulation_config_, |
+ apm_.get(), |
+ simulation_config_.min_number_of_calls, |
+ kCaptureInputFloatLevel) {} |
+ |
+// Run the call simulation with a timeout. |
+EventTypeWrapper CallSimulator::Run(int time_out_limit) { |
+ SetUp(); |
+ StartThreads(); |
hlundin-webrtc
2015/11/13 12:18:31
You should make sure that none of the ASSERT_TRUEs
peah-webrtc
2015/11/18 10:27:26
Done.
|
+ EventTypeWrapper result = test_complete_->Wait(time_out_limit); |
+ TearDown(); |
+ return result; |
+} |
+ |
+// Simulator and APM setup. |
+void CallSimulator::SetUp() { |
+ ASSERT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(true)); |
+ ASSERT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true)); |
+ ASSERT_EQ(apm_->kNoError, |
+ apm_->gain_control()->set_mode(GainControl::kAdaptiveAnalog)); |
+ ASSERT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true)); |
+ ASSERT_EQ(apm_->kNoError, apm_->noise_suppression()->Enable(true)); |
+ ASSERT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(true)); |
+ |
+ Config config; |
hlundin-webrtc
2015/11/13 12:18:31
Move the declaration down to within the else-claus
peah-webrtc
2015/11/18 10:27:26
Done.
|
+ if (simulation_config_.aec_type == AecType::BasicWebRtcAecmSettings) { |
+ ASSERT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(true)); |
+ ASSERT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(false)); |
+ } else { |
+ ASSERT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(false)); |
+ ASSERT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true)); |
+ ASSERT_EQ(apm_->kNoError, apm_->echo_cancellation()->enable_metrics(true)); |
+ ASSERT_EQ(apm_->kNoError, |
+ apm_->echo_cancellation()->enable_delay_logging(true)); |
+ |
+ config.Set<ExtendedFilter>(new ExtendedFilter(true)); |
+ config.Set<DelayAgnostic>(new DelayAgnostic(true)); |
+ apm_->SetExtraOptions(config); |
+ } |
+} |
+ |
+void CallSimulator::TearDown() { |
+ render_thread_->Stop(); |
+ capture_thread_->Stop(); |
+} |
+ |
+TimedThreadApiProcessor::TimedThreadApiProcessor( |
hlundin-webrtc
2015/11/13 12:18:32
I think you can define all the member methods with
peah-webrtc
2015/11/18 10:27:26
Did this on all methods apart from the Process() m
|
+ int max_frame_size, |
+ test::Random* rand_gen, |
+ FrameCounters* shared_counters_state, |
+ CaptureSideCalledChecker* capture_call_checker, |
+ CallSimulator* test_framework, |
+ SimulationConfig* simulation_config, |
+ AudioProcessing* apm, |
+ int num_durations_to_store, |
+ float input_level) |
+ : rand_gen_(rand_gen), |
+ frame_counters_(shared_counters_state), |
+ capture_call_checker_(capture_call_checker), |
+ test_(test_framework), |
+ simulation_config_(simulation_config), |
+ apm_(apm), |
+ frame_data_(max_frame_size), |
hlundin-webrtc
2015/11/13 12:18:31
No need to pass max_frame_size as a parameter; sim
peah-webrtc
2015/11/18 10:27:27
Done.
|
+ clock_(webrtc::Clock::GetRealTimeClock()), |
+ num_durations_to_store_(num_durations_to_store), |
+ api_call_durations_(num_durations_to_store_), |
+ input_level_(input_level) {} |
+ |
+// Implements the callback functionality for the threads. |
+bool TimedThreadApiProcessor::ProcessClocked10msQuantum() { |
+ PrepareFrame(); |
+ |
+ while (!ReadyToProcess()) { |
+ AddJitter(2, true); |
+ } |
+ |
+ const int64_t start_time = clock_->TimeInMicroseconds(); |
+ Process(); |
+ const int64_t end_time = clock_->TimeInMicroseconds(); |
+ const int duration = static_cast<int>(end_time - start_time); |
hlundin-webrtc
2015/11/13 12:18:31
duration_us, to convey the unit.
hlundin-webrtc
2015/11/13 12:18:32
use rtc::checked_cast<int> from base/safe_conversi
peah-webrtc
2015/11/18 10:27:26
Done.
peah-webrtc
2015/11/18 10:27:26
Done.
|
+ const int time_left_of_10_ms_quantum = 10000 - duration; |
+ |
+ if (simulation_config_->use_realtime_simulation && |
+ time_left_of_10_ms_quantum > 0) { |
+ AddJitter(time_left_of_10_ms_quantum, false); |
+ } |
+ |
+ test_->CheckIfSimulationDone(); |
+ |
+ return true; |
+} |
+ |
+int64_t TimedThreadApiProcessor::GetDurationStandardDeviation() const { |
+ double variance = 0; |
+ const int64_t average_duration = GetDurationAverage(); |
+ for (int64_t duration : api_call_durations_) { |
+ int64_t tmp = duration - average_duration; |
+ variance += static_cast<double>(tmp * tmp); |
+ } |
+ return static_cast<int64_t>(sqrt(variance / api_call_durations_.size())); |
hlundin-webrtc
2015/11/13 12:18:32
rtc::checked_cast
peah-webrtc
2015/11/18 10:27:27
Done.
|
+} |
+ |
+int64_t TimedThreadApiProcessor::GetDurationAverage() const { |
+ int64_t average_duration = 0; |
+ for (int64_t duration : api_call_durations_) { |
+ average_duration += duration; |
+ } |
+ return average_duration / api_call_durations_.size(); |
+} |
+ |
+void TimedThreadApiProcessor::PrepareFrame() { |
+ // Prepare the audio input data and metadata. |
+ frame_data_.input_stream_config.set_sample_rate_hz( |
+ simulation_config_->sample_rate_hz); |
+ frame_data_.input_stream_config.set_num_channels(1); |
+ frame_data_.input_stream_config.set_has_keyboard(false); |
+ PopulateAudioFrame(&frame_data_.input_frame[0], input_level_, 1, |
+ (simulation_config_->sample_rate_hz * |
+ AudioProcessing::kChunkSizeMs / 1000), |
+ rand_gen_); |
+ |
+ // Prepare the float audio output data and metadata. |
+ frame_data_.output_stream_config.set_sample_rate_hz( |
+ simulation_config_->sample_rate_hz); |
+ frame_data_.output_stream_config.set_num_channels(1); |
+ frame_data_.output_stream_config.set_has_keyboard(false); |
+} |
+ |
+void TimedThreadApiProcessor::AddJitter(int max_jitter_microseconds, |
+ bool random_jitter) { |
+ int min_method_duration; |
+ if (random_jitter) { |
+ min_method_duration = rand_gen_->Rand(0, max_jitter_microseconds); |
+ } else { |
+ min_method_duration = max_jitter_microseconds; |
+ } |
+ |
+ const int64_t start_time = clock_->TimeInMicroseconds(); |
hlundin-webrtc
2015/11/13 12:18:32
Please, comment on why you cannot just sleep.
peah-webrtc
2015/11/18 10:27:26
Very good point. As I never use this in the test a
|
+ int sum = 0; |
+ while ((clock_->TimeInMicroseconds() - start_time) < min_method_duration) { |
+ for (int k = 0; k < 100; ++k) |
+ for (int j = 1; j < 100; ++j) { |
+ sum += k % j; |
+ sum = sum % 79; |
+ } |
+ if (sum > 100) { |
+ printf("Will not be print out, just present in order to ensure"); |
+ printf("that sum is evaluated by the compiler\n"); |
+ } |
+ } |
+} |
+ |
+CaptureProcessor::CaptureProcessor( |
hlundin-webrtc
2015/11/13 12:18:32
There is a non-negligible overhead associated with
peah-webrtc
2015/11/18 10:27:25
Good point!!!
Will implement it like that.
Done.
|
+ int max_frame_size, |
+ test::Random* rand_gen, |
+ FrameCounters* shared_counters_state, |
+ CaptureSideCalledChecker* capture_call_checker, |
+ CallSimulator* test_framework, |
+ SimulationConfig* simulation_config, |
+ AudioProcessing* apm, |
+ int num_durations_to_store, |
+ float input_level) |
+ : TimedThreadApiProcessor(max_frame_size, |
+ rand_gen, |
+ shared_counters_state, |
+ capture_call_checker, |
+ test_framework, |
+ simulation_config, |
+ apm, |
+ num_durations_to_store, |
+ input_level) {} |
+ |
+int CaptureProcessor::Process() { |
+ // Set the stream delay |
+ apm_->set_stream_delay_ms(30); |
+ |
+ // Call and time the specified capture side API processing method. |
+ const int64_t start_time = clock_->TimeInMicroseconds(); |
+ const int result = apm_->ProcessStream( |
+ &frame_data_.input_frame[0], frame_data_.input_stream_config, |
+ frame_data_.output_stream_config, &frame_data_.output_frame[0]); |
+ const int64_t end_time = clock_->TimeInMicroseconds(); |
+ |
+ const int new_capture_counter = frame_counters_->IncreaseCaptureCounter(); |
+ |
+ if (new_capture_counter <= num_durations_to_store_) { |
+ api_call_durations_[new_capture_counter - 1] = end_time - start_time; |
hlundin-webrtc
2015/11/13 12:18:32
Why not just api_call_durations_.push_back(...)? Y
peah-webrtc
2015/11/18 10:27:26
Good and very valid point!
Done.
|
+ } |
+ |
+ if (first_capture_side_call_) { |
+ // Flag that the capture side has been called at least once |
+ // (needed to ensure that a capture call has been done |
+ // before the first render call is performed (implicitly |
+ // required by the APM API). |
+ capture_call_checker_->FlagCaptureSideCalled(); |
+ first_capture_side_call_ = false; |
+ } |
+ return result; |
+} |
+ |
+bool CaptureProcessor::ReadyToProcess() { |
+ return (frame_counters_->CaptureMinusRenderCounters() <= kMaxCallDifference); |
+} |
+ |
+RenderProcessor::RenderProcessor(int max_frame_size, |
+ test::Random* rand_gen, |
+ FrameCounters* shared_counters_state, |
+ CaptureSideCalledChecker* capture_call_checker, |
+ CallSimulator* test_framework, |
+ SimulationConfig* simulation_config, |
+ AudioProcessing* apm, |
+ int num_durations_to_store, |
+ float input_level) |
+ : TimedThreadApiProcessor(max_frame_size, |
+ rand_gen, |
+ shared_counters_state, |
+ capture_call_checker, |
+ test_framework, |
+ simulation_config, |
+ apm, |
+ num_durations_to_store, |
+ input_level) {} |
+ |
+int RenderProcessor::Process() { |
+ // Call and time the specified render side API processing method. |
+ const int64_t start_time = clock_->TimeInMicroseconds(); |
+ const int result = apm_->ProcessReverseStream( |
+ &frame_data_.input_frame[0], frame_data_.input_stream_config, |
+ frame_data_.output_stream_config, &frame_data_.output_frame[0]); |
+ const int64_t end_time = clock_->TimeInMicroseconds(); |
+ |
+ const int new_render_counter = frame_counters_->IncreaseRenderCounter(); |
+ |
+ if (new_render_counter <= num_durations_to_store_) { |
+ api_call_durations_[new_render_counter - 1] = end_time - start_time; |
+ } |
+ |
+ return result; |
+} |
+ |
+bool RenderProcessor::ReadyToProcess() { |
+ // Do not process until at least one capture call has been done. |
+ // (implicitly required by the APM API). |
+ if (first_render_side_call_ && !capture_call_checker_->CaptureSideCalled()) { |
+ return false; |
+ } |
+ |
+ // Ensure that the number of render and capture calls do not differ too much. |
+ if (frame_counters_->RenderMinusCaptureCounters() > kMaxCallDifference) { |
+ return false; |
+ } |
+ |
+ first_render_side_call_ = false; |
+ return true; |
+} |
+ |
+// Runs the simulation and reports the results. |
+void RunSimulation(SimulationConfig simulation_config, |
+ int timeout, |
+ bool print_durations) { |
+ // Lambda function for printing out the simulation statistics. |
+ auto print_simulation_statistics = []( |
+ const TimedThreadApiProcessor* processor, std::string processor_name, |
+ bool print_durations) { |
+ const std::string modifier = "_api_call_duration"; |
+ |
+ // Lambda function for creating a test printout string. |
+ auto create_mean_and_variance_string = [](int64_t average, |
+ int64_t standard_dev) { |
+ std::string s = std::to_string(average); |
+ s += ","; |
+ s += std::to_string(standard_dev); |
+ return s; |
+ }; |
+ |
+ webrtc::test::PrintResult(processor_name, modifier, "avg,stdev", |
+ create_mean_and_variance_string( |
+ processor->GetDurationAverage(), |
+ processor->GetDurationStandardDeviation()), |
+ "ms", false); |
+ |
+ if (print_durations) { |
+ std::vector<int64_t> durations = processor->get_api_call_durations(); |
+ std::string value_string = ""; |
+ for (int64_t duration : durations) { |
+ value_string += std::to_string(duration) + ","; |
+ } |
+ webrtc::test::PrintResultList(processor_name, modifier, "durations", |
+ value_string, "ms", false); |
+ } |
+ }; |
+ |
+ CallSimulator simulator(simulation_config); |
+ |
+ // Run simulation and verify that it did not time out. |
+ ASSERT_EQ(EventTypeWrapper::kEventSignaled, simulator.Run(timeout)); |
hlundin-webrtc
2015/11/13 12:18:32
Maybe EXPECT_EQ instead. It might still be interes
peah-webrtc
2015/11/18 10:27:27
Done.
|
+ |
+ print_simulation_statistics(simulator.GetRender(), "render", print_durations); |
hlundin-webrtc
2015/11/13 12:18:32
To me it looks like the print_simulation_statistic
peah-webrtc
2015/11/18 10:27:26
Done.
|
+ print_simulation_statistics(simulator.GetCapture(), "capture", |
+ print_durations); |
+} |
+ |
+const int kMaxFramesToProcess = 300; |
+const int32_t kTestTimeout = 3 * 10 * kMaxFramesToProcess; |
+const bool kUseTimedSimulation = false; |
hlundin-webrtc
2015/11/13 12:18:32
I don't think it makes much sense to declare this
peah-webrtc
2015/11/18 10:27:26
Good points and I fully agree. This has been partl
|
+const bool kPrintAllDurations = false; |
+} // anonymous namespace |
+ |
+TEST(AudioProcessingLockPerformanceTest, Aec8kHz) { |
+ RunSimulation(SimulationConfig(8000, AecType::BasicWebRtcAecSettings, |
+ kMaxFramesToProcess, kUseTimedSimulation), |
+ kTestTimeout, kPrintAllDurations); |
+} |
+ |
+TEST(AudioProcessingLockPerformanceTest, Aec16kHz) { |
+ RunSimulation(SimulationConfig(16000, AecType::BasicWebRtcAecSettings, |
+ kMaxFramesToProcess, kUseTimedSimulation), |
+ kTestTimeout, kPrintAllDurations); |
+} |
+ |
+TEST(AudioProcessingLockPerformanceTest, Aec32kHz) { |
+ RunSimulation(SimulationConfig(32000, AecType::BasicWebRtcAecSettings, |
+ kMaxFramesToProcess, kUseTimedSimulation), |
+ kTestTimeout, kPrintAllDurations); |
+} |
+ |
+TEST(AudioProcessingLockPerformanceTest, Aec48kHz) { |
+ RunSimulation(SimulationConfig(48000, AecType::BasicWebRtcAecSettings, |
+ kMaxFramesToProcess, kUseTimedSimulation), |
+ kTestTimeout, kPrintAllDurations); |
+} |
+ |
+TEST(AudioProcessingLockPerformanceTest, Aecm8kHz) { |
+ RunSimulation(SimulationConfig(8000, AecType::BasicWebRtcAecmSettings, |
+ kMaxFramesToProcess, true), |
+ kTestTimeout, kPrintAllDurations); |
+} |
+ |
+TEST(AudioProcessingLockPerformanceTest, Aecm16kHz) { |
+ RunSimulation(SimulationConfig(16000, AecType::BasicWebRtcAecmSettings, |
+ kMaxFramesToProcess, true), |
+ kTestTimeout, kPrintAllDurations); |
+} |
+} // namespace webrtc |