mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-12 21:30:45 +01:00
Adds functionality to write logs to memory.
This makes it possible to save log outputs from scenario tests to either files or memory. Bug: webrtc:9510 Change-Id: I883bd8240ab712d31d54118adf979041bd83481a Reviewed-on: https://webrtc-review.googlesource.com/c/116321 Commit-Queue: Sebastian Jansson <srte@webrtc.org> Reviewed-by: Per Kjellander <perkj@webrtc.org> Reviewed-by: Niels Moller <nisse@webrtc.org> Reviewed-by: Björn Terelius <terelius@webrtc.org> Cr-Commit-Position: refs/heads/master@{#26284}
This commit is contained in:
parent
375b346b30
commit
52de8b0270
29 changed files with 527 additions and 173 deletions
|
@ -32,6 +32,9 @@ class RtcEventLogOutput {
|
|||
// after the first time |false| is returned. Write() may not be called on
|
||||
// an inactive output sink.
|
||||
virtual bool Write(const std::string& output) = 0;
|
||||
|
||||
// Indicates that buffers should be written to disk if applicable.
|
||||
virtual void Flush() {}
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
|
@ -101,6 +101,7 @@ if (rtc_include_tests) {
|
|||
"../../api/units:time_delta",
|
||||
"../../api/units:timestamp",
|
||||
"../../rtc_base:checks",
|
||||
"../../test/logging:log_writer",
|
||||
"//third_party/abseil-cpp/absl/types:optional",
|
||||
]
|
||||
}
|
||||
|
|
|
@ -128,6 +128,7 @@ if (rtc_include_tests) {
|
|||
"..:test_controller_printer",
|
||||
"../../../api/transport:network_control",
|
||||
"../../../api/units:timestamp",
|
||||
"../../../logging:rtc_event_log_api",
|
||||
"../../../rtc_base:checks",
|
||||
]
|
||||
}
|
||||
|
|
|
@ -24,15 +24,17 @@ bool BbrStatePrinter::Attached() const {
|
|||
return controller_ != nullptr;
|
||||
}
|
||||
|
||||
void BbrStatePrinter::PrintHeaders(FILE* out) {
|
||||
fprintf(out, "bbr_mode bbr_recovery_state round_trip_count gain_cycle_index");
|
||||
void BbrStatePrinter::PrintHeaders(RtcEventLogOutput* out) {
|
||||
LogWriteFormat(
|
||||
out, "bbr_mode bbr_recovery_state round_trip_count gain_cycle_index");
|
||||
}
|
||||
|
||||
void BbrStatePrinter::PrintValues(FILE* out) {
|
||||
void BbrStatePrinter::PrintValues(RtcEventLogOutput* out) {
|
||||
RTC_CHECK(controller_);
|
||||
bbr::BbrNetworkController::DebugState debug(*controller_);
|
||||
fprintf(out, "%i %i %i %i", debug.mode, debug.recovery_state,
|
||||
static_cast<int>(debug.round_trip_count), debug.gain_cycle_index);
|
||||
LogWriteFormat(out, "%i %i %i %i", debug.mode, debug.recovery_state,
|
||||
static_cast<int>(debug.round_trip_count),
|
||||
debug.gain_cycle_index);
|
||||
}
|
||||
|
||||
NetworkControlUpdate BbrStatePrinter::GetState(Timestamp at_time) const {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "api/transport/network_control.h"
|
||||
#include "api/transport/network_types.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "logging/rtc_event_log/rtc_event_log.h"
|
||||
#include "modules/congestion_controller/bbr/bbr_factory.h"
|
||||
#include "modules/congestion_controller/bbr/bbr_network_controller.h"
|
||||
#include "modules/congestion_controller/test/controller_printer.h"
|
||||
|
@ -28,8 +29,8 @@ class BbrStatePrinter : public DebugStatePrinter {
|
|||
void Attach(bbr::BbrNetworkController*);
|
||||
bool Attached() const override;
|
||||
|
||||
void PrintHeaders(FILE* out) override;
|
||||
void PrintValues(FILE* out) override;
|
||||
void PrintHeaders(RtcEventLogOutput* out) override;
|
||||
void PrintValues(RtcEventLogOutput* out) override;
|
||||
|
||||
NetworkControlUpdate GetState(Timestamp at_time) const override;
|
||||
|
||||
|
|
|
@ -31,25 +31,26 @@ bool GoogCcStatePrinter::Attached() const {
|
|||
return controller_ != nullptr;
|
||||
}
|
||||
|
||||
void GoogCcStatePrinter::PrintHeaders(FILE* out) {
|
||||
fprintf(out,
|
||||
"rate_control_state rate_control_region alr_state"
|
||||
" trendline trendline_modified_offset trendline_offset_threshold");
|
||||
void GoogCcStatePrinter::PrintHeaders(RtcEventLogOutput* out) {
|
||||
out->Write(
|
||||
"rate_control_state rate_control_region alr_state"
|
||||
" trendline trendline_modified_offset trendline_offset_threshold");
|
||||
}
|
||||
|
||||
void GoogCcStatePrinter::PrintValues(FILE* out) {
|
||||
void GoogCcStatePrinter::PrintValues(RtcEventLogOutput* out) {
|
||||
RTC_CHECK(controller_);
|
||||
auto* detector = controller_->delay_based_bwe_->delay_detector_.get();
|
||||
auto* trendline_estimator = reinterpret_cast<TrendlineEstimator*>(detector);
|
||||
fprintf(out, "%i %f %i %.6lf %.6lf %.6lf",
|
||||
controller_->delay_based_bwe_->rate_control_.rate_control_state_,
|
||||
controller_->delay_based_bwe_->rate_control_.link_capacity_
|
||||
.estimate_kbps_.value_or(NAN) *
|
||||
1000 / 8,
|
||||
controller_->alr_detector_->alr_started_time_ms_.has_value(),
|
||||
trendline_estimator->prev_trend_,
|
||||
trendline_estimator->prev_modified_trend_,
|
||||
trendline_estimator->threshold_);
|
||||
LogWriteFormat(
|
||||
out, "%i %f %i %.6lf %.6lf %.6lf",
|
||||
controller_->delay_based_bwe_->rate_control_.rate_control_state_,
|
||||
controller_->delay_based_bwe_->rate_control_.link_capacity_.estimate_kbps_
|
||||
.value_or(NAN) *
|
||||
1000 / 8,
|
||||
controller_->alr_detector_->alr_started_time_ms_.has_value(),
|
||||
trendline_estimator->prev_trend_,
|
||||
trendline_estimator->prev_modified_trend_,
|
||||
trendline_estimator->threshold_);
|
||||
}
|
||||
|
||||
NetworkControlUpdate GoogCcStatePrinter::GetState(Timestamp at_time) const {
|
||||
|
|
|
@ -29,8 +29,8 @@ class GoogCcStatePrinter : public DebugStatePrinter {
|
|||
void Attach(GoogCcNetworkController*);
|
||||
bool Attached() const override;
|
||||
|
||||
void PrintHeaders(FILE* out) override;
|
||||
void PrintValues(FILE* out) override;
|
||||
void PrintHeaders(RtcEventLogOutput* out) override;
|
||||
void PrintValues(RtcEventLogOutput* out) override;
|
||||
|
||||
NetworkControlUpdate GetState(Timestamp at_time) const override;
|
||||
|
||||
|
|
|
@ -20,20 +20,20 @@
|
|||
namespace webrtc {
|
||||
|
||||
ControlStatePrinter::ControlStatePrinter(
|
||||
FILE* output,
|
||||
std::unique_ptr<RtcEventLogOutput> output,
|
||||
std::unique_ptr<DebugStatePrinter> debug_printer)
|
||||
: output_(output), debug_printer_(std::move(debug_printer)) {}
|
||||
: output_(std::move(output)), debug_printer_(std::move(debug_printer)) {}
|
||||
|
||||
ControlStatePrinter::~ControlStatePrinter() = default;
|
||||
|
||||
void ControlStatePrinter::PrintHeaders() {
|
||||
fprintf(output_, "time bandwidth rtt target pacing padding window");
|
||||
output_->Write("time bandwidth rtt target pacing padding window");
|
||||
if (debug_printer_) {
|
||||
fprintf(output_, " ");
|
||||
debug_printer_->PrintHeaders(output_);
|
||||
output_->Write(" ");
|
||||
debug_printer_->PrintHeaders(output_.get());
|
||||
}
|
||||
fprintf(output_, "\n");
|
||||
fflush(output_);
|
||||
output_->Write("\n");
|
||||
output_->Flush();
|
||||
}
|
||||
|
||||
void ControlStatePrinter::PrintState(const Timestamp time,
|
||||
|
@ -48,16 +48,16 @@ void ControlStatePrinter::PrintState(const Timestamp time,
|
|||
double congestion_window = state.congestion_window
|
||||
? state.congestion_window->bytes<double>()
|
||||
: std::numeric_limits<double>::infinity();
|
||||
|
||||
fprintf(output_, "%f %f %f %f %f %f %f", timestamp, bandwidth, rtt,
|
||||
target_rate, pacing_rate, padding_rate, congestion_window);
|
||||
LogWriteFormat(output_.get(), "%f %f %f %f %f %f %f", timestamp, bandwidth,
|
||||
rtt, target_rate, pacing_rate, padding_rate,
|
||||
congestion_window);
|
||||
|
||||
if (debug_printer_) {
|
||||
fprintf(output_, " ");
|
||||
debug_printer_->PrintValues(output_);
|
||||
output_->Write(" ");
|
||||
debug_printer_->PrintValues(output_.get());
|
||||
}
|
||||
fprintf(output_, "\n");
|
||||
fflush(output_);
|
||||
output_->Write("\n");
|
||||
output_->Flush();
|
||||
}
|
||||
|
||||
void ControlStatePrinter::PrintState(const Timestamp time) {
|
||||
|
|
|
@ -10,25 +10,25 @@
|
|||
#ifndef MODULES_CONGESTION_CONTROLLER_TEST_CONTROLLER_PRINTER_H_
|
||||
#define MODULES_CONGESTION_CONTROLLER_TEST_CONTROLLER_PRINTER_H_
|
||||
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
|
||||
#include "api/transport/network_types.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "test/logging/log_writer.h"
|
||||
|
||||
namespace webrtc {
|
||||
class DebugStatePrinter {
|
||||
public:
|
||||
virtual bool Attached() const = 0;
|
||||
virtual void PrintHeaders(FILE* out) = 0;
|
||||
virtual void PrintValues(FILE* out) = 0;
|
||||
virtual void PrintHeaders(RtcEventLogOutput* out) = 0;
|
||||
virtual void PrintValues(RtcEventLogOutput* out) = 0;
|
||||
virtual NetworkControlUpdate GetState(Timestamp at_time) const = 0;
|
||||
virtual ~DebugStatePrinter() = default;
|
||||
};
|
||||
|
||||
class ControlStatePrinter {
|
||||
public:
|
||||
ControlStatePrinter(FILE* output,
|
||||
ControlStatePrinter(std::unique_ptr<RtcEventLogOutput> output,
|
||||
std::unique_ptr<DebugStatePrinter> debug_printer);
|
||||
~ControlStatePrinter();
|
||||
void PrintHeaders();
|
||||
|
@ -36,7 +36,7 @@ class ControlStatePrinter {
|
|||
void PrintState(const Timestamp time);
|
||||
|
||||
private:
|
||||
FILE* output_;
|
||||
std::unique_ptr<RtcEventLogOutput> output_;
|
||||
std::unique_ptr<DebugStatePrinter> debug_printer_;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
|
33
test/logging/BUILD.gn
Normal file
33
test/logging/BUILD.gn
Normal file
|
@ -0,0 +1,33 @@
|
|||
# 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.
|
||||
|
||||
import("../../webrtc.gni")
|
||||
|
||||
rtc_source_set("log_writer") {
|
||||
testonly = true
|
||||
visibility = [ "*" ]
|
||||
sources = [
|
||||
"file_log_writer.cc",
|
||||
"file_log_writer.h",
|
||||
"log_writer.cc",
|
||||
"log_writer.h",
|
||||
"memory_log_writer.cc",
|
||||
"memory_log_writer.h",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"../../api:libjingle_logging_api",
|
||||
"../../rtc_base:checks",
|
||||
"../../rtc_base:logging",
|
||||
"../../rtc_base:rtc_base_tests_utils",
|
||||
"../../rtc_base:stringutils",
|
||||
"../../test:fileutils",
|
||||
"//third_party/abseil-cpp/absl/memory",
|
||||
"//third_party/abseil-cpp/absl/types:optional",
|
||||
]
|
||||
}
|
62
test/logging/file_log_writer.cc
Normal file
62
test/logging/file_log_writer.cc
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright 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 "test/logging/file_log_writer.h"
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "test/testsupport/fileutils.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace webrtc_impl {
|
||||
|
||||
FileLogWriter::FileLogWriter(std::string file_path)
|
||||
: out_(std::fopen(file_path.c_str(), "wb")) {
|
||||
RTC_CHECK(out_ != nullptr)
|
||||
<< "Failed to open file: '" << file_path << "' for writing.";
|
||||
}
|
||||
|
||||
FileLogWriter::~FileLogWriter() {
|
||||
std::fclose(out_);
|
||||
}
|
||||
|
||||
bool FileLogWriter::IsActive() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileLogWriter::Write(const std::string& value) {
|
||||
// We don't expect the write to fail. If it does, we don't want to risk
|
||||
// silently ignoring it.
|
||||
RTC_CHECK_EQ(std::fwrite(value.data(), 1, value.size(), out_), value.size())
|
||||
<< "fwrite failed unexpectedly: " << errno;
|
||||
return true;
|
||||
}
|
||||
|
||||
void FileLogWriter::Flush() {
|
||||
RTC_CHECK_EQ(fflush(out_), 0) << "fflush failed unexpectedly: " << errno;
|
||||
}
|
||||
|
||||
} // namespace webrtc_impl
|
||||
|
||||
FileLogWriterFactory::FileLogWriterFactory(std::string base_path)
|
||||
: base_path_(base_path) {
|
||||
for (size_t i = 0; i < base_path.size(); ++i) {
|
||||
if (base_path[i] == '/')
|
||||
test::CreateDir(base_path.substr(0, i));
|
||||
}
|
||||
}
|
||||
|
||||
FileLogWriterFactory::~FileLogWriterFactory() {}
|
||||
|
||||
std::unique_ptr<RtcEventLogOutput> FileLogWriterFactory::Create(
|
||||
std::string filename) {
|
||||
return absl::make_unique<webrtc_impl::FileLogWriter>(base_path_ + filename);
|
||||
}
|
||||
} // namespace webrtc
|
48
test/logging/file_log_writer.h
Normal file
48
test/logging/file_log_writer.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 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 TEST_LOGGING_FILE_LOG_WRITER_H_
|
||||
#define TEST_LOGGING_FILE_LOG_WRITER_H_
|
||||
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "test/logging/log_writer.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace webrtc_impl {
|
||||
class FileLogWriter final : public RtcEventLogOutput {
|
||||
public:
|
||||
explicit FileLogWriter(std::string file_path);
|
||||
~FileLogWriter() final;
|
||||
bool IsActive() const override;
|
||||
bool Write(const std::string& value) override;
|
||||
void Flush() override;
|
||||
|
||||
private:
|
||||
std::FILE* const out_;
|
||||
};
|
||||
} // namespace webrtc_impl
|
||||
class FileLogWriterFactory final : public LogWriterFactoryInterface {
|
||||
public:
|
||||
explicit FileLogWriterFactory(std::string base_path);
|
||||
~FileLogWriterFactory() final;
|
||||
|
||||
std::unique_ptr<RtcEventLogOutput> Create(std::string filename) override;
|
||||
|
||||
private:
|
||||
const std::string base_path_;
|
||||
std::vector<std::unique_ptr<webrtc_impl::FileLogWriter>> writers_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // TEST_LOGGING_FILE_LOG_WRITER_H_
|
24
test/logging/log_writer.cc
Normal file
24
test/logging/log_writer.cc
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright 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 "test/logging/log_writer.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
LogWriterFactoryAddPrefix::LogWriterFactoryAddPrefix(
|
||||
LogWriterFactoryInterface* base,
|
||||
std::string prefix)
|
||||
: base_factory_(base), prefix_(prefix) {}
|
||||
|
||||
std::unique_ptr<RtcEventLogOutput> LogWriterFactoryAddPrefix::Create(
|
||||
std::string filename) {
|
||||
return base_factory_->Create(prefix_ + filename);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
60
test/logging/log_writer.h
Normal file
60
test/logging/log_writer.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright 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 TEST_LOGGING_LOG_WRITER_H_
|
||||
#define TEST_LOGGING_LOG_WRITER_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "api/rtceventlogoutput.h"
|
||||
#include "rtc_base/strings/string_builder.h"
|
||||
|
||||
namespace webrtc {
|
||||
template <class... Args>
|
||||
inline void LogWriteFormat(RtcEventLogOutput* out_, const char* fmt, ...) {
|
||||
va_list args, copy;
|
||||
va_start(args, fmt);
|
||||
va_copy(copy, args);
|
||||
const int predicted_length = std::vsnprintf(nullptr, 0, fmt, copy);
|
||||
va_end(copy);
|
||||
|
||||
RTC_DCHECK_GE(predicted_length, 0);
|
||||
std::string out_str(predicted_length, '\0');
|
||||
if (predicted_length > 0) {
|
||||
// Pass "+ 1" to vsnprintf to include space for the '\0'.
|
||||
const int actual_length =
|
||||
std::vsnprintf(&out_str.front(), predicted_length + 1, fmt, args);
|
||||
RTC_DCHECK_GE(actual_length, 0);
|
||||
}
|
||||
va_end(args);
|
||||
out_->Write(out_str);
|
||||
}
|
||||
|
||||
class LogWriterFactoryInterface {
|
||||
public:
|
||||
virtual std::unique_ptr<RtcEventLogOutput> Create(std::string filename) = 0;
|
||||
virtual ~LogWriterFactoryInterface() = default;
|
||||
};
|
||||
|
||||
class LogWriterFactoryAddPrefix : public LogWriterFactoryInterface {
|
||||
public:
|
||||
LogWriterFactoryAddPrefix(LogWriterFactoryInterface* base,
|
||||
std::string prefix);
|
||||
std::unique_ptr<RtcEventLogOutput> Create(std::string filename) override;
|
||||
|
||||
private:
|
||||
LogWriterFactoryInterface* const base_factory_;
|
||||
const std::string prefix_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // TEST_LOGGING_LOG_WRITER_H_
|
66
test/logging/memory_log_writer.cc
Normal file
66
test/logging/memory_log_writer.cc
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright 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 "test/logging/memory_log_writer.h"
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
class MemoryLogWriter final : public RtcEventLogOutput {
|
||||
public:
|
||||
explicit MemoryLogWriter(std::map<std::string, std::string>* target,
|
||||
std::string filename)
|
||||
: target_(target), filename_(filename) {}
|
||||
~MemoryLogWriter() final {
|
||||
size_t size;
|
||||
buffer_.GetSize(&size);
|
||||
target_->insert({filename_, std::string(buffer_.GetBuffer(), size)});
|
||||
}
|
||||
bool IsActive() const override { return true; }
|
||||
bool Write(const std::string& value) override {
|
||||
size_t written;
|
||||
int error;
|
||||
return buffer_.Write(value.data(), value.size(), &written, &error) ==
|
||||
rtc::SR_SUCCESS;
|
||||
}
|
||||
void Flush() override {}
|
||||
|
||||
private:
|
||||
std::map<std::string, std::string>* const target_;
|
||||
const std::string filename_;
|
||||
rtc::MemoryStream buffer_;
|
||||
};
|
||||
|
||||
class MemoryLogWriterFactory : public LogWriterFactoryInterface {
|
||||
public:
|
||||
explicit MemoryLogWriterFactory(std::map<std::string, std::string>* target)
|
||||
: target_(target) {}
|
||||
~MemoryLogWriterFactory() final {}
|
||||
std::unique_ptr<RtcEventLogOutput> Create(std::string filename) override {
|
||||
return absl::make_unique<MemoryLogWriter>(target_, filename);
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<std::string, std::string>* const target_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
MemoryLogStorage::MemoryLogStorage() {}
|
||||
|
||||
MemoryLogStorage::~MemoryLogStorage() {}
|
||||
|
||||
std::unique_ptr<LogWriterFactoryInterface> MemoryLogStorage::CreateFactory() {
|
||||
return absl::make_unique<MemoryLogWriterFactory>(&logs_);
|
||||
}
|
||||
|
||||
// namespace webrtc_impl
|
||||
} // namespace webrtc
|
41
test/logging/memory_log_writer.h
Normal file
41
test/logging/memory_log_writer.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 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 TEST_LOGGING_MEMORY_LOG_WRITER_H_
|
||||
#define TEST_LOGGING_MEMORY_LOG_WRITER_H_
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rtc_base/memory_stream.h"
|
||||
#include "test/logging/log_writer.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Allows creating log writer factories that creates log writers that saves
|
||||
// their content to memory. When the log writers are destroyed, their content is
|
||||
// saved to the logs_ member of this class. The intended usage is to keep this
|
||||
// class alive after the created factories and writers have been destroyed and
|
||||
// then use logs() to access all the saved logs.
|
||||
class MemoryLogStorage {
|
||||
public:
|
||||
MemoryLogStorage();
|
||||
~MemoryLogStorage();
|
||||
std::unique_ptr<LogWriterFactoryInterface> CreateFactory();
|
||||
const std::map<std::string, std::string>& logs() { return logs_; }
|
||||
|
||||
private:
|
||||
std::map<std::string, std::string> logs_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // TEST_LOGGING_MEMORY_LOG_WRITER_H_
|
|
@ -95,6 +95,7 @@ if (rtc_include_tests) {
|
|||
"../../system_wrappers",
|
||||
"../../system_wrappers:field_trial",
|
||||
"../../video",
|
||||
"../logging:log_writer",
|
||||
"network:emulated_network",
|
||||
"//third_party/abseil-cpp/absl/memory",
|
||||
"//third_party/abseil-cpp/absl/types:optional",
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include <utility>
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "logging/rtc_event_log/output/rtc_event_log_output_file.h"
|
||||
#include "modules/audio_mixer/audio_mixer_impl.h"
|
||||
#include "modules/congestion_controller/goog_cc/test/goog_cc_printer.h"
|
||||
#include "test/call_test.h"
|
||||
|
@ -57,39 +56,38 @@ Call* CreateCall(CallClientConfig config,
|
|||
}
|
||||
|
||||
LoggingNetworkControllerFactory::LoggingNetworkControllerFactory(
|
||||
std::string filename,
|
||||
LogWriterFactoryInterface* log_writer_factory,
|
||||
TransportControllerConfig config) {
|
||||
if (filename.empty()) {
|
||||
std::unique_ptr<RtcEventLogOutput> cc_out;
|
||||
if (!log_writer_factory) {
|
||||
event_log_ = RtcEventLog::CreateNull();
|
||||
} else {
|
||||
event_log_ = RtcEventLog::Create(RtcEventLog::EncodingType::Legacy);
|
||||
bool success = event_log_->StartLogging(
|
||||
absl::make_unique<RtcEventLogOutputFile>(filename + ".rtc.dat",
|
||||
RtcEventLog::kUnlimitedOutput),
|
||||
RtcEventLog::kImmediateOutput);
|
||||
log_writer_factory->Create(".rtc.dat"), RtcEventLog::kImmediateOutput);
|
||||
RTC_CHECK(success);
|
||||
cc_out_ = fopen((filename + ".cc_state.txt").c_str(), "w");
|
||||
cc_out = log_writer_factory->Create(".cc_state.txt");
|
||||
}
|
||||
switch (config.cc) {
|
||||
case TransportControllerConfig::CongestionController::kGoogCc:
|
||||
if (cc_out_) {
|
||||
if (cc_out) {
|
||||
auto goog_printer = absl::make_unique<GoogCcStatePrinter>();
|
||||
owned_cc_factory_.reset(
|
||||
new GoogCcDebugFactory(event_log_.get(), goog_printer.get()));
|
||||
cc_printer_.reset(
|
||||
new ControlStatePrinter(cc_out_, std::move(goog_printer)));
|
||||
cc_printer_.reset(new ControlStatePrinter(std::move(cc_out),
|
||||
std::move(goog_printer)));
|
||||
} else {
|
||||
owned_cc_factory_.reset(
|
||||
new GoogCcNetworkControllerFactory(event_log_.get()));
|
||||
}
|
||||
break;
|
||||
case TransportControllerConfig::CongestionController::kGoogCcFeedback:
|
||||
if (cc_out_) {
|
||||
if (cc_out) {
|
||||
auto goog_printer = absl::make_unique<GoogCcStatePrinter>();
|
||||
owned_cc_factory_.reset(new GoogCcFeedbackDebugFactory(
|
||||
event_log_.get(), goog_printer.get()));
|
||||
cc_printer_.reset(
|
||||
new ControlStatePrinter(cc_out_, std::move(goog_printer)));
|
||||
cc_printer_.reset(new ControlStatePrinter(std::move(cc_out),
|
||||
std::move(goog_printer)));
|
||||
} else {
|
||||
owned_cc_factory_.reset(
|
||||
new GoogCcFeedbackNetworkControllerFactory(event_log_.get()));
|
||||
|
@ -97,7 +95,7 @@ LoggingNetworkControllerFactory::LoggingNetworkControllerFactory(
|
|||
break;
|
||||
case TransportControllerConfig::CongestionController::kInjected:
|
||||
cc_factory_ = config.cc_factory;
|
||||
if (cc_out_)
|
||||
if (cc_out)
|
||||
RTC_LOG(LS_WARNING)
|
||||
<< "Can't log controller state for injected network controllers";
|
||||
break;
|
||||
|
@ -111,8 +109,6 @@ LoggingNetworkControllerFactory::LoggingNetworkControllerFactory(
|
|||
}
|
||||
|
||||
LoggingNetworkControllerFactory::~LoggingNetworkControllerFactory() {
|
||||
if (cc_out_)
|
||||
fclose(cc_out_);
|
||||
}
|
||||
|
||||
void LoggingNetworkControllerFactory::LogCongestionControllerStats(
|
||||
|
@ -134,13 +130,13 @@ TimeDelta LoggingNetworkControllerFactory::GetProcessInterval() const {
|
|||
return cc_factory_->GetProcessInterval();
|
||||
}
|
||||
|
||||
CallClient::CallClient(Clock* clock,
|
||||
std::string name,
|
||||
std::string log_filename,
|
||||
CallClientConfig config)
|
||||
CallClient::CallClient(
|
||||
Clock* clock,
|
||||
std::unique_ptr<LogWriterFactoryInterface> log_writer_factory,
|
||||
CallClientConfig config)
|
||||
: clock_(clock),
|
||||
name_(name),
|
||||
network_controller_factory_(log_filename, config.transport),
|
||||
log_writer_factory_(std::move(log_writer_factory)),
|
||||
network_controller_factory_(log_writer_factory_.get(), config.transport),
|
||||
fake_audio_setup_(InitAudio()),
|
||||
call_(CreateCall(config,
|
||||
&network_controller_factory_,
|
||||
|
@ -189,6 +185,12 @@ void CallClient::OnPacketReceived(EmulatedIpPacket packet) {
|
|||
packet.arrival_time.us());
|
||||
}
|
||||
|
||||
std::unique_ptr<RtcEventLogOutput> CallClient::GetLogWriter(std::string name) {
|
||||
if (!log_writer_factory_ || name.empty())
|
||||
return nullptr;
|
||||
return log_writer_factory_->Create(name);
|
||||
}
|
||||
|
||||
uint32_t CallClient::GetNextVideoSsrc() {
|
||||
RTC_CHECK_LT(next_video_ssrc_index_, CallTest::kNumSsrcs);
|
||||
return CallTest::kVideoSendSsrcs[next_video_ssrc_index_++];
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "modules/congestion_controller/test/controller_printer.h"
|
||||
#include "modules/rtp_rtcp/include/rtp_header_parser.h"
|
||||
#include "rtc_base/constructor_magic.h"
|
||||
#include "test/logging/log_writer.h"
|
||||
#include "test/scenario/column_printer.h"
|
||||
#include "test/scenario/network/network_emulation.h"
|
||||
#include "test/scenario/network_node.h"
|
||||
|
@ -30,7 +31,7 @@ namespace test {
|
|||
class LoggingNetworkControllerFactory
|
||||
: public NetworkControllerFactoryInterface {
|
||||
public:
|
||||
LoggingNetworkControllerFactory(std::string filename,
|
||||
LoggingNetworkControllerFactory(LogWriterFactoryInterface* log_writer_factory,
|
||||
TransportControllerConfig config);
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(LoggingNetworkControllerFactory);
|
||||
~LoggingNetworkControllerFactory();
|
||||
|
@ -46,7 +47,6 @@ class LoggingNetworkControllerFactory
|
|||
std::unique_ptr<NetworkControllerFactoryInterface> owned_cc_factory_;
|
||||
NetworkControllerFactoryInterface* cc_factory_ = nullptr;
|
||||
std::unique_ptr<ControlStatePrinter> cc_printer_;
|
||||
FILE* cc_out_ = nullptr;
|
||||
};
|
||||
|
||||
struct CallClientFakeAudio {
|
||||
|
@ -60,8 +60,7 @@ struct CallClientFakeAudio {
|
|||
class CallClient : public EmulatedNetworkReceiverInterface {
|
||||
public:
|
||||
CallClient(Clock* clock,
|
||||
std::string name,
|
||||
std::string log_filename,
|
||||
std::unique_ptr<LogWriterFactoryInterface> log_writer_factory,
|
||||
CallClientConfig config);
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(CallClient);
|
||||
|
||||
|
@ -73,6 +72,7 @@ class CallClient : public EmulatedNetworkReceiverInterface {
|
|||
}
|
||||
|
||||
void OnPacketReceived(EmulatedIpPacket packet) override;
|
||||
std::unique_ptr<RtcEventLogOutput> GetLogWriter(std::string name);
|
||||
|
||||
private:
|
||||
friend class Scenario;
|
||||
|
@ -91,7 +91,7 @@ class CallClient : public EmulatedNetworkReceiverInterface {
|
|||
void AddExtensions(std::vector<RtpExtension> extensions);
|
||||
|
||||
Clock* clock_;
|
||||
const std::string name_;
|
||||
const std::unique_ptr<LogWriterFactoryInterface> log_writer_factory_;
|
||||
LoggingNetworkControllerFactory network_controller_factory_;
|
||||
CallClientFakeAudio fake_audio_setup_;
|
||||
std::unique_ptr<Call> call_;
|
||||
|
|
|
@ -34,38 +34,26 @@ ColumnPrinter ColumnPrinter::Lambda(
|
|||
return ColumnPrinter(headers, printer, max_length);
|
||||
}
|
||||
|
||||
StatesPrinter::StatesPrinter(std::string filename,
|
||||
StatesPrinter::StatesPrinter(std::unique_ptr<RtcEventLogOutput> writer,
|
||||
std::vector<ColumnPrinter> printers)
|
||||
: StatesPrinter(printers) {
|
||||
if (!filename.empty()) {
|
||||
output_file_ = fopen(filename.c_str(), "w");
|
||||
RTC_CHECK(output_file_);
|
||||
output_ = output_file_;
|
||||
}
|
||||
}
|
||||
|
||||
StatesPrinter::StatesPrinter(std::vector<ColumnPrinter> printers)
|
||||
: printers_(printers) {
|
||||
output_ = stdout;
|
||||
: writer_(std::move(writer)), printers_(printers) {
|
||||
RTC_CHECK(!printers_.empty());
|
||||
for (auto& printer : printers_)
|
||||
buffer_size_ += printer.max_length_ + 1;
|
||||
buffer_.resize(buffer_size_);
|
||||
}
|
||||
|
||||
StatesPrinter::~StatesPrinter() {
|
||||
if (output_file_)
|
||||
fclose(output_file_);
|
||||
}
|
||||
StatesPrinter::~StatesPrinter() = default;
|
||||
|
||||
void StatesPrinter::PrintHeaders() {
|
||||
if (!output_file_)
|
||||
if (!writer_)
|
||||
return;
|
||||
fprintf(output_, "%s", printers_[0].headers_);
|
||||
writer_->Write(printers_[0].headers_);
|
||||
for (size_t i = 1; i < printers_.size(); ++i) {
|
||||
fprintf(output_, " %s", printers_[i].headers_);
|
||||
writer_->Write(" ");
|
||||
writer_->Write(printers_[i].headers_);
|
||||
}
|
||||
fputs("\n", output_);
|
||||
writer_->Write("\n");
|
||||
}
|
||||
|
||||
void StatesPrinter::PrintRow() {
|
||||
|
@ -77,9 +65,9 @@ void StatesPrinter::PrintRow() {
|
|||
sb << ' ';
|
||||
printers_[i].printer_(sb);
|
||||
}
|
||||
sb << "\n\0";
|
||||
if (output_file_)
|
||||
fputs(&buffer_.front(), output_);
|
||||
sb << "\n";
|
||||
if (writer_)
|
||||
writer_->Write(std::string(sb.str(), sb.size()));
|
||||
}
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "rtc_base/constructor_magic.h"
|
||||
#include "rtc_base/strings/string_builder.h"
|
||||
#include "test/logging/log_writer.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
|
@ -43,19 +44,18 @@ class ColumnPrinter {
|
|||
|
||||
class StatesPrinter {
|
||||
public:
|
||||
StatesPrinter(std::string filename, std::vector<ColumnPrinter> printers);
|
||||
explicit StatesPrinter(std::vector<ColumnPrinter> printers);
|
||||
StatesPrinter(std::unique_ptr<RtcEventLogOutput> writer,
|
||||
std::vector<ColumnPrinter> printers);
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(StatesPrinter);
|
||||
~StatesPrinter();
|
||||
void PrintHeaders();
|
||||
void PrintRow();
|
||||
|
||||
private:
|
||||
const std::unique_ptr<RtcEventLogOutput> writer_;
|
||||
const std::vector<ColumnPrinter> printers_;
|
||||
size_t buffer_size_ = 0;
|
||||
std::vector<char> buffer_;
|
||||
FILE* output_file_ = nullptr;
|
||||
FILE* output_ = nullptr;
|
||||
};
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
|
|
|
@ -19,12 +19,10 @@ namespace webrtc {
|
|||
namespace test {
|
||||
|
||||
VideoQualityAnalyzer::VideoQualityAnalyzer(
|
||||
std::string filename_or_empty,
|
||||
std::unique_ptr<RtcEventLogOutput> writer,
|
||||
std::function<void(const VideoFrameQualityInfo&)> frame_info_handler)
|
||||
: task_queue_("VideoAnalyzer") {
|
||||
if (!filename_or_empty.empty()) {
|
||||
output_file_ = fopen(filename_or_empty.c_str(), "w");
|
||||
RTC_CHECK(output_file_);
|
||||
: writer_(std::move(writer)), task_queue_("VideoAnalyzer") {
|
||||
if (writer_) {
|
||||
PrintHeaders();
|
||||
frame_info_handlers_.push_back(
|
||||
[this](const VideoFrameQualityInfo& info) { PrintFrameInfo(info); });
|
||||
|
@ -37,8 +35,6 @@ VideoQualityAnalyzer::~VideoQualityAnalyzer() {
|
|||
rtc::Event event;
|
||||
task_queue_.PostTask([&event] { event.Set(); });
|
||||
event.Wait(rtc::Event::kForever);
|
||||
if (output_file_)
|
||||
fclose(output_file_);
|
||||
}
|
||||
|
||||
void VideoQualityAnalyzer::OnCapturedFrame(const VideoFrame& frame) {
|
||||
|
@ -114,15 +110,15 @@ int64_t VideoQualityAnalyzer::CapturedFrameCaptureTimeOffsetMs(
|
|||
}
|
||||
|
||||
void VideoQualityAnalyzer::PrintHeaders() {
|
||||
fprintf(output_file_, "capt recv_capt render width height psnr\n");
|
||||
writer_->Write("capt recv_capt render width height psnr\n");
|
||||
}
|
||||
|
||||
void VideoQualityAnalyzer::PrintFrameInfo(const VideoFrameQualityInfo& sample) {
|
||||
fprintf(output_file_, "%.3f %.3f %.3f %i %i %.3f\n",
|
||||
sample.capture_time.seconds<double>(),
|
||||
sample.received_capture_time.seconds<double>(),
|
||||
sample.render_time.seconds<double>(), sample.width, sample.height,
|
||||
sample.psnr);
|
||||
LogWriteFormat(writer_.get(), "%.3f %.3f %.3f %i %i %.3f\n",
|
||||
sample.capture_time.seconds<double>(),
|
||||
sample.received_capture_time.seconds<double>(),
|
||||
sample.render_time.seconds<double>(), sample.width,
|
||||
sample.height, sample.psnr);
|
||||
}
|
||||
|
||||
void VideoQualityStats::HandleFrameInfo(VideoFrameQualityInfo sample) {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#define TEST_SCENARIO_QUALITY_STATS_H_
|
||||
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
@ -22,6 +23,7 @@
|
|||
#include "rtc_base/task_queue.h"
|
||||
#include "rtc_base/time_utils.h"
|
||||
#include "system_wrappers/include/clock.h"
|
||||
#include "test/logging/log_writer.h"
|
||||
#include "test/scenario/quality_info.h"
|
||||
#include "test/scenario/scenario_config.h"
|
||||
#include "test/statistics.h"
|
||||
|
@ -32,7 +34,7 @@ namespace test {
|
|||
class VideoQualityAnalyzer {
|
||||
public:
|
||||
VideoQualityAnalyzer(
|
||||
std::string filename_or_empty,
|
||||
std::unique_ptr<RtcEventLogOutput> writer,
|
||||
std::function<void(const VideoFrameQualityInfo&)> frame_info_handler);
|
||||
~VideoQualityAnalyzer();
|
||||
void OnCapturedFrame(const VideoFrame& frame);
|
||||
|
@ -46,12 +48,12 @@ class VideoQualityAnalyzer {
|
|||
int64_t CapturedFrameCaptureTimeOffsetMs(const VideoFrame& captured) const;
|
||||
void PrintHeaders();
|
||||
void PrintFrameInfo(const VideoFrameQualityInfo& sample);
|
||||
const std::unique_ptr<RtcEventLogOutput> writer_;
|
||||
std::vector<std::function<void(const VideoFrameQualityInfo&)>>
|
||||
frame_info_handlers_;
|
||||
std::deque<VideoFrame> captured_frames_;
|
||||
absl::optional<int64_t> first_capture_ntp_time_ms_;
|
||||
absl::optional<uint32_t> first_decode_rtp_timestamp_;
|
||||
FILE* output_file_ = nullptr;
|
||||
rtc::TaskQueue task_queue_;
|
||||
};
|
||||
|
||||
|
|
|
@ -11,10 +11,12 @@
|
|||
|
||||
#include <algorithm>
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "api/audio_codecs/builtin_audio_decoder_factory.h"
|
||||
#include "api/audio_codecs/builtin_audio_encoder_factory.h"
|
||||
#include "rtc_base/flags.h"
|
||||
#include "rtc_base/socket_address.h"
|
||||
#include "test/logging/file_log_writer.h"
|
||||
#include "test/scenario/network/network_emulation.h"
|
||||
#include "test/testsupport/file_utils.h"
|
||||
|
||||
|
@ -27,6 +29,19 @@ namespace webrtc {
|
|||
namespace test {
|
||||
namespace {
|
||||
int64_t kMicrosPerSec = 1000000;
|
||||
std::unique_ptr<FileLogWriterFactory> GetScenarioLogManager(
|
||||
std::string file_name) {
|
||||
if (FLAG_scenario_logs && !file_name.empty()) {
|
||||
std::string output_root = FLAG_out_root;
|
||||
if (output_root.empty())
|
||||
output_root = OutputPath() + "output_data/";
|
||||
|
||||
auto base_filename = output_root + file_name + ".";
|
||||
RTC_LOG(LS_INFO) << "Saving scenario logs to: " << base_filename;
|
||||
return absl::make_unique<FileLogWriterFactory>(base_filename);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
RepeatedActivity::RepeatedActivity(TimeDelta interval,
|
||||
|
@ -54,30 +69,24 @@ Timestamp RepeatedActivity::NextTime() {
|
|||
return last_update_ + interval_;
|
||||
}
|
||||
|
||||
Scenario::Scenario() : Scenario("", true) {}
|
||||
Scenario::Scenario()
|
||||
: Scenario(std::unique_ptr<LogWriterFactoryInterface>(), true) {}
|
||||
|
||||
Scenario::Scenario(std::string file_name) : Scenario(file_name, true) {}
|
||||
|
||||
Scenario::Scenario(std::string file_name, bool real_time)
|
||||
: real_time_mode_(real_time),
|
||||
: Scenario(GetScenarioLogManager(file_name), real_time) {}
|
||||
|
||||
Scenario::Scenario(
|
||||
std::unique_ptr<LogWriterFactoryInterface> log_writer_factory,
|
||||
bool real_time)
|
||||
: log_writer_factory_(std::move(log_writer_factory)),
|
||||
real_time_mode_(real_time),
|
||||
sim_clock_(100000 * kMicrosPerSec),
|
||||
clock_(real_time ? Clock::GetRealTimeClock() : &sim_clock_),
|
||||
audio_decoder_factory_(CreateBuiltinAudioDecoderFactory()),
|
||||
audio_encoder_factory_(CreateBuiltinAudioEncoderFactory()) {
|
||||
if (FLAG_scenario_logs && !file_name.empty()) {
|
||||
std::string output_root = FLAG_out_root;
|
||||
if (output_root.empty())
|
||||
output_root = OutputPath() + "output_data/";
|
||||
if (output_root.back() == '/')
|
||||
CreateDir(output_root);
|
||||
for (size_t i = 0; i < file_name.size(); ++i) {
|
||||
if (file_name[i] == '/')
|
||||
CreateDir(output_root + file_name.substr(0, i));
|
||||
}
|
||||
base_filename_ = output_root + file_name;
|
||||
RTC_LOG(LS_INFO) << "Saving scenario logs to: " << base_filename_;
|
||||
}
|
||||
if (!real_time_mode_ && !base_filename_.empty()) {
|
||||
if (!real_time_mode_ && log_writer_factory_) {
|
||||
rtc::SetClockForTesting(&event_log_fake_clock_);
|
||||
event_log_fake_clock_.SetTimeNanos(sim_clock_.TimeInMicroseconds() * 1000);
|
||||
}
|
||||
|
@ -105,8 +114,7 @@ StatesPrinter* Scenario::CreatePrinter(std::string name,
|
|||
std::vector<ColumnPrinter> all_printers{TimePrinter()};
|
||||
for (auto& printer : printers)
|
||||
all_printers.push_back(printer);
|
||||
StatesPrinter* printer =
|
||||
new StatesPrinter(GetFullPathOrEmpty(name), all_printers);
|
||||
StatesPrinter* printer = new StatesPrinter(GetLogWriter(name), all_printers);
|
||||
printers_.emplace_back(printer);
|
||||
printer->PrintHeaders();
|
||||
if (interval.IsFinite())
|
||||
|
@ -117,7 +125,7 @@ StatesPrinter* Scenario::CreatePrinter(std::string name,
|
|||
CallClient* Scenario::CreateClient(std::string name, CallClientConfig config) {
|
||||
RTC_DCHECK(real_time_mode_);
|
||||
CallClient* client =
|
||||
new CallClient(clock_, name, GetFullPathOrEmpty(name), config);
|
||||
new CallClient(clock_, GetLogWriterFactory(name), config);
|
||||
if (config.transport.state_log_interval.IsFinite()) {
|
||||
Every(config.transport.state_log_interval, [this, client]() {
|
||||
client->network_controller_factory_.LogCongestionControllerStats(Now());
|
||||
|
@ -182,9 +190,9 @@ SimulatedTimeClient* Scenario::CreateSimulatedTimeClient(
|
|||
uint64_t send_id = next_route_id_++;
|
||||
uint64_t return_id = next_route_id_++;
|
||||
SimulatedTimeClient* client = new SimulatedTimeClient(
|
||||
GetFullPathOrEmpty(name), config, stream_configs, send_link, return_link,
|
||||
GetLogWriterFactory(name), config, stream_configs, send_link, return_link,
|
||||
send_id, return_id, Now());
|
||||
if (!base_filename_.empty() && !name.empty() &&
|
||||
if (log_writer_factory_ && !name.empty() &&
|
||||
config.transport.state_log_interval.IsFinite()) {
|
||||
Every(config.transport.state_log_interval, [this, client]() {
|
||||
client->network_controller_factory_.LogCongestionControllerStats(Now());
|
||||
|
@ -283,12 +291,11 @@ VideoStreamPair* Scenario::CreateVideoStream(
|
|||
VideoStreamPair* Scenario::CreateVideoStream(
|
||||
std::pair<CallClient*, CallClient*> clients,
|
||||
VideoStreamConfig config) {
|
||||
std::string quality_log_file_name;
|
||||
std::unique_ptr<RtcEventLogOutput> quality_logger;
|
||||
if (config.analyzer.log_to_file)
|
||||
quality_log_file_name =
|
||||
GetFullPathOrEmpty(clients.first->name_ + ".video_quality.txt");
|
||||
quality_logger = clients.first->GetLogWriter(".video_quality.txt");
|
||||
video_streams_.emplace_back(new VideoStreamPair(
|
||||
clients.first, clients.second, config, quality_log_file_name));
|
||||
clients.first, clients.second, config, std::move(quality_logger)));
|
||||
return video_streams_.back().get();
|
||||
}
|
||||
|
||||
|
@ -364,7 +371,7 @@ void Scenario::RunUntil(TimeDelta max_duration,
|
|||
sim_clock_.AdvanceTimeMicroseconds(wait_time.us());
|
||||
// The fake clock is quite slow to update, we only update it if logging is
|
||||
// turned on to save time.
|
||||
if (!base_filename_.empty())
|
||||
if (!log_writer_factory_)
|
||||
event_log_fake_clock_.SetTimeNanos(sim_clock_.TimeInMicroseconds() *
|
||||
1000);
|
||||
}
|
||||
|
|
|
@ -14,8 +14,10 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "rtc_base/constructor_magic.h"
|
||||
#include "rtc_base/fake_clock.h"
|
||||
#include "test/logging/log_writer.h"
|
||||
#include "test/scenario/audio_stream.h"
|
||||
#include "test/scenario/call_client.h"
|
||||
#include "test/scenario/column_printer.h"
|
||||
|
@ -63,6 +65,8 @@ class Scenario {
|
|||
Scenario();
|
||||
explicit Scenario(std::string file_name);
|
||||
Scenario(std::string file_name, bool real_time);
|
||||
Scenario(std::unique_ptr<LogWriterFactoryInterface> log_writer_manager,
|
||||
bool real_time);
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(Scenario);
|
||||
~Scenario();
|
||||
|
||||
|
@ -163,15 +167,22 @@ class Scenario {
|
|||
// Return the duration of the current session so far.
|
||||
TimeDelta Duration();
|
||||
|
||||
std::string GetFullPathOrEmpty(std::string name) const {
|
||||
if (base_filename_.empty() || name.empty())
|
||||
return std::string();
|
||||
return base_filename_ + "." + name;
|
||||
std::unique_ptr<RtcEventLogOutput> GetLogWriter(std::string name) {
|
||||
if (!log_writer_factory_ || name.empty())
|
||||
return nullptr;
|
||||
return log_writer_factory_->Create(name);
|
||||
}
|
||||
std::unique_ptr<LogWriterFactoryInterface> GetLogWriterFactory(
|
||||
std::string name) {
|
||||
if (!log_writer_factory_ || name.empty())
|
||||
return nullptr;
|
||||
return absl::make_unique<LogWriterFactoryAddPrefix>(
|
||||
log_writer_factory_.get(), name);
|
||||
}
|
||||
|
||||
private:
|
||||
NullReceiver null_receiver_;
|
||||
std::string base_filename_;
|
||||
std::unique_ptr<LogWriterFactoryInterface> log_writer_factory_;
|
||||
const bool real_time_mode_;
|
||||
SimulatedClock sim_clock_;
|
||||
Clock* clock_;
|
||||
|
|
|
@ -245,7 +245,7 @@ void SimulatedFeedback::OnPacketReceived(EmulatedIpPacket packet) {
|
|||
}
|
||||
|
||||
SimulatedTimeClient::SimulatedTimeClient(
|
||||
std::string log_filename,
|
||||
std::unique_ptr<LogWriterFactoryInterface> log_writer_factory,
|
||||
SimulatedTimeClientConfig config,
|
||||
std::vector<PacketStreamConfig> stream_configs,
|
||||
std::vector<EmulatedNetworkNode*> send_link,
|
||||
|
@ -253,7 +253,8 @@ SimulatedTimeClient::SimulatedTimeClient(
|
|||
uint64_t send_receiver_id,
|
||||
uint64_t return_receiver_id,
|
||||
Timestamp at_time)
|
||||
: network_controller_factory_(log_filename, config.transport),
|
||||
: log_writer_factory_(std::move(log_writer_factory)),
|
||||
network_controller_factory_(log_writer_factory_.get(), config.transport),
|
||||
send_link_(send_link),
|
||||
return_link_(return_link),
|
||||
sender_(send_link.front(), send_receiver_id),
|
||||
|
@ -274,11 +275,10 @@ SimulatedTimeClient::SimulatedTimeClient(
|
|||
|
||||
CongestionProcess(at_time);
|
||||
network_controller_factory_.LogCongestionControllerStats(at_time);
|
||||
if (!log_filename.empty()) {
|
||||
std::string packet_log_name = log_filename + ".packets.txt";
|
||||
packet_log_ = fopen(packet_log_name.c_str(), "w");
|
||||
fprintf(packet_log_,
|
||||
"transport_seq packet_size send_time recv_time feed_time\n");
|
||||
if (log_writer_factory_) {
|
||||
packet_log_ = log_writer_factory_->Create(".packets.txt");
|
||||
packet_log_->Write(
|
||||
"transport_seq packet_size send_time recv_time feed_time\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -289,18 +289,17 @@ void SimulatedTimeClient::OnPacketReceived(EmulatedIpPacket packet) {
|
|||
packet.arrival_time);
|
||||
for (PacketResult& feedback : report.packet_feedbacks) {
|
||||
if (packet_log_)
|
||||
fprintf(packet_log_, "%" PRId64 " %" PRId64 " %.3lf %.3lf %.3lf\n",
|
||||
feedback.sent_packet.sequence_number,
|
||||
feedback.sent_packet.size.bytes(),
|
||||
feedback.sent_packet.send_time.seconds<double>(),
|
||||
feedback.receive_time.seconds<double>(),
|
||||
packet.arrival_time.seconds<double>());
|
||||
LogWriteFormat(packet_log_.get(),
|
||||
"%" PRId64 " %" PRId64 " %.3lf %.3lf %.3lf\n",
|
||||
feedback.sent_packet.sequence_number,
|
||||
feedback.sent_packet.size.bytes(),
|
||||
feedback.sent_packet.send_time.seconds<double>(),
|
||||
feedback.receive_time.seconds<double>(),
|
||||
packet.arrival_time.seconds<double>());
|
||||
}
|
||||
Update(congestion_controller_->OnTransportPacketsFeedback(report));
|
||||
}
|
||||
SimulatedTimeClient::~SimulatedTimeClient() {
|
||||
if (packet_log_)
|
||||
fclose(packet_log_);
|
||||
}
|
||||
|
||||
void SimulatedTimeClient::Update(NetworkControlUpdate update) {
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#define TEST_SCENARIO_SIMULATED_TIME_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
@ -25,6 +24,7 @@
|
|||
#include "api/units/time_delta.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "rtc_base/copy_on_write_buffer.h"
|
||||
#include "test/logging/log_writer.h"
|
||||
#include "test/scenario/call_client.h"
|
||||
#include "test/scenario/network_node.h"
|
||||
#include "test/scenario/scenario_config.h"
|
||||
|
@ -120,14 +120,15 @@ class SimulatedSender {
|
|||
// a more accurate simulation, use the real time only CallClient.
|
||||
class SimulatedTimeClient : EmulatedNetworkReceiverInterface {
|
||||
public:
|
||||
SimulatedTimeClient(std::string log_filename,
|
||||
SimulatedTimeClientConfig config,
|
||||
std::vector<PacketStreamConfig> stream_configs,
|
||||
std::vector<EmulatedNetworkNode*> send_link,
|
||||
std::vector<EmulatedNetworkNode*> return_link,
|
||||
uint64_t send_receiver_id,
|
||||
uint64_t return_receiver_id,
|
||||
Timestamp at_time);
|
||||
SimulatedTimeClient(
|
||||
std::unique_ptr<LogWriterFactoryInterface> log_writer_factory,
|
||||
SimulatedTimeClientConfig config,
|
||||
std::vector<PacketStreamConfig> stream_configs,
|
||||
std::vector<EmulatedNetworkNode*> send_link,
|
||||
std::vector<EmulatedNetworkNode*> return_link,
|
||||
uint64_t send_receiver_id,
|
||||
uint64_t return_receiver_id,
|
||||
Timestamp at_time);
|
||||
SimulatedTimeClient(const SimulatedTimeClient&) = delete;
|
||||
~SimulatedTimeClient();
|
||||
void Update(NetworkControlUpdate update);
|
||||
|
@ -144,6 +145,7 @@ class SimulatedTimeClient : EmulatedNetworkReceiverInterface {
|
|||
|
||||
private:
|
||||
friend class Scenario;
|
||||
std::unique_ptr<LogWriterFactoryInterface> log_writer_factory_;
|
||||
LoggingNetworkControllerFactory network_controller_factory_;
|
||||
std::unique_ptr<NetworkControllerInterface> congestion_controller_;
|
||||
std::vector<EmulatedNetworkNode*> send_link_;
|
||||
|
@ -153,7 +155,7 @@ class SimulatedTimeClient : EmulatedNetworkReceiverInterface {
|
|||
TargetRateConstraints current_contraints_;
|
||||
DataRate target_rate_ = DataRate::Infinity();
|
||||
DataRate link_capacity_ = DataRate::Infinity();
|
||||
FILE* packet_log_ = nullptr;
|
||||
std::unique_ptr<RtcEventLogOutput> packet_log_;
|
||||
|
||||
std::vector<std::unique_ptr<PacketStream>> packet_streams_;
|
||||
};
|
||||
|
|
|
@ -399,12 +399,14 @@ void ReceiveVideoStream::Start() {
|
|||
|
||||
VideoStreamPair::~VideoStreamPair() = default;
|
||||
|
||||
VideoStreamPair::VideoStreamPair(CallClient* sender,
|
||||
CallClient* receiver,
|
||||
VideoStreamConfig config,
|
||||
std::string quality_log_file_name)
|
||||
VideoStreamPair::VideoStreamPair(
|
||||
CallClient* sender,
|
||||
CallClient* receiver,
|
||||
VideoStreamConfig config,
|
||||
std::unique_ptr<RtcEventLogOutput> quality_writer)
|
||||
: config_(config),
|
||||
analyzer_(quality_log_file_name, config.analyzer.frame_quality_handler),
|
||||
analyzer_(std::move(quality_writer),
|
||||
config.analyzer.frame_quality_handler),
|
||||
send_stream_(sender, config, &sender->transport_, &analyzer_),
|
||||
receive_stream_(receiver,
|
||||
config,
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "rtc_base/constructor_magic.h"
|
||||
#include "test/fake_encoder.h"
|
||||
#include "test/frame_generator_capturer.h"
|
||||
#include "test/logging/log_writer.h"
|
||||
#include "test/scenario/call_client.h"
|
||||
#include "test/scenario/column_printer.h"
|
||||
#include "test/scenario/network_node.h"
|
||||
|
@ -104,7 +105,7 @@ class VideoStreamPair {
|
|||
VideoStreamPair(CallClient* sender,
|
||||
CallClient* receiver,
|
||||
VideoStreamConfig config,
|
||||
std::string quality_log_file_name);
|
||||
std::unique_ptr<RtcEventLogOutput> quality_writer);
|
||||
|
||||
const VideoStreamConfig config_;
|
||||
|
||||
|
|
Loading…
Reference in a new issue