Added more refined benchmarking code for audioproc_f
This CL extends, and partly corrects, the benchmarking
code in audioproc_f to provide statistics for the API
call durations in audioproc_f
Bug: chromium:939791
Change-Id: I4c26c4bb3782335f13dd3e21e6f861842539ea62
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/129260
Commit-Queue: Per Åhgren <peah@webrtc.org>
Reviewed-by: Sam Zackrisson <saza@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27443}
diff --git a/modules/audio_processing/BUILD.gn b/modules/audio_processing/BUILD.gn
index 64a07e2..81dc2be 100644
--- a/modules/audio_processing/BUILD.gn
+++ b/modules/audio_processing/BUILD.gn
@@ -608,6 +608,8 @@
sources = [
"test/aec_dump_based_simulator.cc",
"test/aec_dump_based_simulator.h",
+ "test/api_call_statistics.cc",
+ "test/api_call_statistics.h",
"test/audio_processing_simulator.cc",
"test/audio_processing_simulator.h",
"test/audioproc_float_impl.cc",
diff --git a/modules/audio_processing/test/api_call_statistics.cc b/modules/audio_processing/test/api_call_statistics.cc
new file mode 100644
index 0000000..5e95668
--- /dev/null
+++ b/modules/audio_processing/test/api_call_statistics.cc
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * 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 "modules/audio_processing/test/api_call_statistics.h"
+
+#include <algorithm>
+#include <fstream>
+#include <iostream>
+#include <limits>
+#include <memory>
+
+#include "absl/memory/memory.h"
+#include "rtc_base/time_utils.h"
+
+namespace webrtc {
+namespace test {
+
+void ApiCallStatistics::Add(int64_t duration_nanos, CallType call_type) {
+ calls_.push_back(CallData(duration_nanos, call_type));
+}
+
+void ApiCallStatistics::PrintReport() const {
+ int64_t min_render = std::numeric_limits<int64_t>::max();
+ int64_t min_capture = std::numeric_limits<int64_t>::max();
+ int64_t max_render = 0;
+ int64_t max_capture = 0;
+ int64_t sum_render = 0;
+ int64_t sum_capture = 0;
+ int64_t num_render = 0;
+ int64_t num_capture = 0;
+ int64_t avg_render = 0;
+ int64_t avg_capture = 0;
+
+ for (auto v : calls_) {
+ if (v.call_type == CallType::kRender) {
+ ++num_render;
+ min_render = std::min(min_render, v.duration_nanos);
+ max_render = std::max(max_render, v.duration_nanos);
+ sum_render += v.duration_nanos;
+ } else {
+ ++num_capture;
+ min_capture = std::min(min_capture, v.duration_nanos);
+ max_capture = std::max(max_capture, v.duration_nanos);
+ sum_capture += v.duration_nanos;
+ }
+ }
+ min_render /= rtc::kNumNanosecsPerMicrosec;
+ max_render /= rtc::kNumNanosecsPerMicrosec;
+ sum_render /= rtc::kNumNanosecsPerMicrosec;
+ min_capture /= rtc::kNumNanosecsPerMicrosec;
+ max_capture /= rtc::kNumNanosecsPerMicrosec;
+ sum_capture /= rtc::kNumNanosecsPerMicrosec;
+ avg_render = num_render > 0 ? sum_render / num_render : 0;
+ avg_capture = num_capture > 0 ? sum_capture / num_capture : 0;
+
+ std::cout << std::endl
+ << "Total time: " << (sum_capture + sum_render) * 1e-6 << " s"
+ << std::endl
+ << " Render API calls:" << std::endl
+ << " min: " << min_render << " us" << std::endl
+ << " max: " << max_render << " us" << std::endl
+ << " avg: " << avg_render << " us" << std::endl
+ << " Capture API calls:" << std::endl
+ << " min: " << min_capture << " us" << std::endl
+ << " max: " << max_capture << " us" << std::endl
+ << " avg: " << avg_capture << " us" << std::endl;
+}
+
+void ApiCallStatistics::WriteReportToFile(const std::string& filename) const {
+ std::unique_ptr<std::ofstream> out =
+ absl::make_unique<std::ofstream>(filename);
+ for (auto v : calls_) {
+ if (v.call_type == CallType::kRender) {
+ *out << "render, ";
+ } else {
+ *out << "capture, ";
+ }
+ *out << (v.duration_nanos / rtc::kNumNanosecsPerMicrosec) << std::endl;
+ }
+}
+
+ApiCallStatistics::CallData::CallData(int64_t duration_nanos,
+ CallType call_type)
+ : duration_nanos(duration_nanos), call_type(call_type) {}
+
+} // namespace test
+} // namespace webrtc
diff --git a/modules/audio_processing/test/api_call_statistics.h b/modules/audio_processing/test/api_call_statistics.h
new file mode 100644
index 0000000..6a78d36
--- /dev/null
+++ b/modules/audio_processing/test/api_call_statistics.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * 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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_TEST_API_CALL_STATISTICS_H_
+#define MODULES_AUDIO_PROCESSING_TEST_API_CALL_STATISTICS_H_
+
+#include <string>
+#include <vector>
+
+namespace webrtc {
+namespace test {
+
+// Collects statistics about the API call durations.
+class ApiCallStatistics {
+ public:
+ enum class CallType { kRender, kCapture };
+
+ // Adds a new datapoint.
+ void Add(int64_t duration_nanos, CallType call_type);
+
+ // Prints out a report of the statistics.
+ void PrintReport() const;
+
+ // Writes the call information to a file.
+ void WriteReportToFile(const std::string& filename) const;
+
+ private:
+ struct CallData {
+ CallData(int64_t duration_nanos, CallType call_type);
+ int64_t duration_nanos;
+ CallType call_type;
+ };
+ std::vector<CallData> calls_;
+};
+
+} // namespace test
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_TEST_API_CALL_STATISTICS_H_
diff --git a/modules/audio_processing/test/audio_processing_simulator.cc b/modules/audio_processing/test/audio_processing_simulator.cc
index ce43517..0d57749 100644
--- a/modules/audio_processing/test/audio_processing_simulator.cc
+++ b/modules/audio_processing/test/audio_processing_simulator.cc
@@ -95,6 +95,27 @@
<< " plt.show()" << std::endl;
}
+// RAII class for execution time measurement. Updates the provided
+// ApiCallStatistics based on the time between ScopedTimer creation and
+// leaving the enclosing scope.
+class ScopedTimer {
+ public:
+ ScopedTimer(ApiCallStatistics* api_call_statistics_,
+ ApiCallStatistics::CallType call_type)
+ : start_time_(rtc::TimeNanos()),
+ call_type_(call_type),
+ api_call_statistics_(api_call_statistics_) {}
+
+ ~ScopedTimer() {
+ api_call_statistics_->Add(rtc::TimeNanos() - start_time_, call_type_);
+ }
+
+ private:
+ const int64_t start_time_;
+ const ApiCallStatistics::CallType call_type_;
+ ApiCallStatistics* const api_call_statistics_;
+};
+
} // namespace
SimulationSettings::SimulationSettings() = default;
@@ -150,13 +171,6 @@
}
}
-AudioProcessingSimulator::ScopedTimer::~ScopedTimer() {
- int64_t interval = rtc::TimeNanos() - start_time_;
- proc_time_->sum += interval;
- proc_time_->max = std::max(proc_time_->max, interval);
- proc_time_->min = std::min(proc_time_->min, interval);
-}
-
void AudioProcessingSimulator::ProcessStream(bool fixed_interface) {
// Optionally use the fake recording device to simulate analog gain.
if (settings_.simulate_mic_gain) {
@@ -188,12 +202,14 @@
// Process the current audio frame.
if (fixed_interface) {
{
- const auto st = ScopedTimer(mutable_proc_time());
+ const auto st = ScopedTimer(&api_call_statistics_,
+ ApiCallStatistics::CallType::kCapture);
RTC_CHECK_EQ(AudioProcessing::kNoError, ap_->ProcessStream(&fwd_frame_));
}
CopyFromAudioFrame(fwd_frame_, out_buf_.get());
} else {
- const auto st = ScopedTimer(mutable_proc_time());
+ const auto st = ScopedTimer(&api_call_statistics_,
+ ApiCallStatistics::CallType::kCapture);
RTC_CHECK_EQ(AudioProcessing::kNoError,
ap_->ProcessStream(in_buf_->channels(), in_config_,
out_config_, out_buf_->channels()));
@@ -222,13 +238,16 @@
void AudioProcessingSimulator::ProcessReverseStream(bool fixed_interface) {
if (fixed_interface) {
- const auto st = ScopedTimer(mutable_proc_time());
- RTC_CHECK_EQ(AudioProcessing::kNoError,
- ap_->ProcessReverseStream(&rev_frame_));
+ {
+ const auto st = ScopedTimer(&api_call_statistics_,
+ ApiCallStatistics::CallType::kRender);
+ RTC_CHECK_EQ(AudioProcessing::kNoError,
+ ap_->ProcessReverseStream(&rev_frame_));
+ }
CopyFromAudioFrame(rev_frame_, reverse_out_buf_.get());
-
} else {
- const auto st = ScopedTimer(mutable_proc_time());
+ const auto st = ScopedTimer(&api_call_statistics_,
+ ApiCallStatistics::CallType::kRender);
RTC_CHECK_EQ(AudioProcessing::kNoError,
ap_->ProcessReverseStream(
reverse_in_buf_->channels(), reverse_in_config_,
diff --git a/modules/audio_processing/test/audio_processing_simulator.h b/modules/audio_processing/test/audio_processing_simulator.h
index 5bf2760..2ff2539 100644
--- a/modules/audio_processing/test/audio_processing_simulator.h
+++ b/modules/audio_processing/test/audio_processing_simulator.h
@@ -20,6 +20,7 @@
#include "absl/types/optional.h"
#include "common_audio/channel_buffer.h"
#include "modules/audio_processing/include/audio_processing.h"
+#include "modules/audio_processing/test/api_call_statistics.h"
#include "modules/audio_processing/test/fake_recording_device.h"
#include "modules/audio_processing/test/test_utils.h"
#include "rtc_base/constructor_magic.h"
@@ -85,6 +86,7 @@
bool simulate_mic_gain = false;
absl::optional<int> simulated_mic_kind;
bool report_performance = false;
+ absl::optional<std::string> performance_report_output_filename;
bool report_bitexactness = false;
bool use_verbose_logging = false;
bool use_quiet_output = false;
@@ -101,14 +103,6 @@
absl::optional<std::string> aec_settings_filename;
};
-// Holds a few statistics about a series of TickIntervals.
-struct TickIntervalStats {
- TickIntervalStats() : min(std::numeric_limits<int64_t>::max()) {}
- int64_t sum;
- int64_t max;
- int64_t min;
-};
-
// Copies samples present in a ChannelBuffer into an AudioFrame.
void CopyToAudioFrame(const ChannelBuffer<float>& src, AudioFrame* dest);
@@ -124,8 +118,10 @@
// Processes the data in the input.
virtual void Process() = 0;
- // Returns the execution time of all AudioProcessing calls.
- const TickIntervalStats& proc_time() const { return proc_time_; }
+ // Returns the execution times of all AudioProcessing calls.
+ const ApiCallStatistics& GetApiCallStatistics() const {
+ return api_call_statistics_;
+ }
// Reports whether the processed recording was bitexact.
bool OutputWasBitexact() { return bitexact_output_; }
@@ -136,22 +132,6 @@
}
protected:
- // RAII class for execution time measurement. Updates the provided
- // TickIntervalStats based on the time between ScopedTimer creation and
- // leaving the enclosing scope.
- class ScopedTimer {
- public:
- explicit ScopedTimer(TickIntervalStats* proc_time)
- : proc_time_(proc_time), start_time_(rtc::TimeNanos()) {}
-
- ~ScopedTimer();
-
- private:
- TickIntervalStats* const proc_time_;
- int64_t start_time_;
- };
-
- TickIntervalStats* mutable_proc_time() { return &proc_time_; }
void ProcessStream(bool fixed_interface);
void ProcessReverseStream(bool fixed_interface);
void CreateAudioProcessor();
@@ -194,7 +174,7 @@
size_t num_reverse_process_stream_calls_ = 0;
std::unique_ptr<ChannelBufferWavWriter> buffer_writer_;
std::unique_ptr<ChannelBufferWavWriter> reverse_buffer_writer_;
- TickIntervalStats proc_time_;
+ ApiCallStatistics api_call_statistics_;
std::ofstream residual_echo_likelihood_graph_writer_;
int analog_mic_level_;
FakeRecordingDevice fake_recording_device_;
diff --git a/modules/audio_processing/test/audioproc_float_impl.cc b/modules/audio_processing/test/audioproc_float_impl.cc
index f0e57a9..d29541b4 100644
--- a/modules/audio_processing/test/audioproc_float_impl.cc
+++ b/modules/audio_processing/test/audioproc_float_impl.cc
@@ -190,6 +190,10 @@
kParameterNotSpecifiedValue,
"Specify which microphone kind to use for microphone simulation");
WEBRTC_DEFINE_bool(performance_report, false, "Report the APM performance ");
+WEBRTC_DEFINE_string(performance_report_output_file,
+ "",
+ "Generate a CSV file with the API call durations");
+
WEBRTC_DEFINE_bool(verbose, false, "Produce verbose output");
WEBRTC_DEFINE_bool(quiet,
false,
@@ -351,6 +355,8 @@
settings.simulate_mic_gain = FLAG_simulate_mic_gain;
SetSettingIfSpecified(FLAG_simulated_mic_kind, &settings.simulated_mic_kind);
settings.report_performance = FLAG_performance_report;
+ SetSettingIfSpecified(FLAG_performance_report_output_file,
+ &settings.performance_report_output_filename);
settings.use_verbose_logging = FLAG_verbose;
settings.use_quiet_output = FLAG_quiet;
settings.report_bitexactness = FLAG_bitexactness_report;
@@ -555,18 +561,11 @@
processor->Process();
if (settings.report_performance) {
- const auto& proc_time = processor->proc_time();
- int64_t exec_time_us = proc_time.sum / rtc::kNumNanosecsPerMicrosec;
- std::cout << std::endl
- << "Execution time: " << exec_time_us * 1e-6 << " s, File time: "
- << processor->get_num_process_stream_calls() * 1.f /
- AudioProcessingSimulator::kChunksPerSecond
- << std::endl
- << "Time per fwd stream chunk (mean, max, min): " << std::endl
- << exec_time_us * 1.f / processor->get_num_process_stream_calls()
- << " us, " << 1.f * proc_time.max / rtc::kNumNanosecsPerMicrosec
- << " us, " << 1.f * proc_time.min / rtc::kNumNanosecsPerMicrosec
- << " us" << std::endl;
+ processor->GetApiCallStatistics().PrintReport();
+ }
+ if (settings.performance_report_output_filename) {
+ processor->GetApiCallStatistics().WriteReportToFile(
+ *settings.performance_report_output_filename);
}
if (settings.report_bitexactness && settings.aec_dump_input_filename) {