From 54a6149b4206a9791d934dd154c17b75ed8d1de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Terelius?= Date: Tue, 24 Oct 2023 18:32:06 +0200 Subject: [PATCH] C-style bindings around RTC event log analyzer (2). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Parses log, calls analyzer and populates output. Currently only outputs two charts. Chart selection to be added in a followup. Bug: None Change-Id: I960cff15a5935a638a5d979a71230ad598083596 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/324680 Reviewed-by: Mirko Bonadei Commit-Queue: Björn Terelius Commit-Queue: Mirko Bonadei Auto-Submit: Björn Terelius Cr-Commit-Position: refs/heads/main@{#41000} --- .../rtc_event_log_500kbps.binarypb.sha1 | 1 + rtc_tools/BUILD.gn | 30 ++++++- .../analyzer_bindings.cc | 83 +++++++++++++++++-- .../analyzer_bindings.h | 5 +- .../analyzer_bindings_unittest.cc | 68 +++++++++++++++ .../proto/chart_enums.proto | 1 + 6 files changed, 177 insertions(+), 11 deletions(-) create mode 100644 resources/rtc_event_log/rtc_event_log_500kbps.binarypb.sha1 create mode 100644 rtc_tools/rtc_event_log_visualizer/analyzer_bindings_unittest.cc diff --git a/resources/rtc_event_log/rtc_event_log_500kbps.binarypb.sha1 b/resources/rtc_event_log/rtc_event_log_500kbps.binarypb.sha1 new file mode 100644 index 0000000000..b190e48733 --- /dev/null +++ b/resources/rtc_event_log/rtc_event_log_500kbps.binarypb.sha1 @@ -0,0 +1 @@ +56e4ff9ea2b0fb92e88c7126f1df1283787ae0e5 \ No newline at end of file diff --git a/rtc_tools/BUILD.gn b/rtc_tools/BUILD.gn index 13d6df4e0f..c1c6181b67 100644 --- a/rtc_tools/BUILD.gn +++ b/rtc_tools/BUILD.gn @@ -430,7 +430,29 @@ if (!build_with_chromium) { "rtc_event_log_visualizer/analyzer_bindings.cc", "rtc_event_log_visualizer/analyzer_bindings.h", ] - deps = [ ":event_log_visualizer_utils" ] + deps = [ + ":chart_proto", + ":event_log_visualizer_utils", + "//api/units:time_delta", + "//logging:rtc_event_log_parser", + "//rtc_base:protobuf_utils", + "//rtc_base:safe_conversions", + "//rtc_base/system:unused", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] + } + + rtc_library("event_log_visualizer_bindings_unittest") { + testonly = true + sources = [ "rtc_event_log_visualizer/analyzer_bindings_unittest.cc" ] + deps = [ + ":chart_proto", + ":event_log_visualizer_bindings", + "//rtc_base:protobuf_utils", + "//rtc_base/system:file_wrapper", + "//test:fileutils", + "//test:test_support", + ] } } @@ -531,6 +553,7 @@ if (rtc_include_tests) { "../resources/foreman_128x96.yuv", "../resources/foreman_cif.yuv", "../resources/reference_less_video_test_file.y4m", + "../resources/rtc_event_log/rtc_event_log_500kbps.binarypb", ] if (is_ios) { @@ -582,7 +605,10 @@ if (rtc_include_tests) { } if (rtc_enable_protobuf) { - deps += [ "network_tester:network_tester_unittests" ] + deps += [ + ":event_log_visualizer_bindings_unittest", + "network_tester:network_tester_unittests", + ] } data = tools_unittests_resources diff --git a/rtc_tools/rtc_event_log_visualizer/analyzer_bindings.cc b/rtc_tools/rtc_event_log_visualizer/analyzer_bindings.cc index ab5035e62c..575b17f9af 100644 --- a/rtc_tools/rtc_event_log_visualizer/analyzer_bindings.cc +++ b/rtc_tools/rtc_event_log_visualizer/analyzer_bindings.cc @@ -10,18 +10,87 @@ #include "rtc_tools/rtc_event_log_visualizer/analyzer_bindings.h" -#include #include +#include +#include +#include -void analyze_rtc_event_log(const char* log, +#include "absl/strings/string_view.h" +#include "api/units/time_delta.h" +#include "logging/rtc_event_log/rtc_event_log_parser.h" +#include "rtc_base/numerics/safe_conversions.h" +#include "rtc_base/protobuf_utils.h" +#include "rtc_base/system/unused.h" +#include "rtc_tools/rtc_event_log_visualizer/analyzer.h" +#include "rtc_tools/rtc_event_log_visualizer/analyzer_common.h" +#include "rtc_tools/rtc_event_log_visualizer/plot_base.h" + +#ifdef WEBRTC_ANDROID_PLATFORM_BUILD +#include "external/webrtc/webrtc/rtc_tools/rtc_event_log_visualizer/proto/chart.pb.h" +#else +#include "rtc_tools/rtc_event_log_visualizer/proto/chart.pb.h" +#endif + +void analyze_rtc_event_log(const char* log_contents, size_t log_size, const char* selection, size_t selection_size, char* output, - size_t* output_size) { - size_t size = std::min(log_size, *output_size); - for (size_t i = 0; i < size; ++i) { - output[i] = log[i]; + uint32_t* output_size) { + RTC_UNUSED(selection); + RTC_UNUSED(selection_size); + + webrtc::ParsedRtcEventLog parsed_log( + webrtc::ParsedRtcEventLog::UnconfiguredHeaderExtensions::kDontParse, + /*allow_incomplete_logs*/ false); + + absl::string_view log_view(log_contents, log_size); + auto status = parsed_log.ParseString(log_view); + if (!status.ok()) { + std::cerr << "Failed to parse log: " << status.message() << std::endl; + *output_size = 0; + return; } - *output_size = size; + + webrtc::AnalyzerConfig config; + config.window_duration_ = webrtc::TimeDelta::Millis(250); + config.step_ = webrtc::TimeDelta::Millis(10); + if (!parsed_log.start_log_events().empty()) { + config.rtc_to_utc_offset_ = parsed_log.start_log_events()[0].utc_time() - + parsed_log.start_log_events()[0].log_time(); + } + config.normalize_time_ = true; + config.begin_time_ = parsed_log.first_timestamp(); + config.end_time_ = parsed_log.last_timestamp(); + if (config.end_time_ < config.begin_time_) { + std::cerr << "Log end time " << config.end_time_.ms() + << " not after begin time " << config.begin_time_.ms() + << ". Nothing to analyze. Is the log broken?"; + *output_size = 0; + return; + } + + webrtc::EventLogAnalyzer analyzer(parsed_log, config); + webrtc::PlotCollection collection; + collection.SetCallTimeToUtcOffsetMs(config.CallTimeToUtcOffsetMs()); + + analyzer.CreateTotalOutgoingBitrateGraph(collection.AppendNewPlot(), + /*show_detector_state*/ true, + /*show_alr_state*/ false, + /*show_link_capacity*/ true); + + analyzer.CreateNetworkDelayFeedbackGraph(collection.AppendNewPlot()); + + webrtc::analytics::ChartCollection proto_charts; + collection.ExportProtobuf(&proto_charts); + std::string serialized_charts = proto_charts.SerializeAsString(); + if (rtc::checked_cast(serialized_charts.size()) > *output_size) { + std::cerr << "Serialized charts larger than available output buffer: " + << serialized_charts.size() << " vs " << *output_size; + *output_size = 0; + return; + } + + memcpy(output, serialized_charts.data(), serialized_charts.size()); + *output_size = rtc::checked_cast(serialized_charts.size()); } diff --git a/rtc_tools/rtc_event_log_visualizer/analyzer_bindings.h b/rtc_tools/rtc_event_log_visualizer/analyzer_bindings.h index d24d6bd028..6662d9bc0e 100644 --- a/rtc_tools/rtc_event_log_visualizer/analyzer_bindings.h +++ b/rtc_tools/rtc_event_log_visualizer/analyzer_bindings.h @@ -12,12 +12,13 @@ #define RTC_TOOLS_RTC_EVENT_LOG_VISUALIZER_ANALYZER_BINDINGS_H_ #include +#include -void analyze_rtc_event_log(const char* log, +void analyze_rtc_event_log(const char* log_contents, size_t log_size, const char* selection, size_t selection_size, char* output, - size_t* output_size); + uint32_t* output_size); #endif // RTC_TOOLS_RTC_EVENT_LOG_VISUALIZER_ANALYZER_BINDINGS_H_ diff --git a/rtc_tools/rtc_event_log_visualizer/analyzer_bindings_unittest.cc b/rtc_tools/rtc_event_log_visualizer/analyzer_bindings_unittest.cc new file mode 100644 index 0000000000..8dabf935b2 --- /dev/null +++ b/rtc_tools/rtc_event_log_visualizer/analyzer_bindings_unittest.cc @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2023 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 "rtc_tools/rtc_event_log_visualizer/analyzer_bindings.h" + +#include +#include +#include + +#include "rtc_base/protobuf_utils.h" +#include "rtc_base/system/file_wrapper.h" +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/testsupport/file_utils.h" + +#ifdef WEBRTC_ANDROID_PLATFORM_BUILD +#include "external/webrtc/webrtc/rtc_tools/rtc_event_log_visualizer/proto/chart.pb.h" +#else +#include "rtc_tools/rtc_event_log_visualizer/proto/chart.pb.h" +#endif + +TEST(RtcEventLogAnalyzerBindingsTest, ProducesCharts) { + constexpr int kInputBufferSize = 1'000'000; + constexpr int kOutputBufferSize = 1'000'000; + std::unique_ptr input = std::make_unique(kInputBufferSize); + std::unique_ptr output = std::make_unique(kOutputBufferSize); + + // Read an RTC event log to a char buffer. + std::string file_name = webrtc::test::ResourcePath( + "rtc_event_log/rtc_event_log_500kbps", "binarypb"); + webrtc::FileWrapper file = webrtc::FileWrapper::OpenReadOnly(file_name); + ASSERT_TRUE(file.is_open()); + int64_t file_size = file.FileSize(); + ASSERT_LE(file_size, kInputBufferSize); + ASSERT_GT(file_size, 0); + size_t input_size = file.Read(input.get(), static_cast(file_size)); + ASSERT_EQ(static_cast(file_size), input_size); + + // Call analyzer. + uint32_t output_size = kOutputBufferSize; + char selection[] = ""; + size_t selection_size = strlen(selection); + analyze_rtc_event_log(input.get(), input_size, selection, selection_size, + output.get(), &output_size); + ASSERT_GT(output_size, 0u); + + // Parse output as charts. + webrtc::analytics::ChartCollection collection; + bool success = + collection.ParseFromArray(output.get(), static_cast(output_size)); + ASSERT_TRUE(success); + EXPECT_EQ(collection.charts().size(), 2); + std::vector chart_titles; + for (const auto& chart : collection.charts()) { + chart_titles.push_back(chart.title()); + } + EXPECT_THAT(chart_titles, + ::testing::UnorderedElementsAre( + "Outgoing RTP bitrate", + "Outgoing network delay (based on per-packet feedback)")); +} diff --git a/rtc_tools/rtc_event_log_visualizer/proto/chart_enums.proto b/rtc_tools/rtc_event_log_visualizer/proto/chart_enums.proto index 985ad0ad7d..8df7770e53 100644 --- a/rtc_tools/rtc_event_log_visualizer/proto/chart_enums.proto +++ b/rtc_tools/rtc_event_log_visualizer/proto/chart_enums.proto @@ -1,5 +1,6 @@ syntax = "proto3"; // Contains enums used as part of chart.proto +option optimize_for = LITE_RUNTIME; package webrtc.analytics; message ChartStyle {