Adds field trial parser.
Bug: webrtc:9346 Change-Id: Ibd07a1753feaa40d4be4d465d61f55bc8a8a9325 Reviewed-on: https://webrtc-review.googlesource.com/80263 Commit-Queue: Sebastian Jansson <srte@webrtc.org> Reviewed-by: Niels Moller <nisse@webrtc.org> Reviewed-by: Stefan Holmer <stefan@webrtc.org> Reviewed-by: Christoffer Rodbro <crodbro@webrtc.org> Cr-Commit-Position: refs/heads/master@{#23615}
This commit is contained in:
parent
7c32c866c0
commit
9eb38866cd
@ -20,6 +20,23 @@ rtc_static_library("alr_experiment") {
|
||||
]
|
||||
}
|
||||
|
||||
rtc_static_library("field_trial_parser") {
|
||||
sources = [
|
||||
"field_trial_parser.cc",
|
||||
"field_trial_parser.h",
|
||||
"field_trial_units.cc",
|
||||
"field_trial_units.h",
|
||||
]
|
||||
deps = [
|
||||
"../:rtc_base_approved",
|
||||
"../../api:optional",
|
||||
"../../api/units:data_rate",
|
||||
"../../api/units:data_size",
|
||||
"../../api/units:time_delta",
|
||||
"../../system_wrappers:field_trial_api",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_static_library("congestion_controller_experiment") {
|
||||
sources = [
|
||||
"congestion_controller_experiment.cc",
|
||||
@ -52,13 +69,17 @@ if (rtc_include_tests) {
|
||||
|
||||
sources = [
|
||||
"congestion_controller_experiment_unittest.cc",
|
||||
"field_trial_parser_unittest.cc",
|
||||
"field_trial_units_unittest.cc",
|
||||
"quality_scaling_experiment_unittest.cc",
|
||||
]
|
||||
deps = [
|
||||
":congestion_controller_experiment",
|
||||
":field_trial_parser",
|
||||
":quality_scaling_experiment",
|
||||
"../:rtc_base_tests_main",
|
||||
"../:rtc_base_tests_utils",
|
||||
"../../system_wrappers:field_trial_api",
|
||||
"../../test:field_trial",
|
||||
]
|
||||
}
|
||||
|
||||
134
rtc_base/experiments/field_trial_parser.cc
Normal file
134
rtc_base/experiments/field_trial_parser.cc
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2018 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_base/experiments/field_trial_parser.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
int FindOrEnd(std::string str, size_t start, char delimiter) {
|
||||
size_t pos = str.find(delimiter, start);
|
||||
pos = (pos == std::string::npos) ? str.length() : pos;
|
||||
return static_cast<int>(pos);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
FieldTrialParameterInterface::FieldTrialParameterInterface(std::string key)
|
||||
: key_(key) {}
|
||||
FieldTrialParameterInterface::~FieldTrialParameterInterface() = default;
|
||||
std::string FieldTrialParameterInterface::Key() const {
|
||||
return key_;
|
||||
}
|
||||
|
||||
void ParseFieldTrial(
|
||||
std::initializer_list<FieldTrialParameterInterface*> fields,
|
||||
std::string trial_string) {
|
||||
std::map<std::string, FieldTrialParameterInterface*> field_map;
|
||||
for (FieldTrialParameterInterface* field : fields) {
|
||||
field_map[field->Key()] = field;
|
||||
}
|
||||
size_t i = 0;
|
||||
while (i < trial_string.length()) {
|
||||
int val_end = FindOrEnd(trial_string, i, ',');
|
||||
int colon_pos = FindOrEnd(trial_string, i, ':');
|
||||
int key_end = std::min(val_end, colon_pos);
|
||||
int val_begin = key_end + 1;
|
||||
std::string key = trial_string.substr(i, key_end - i);
|
||||
rtc::Optional<std::string> opt_value;
|
||||
if (val_end >= val_begin)
|
||||
opt_value = trial_string.substr(val_begin, val_end - val_begin);
|
||||
i = val_end + 1;
|
||||
auto field = field_map.find(key);
|
||||
if (field != field_map.end()) {
|
||||
if (!field->second->Parse(std::move(opt_value))) {
|
||||
RTC_LOG(LS_WARNING) << "Failed to read field with key: '" << key
|
||||
<< "' in trial: \"" << trial_string << "\"";
|
||||
}
|
||||
} else {
|
||||
RTC_LOG(LS_INFO) << "No field with key: '" << key
|
||||
<< "' (found in trial: \"" << trial_string << "\")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
rtc::Optional<bool> ParseTypedParameter<bool>(std::string str) {
|
||||
if (str == "true" || str == "1") {
|
||||
return true;
|
||||
} else if (str == "false" || str == "0") {
|
||||
return false;
|
||||
}
|
||||
return rtc::nullopt;
|
||||
}
|
||||
|
||||
template <>
|
||||
rtc::Optional<double> ParseTypedParameter<double>(std::string str) {
|
||||
double value;
|
||||
if (sscanf(str.c_str(), "%lf", &value) == 1) {
|
||||
return value;
|
||||
} else {
|
||||
return rtc::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
rtc::Optional<int> ParseTypedParameter<int>(std::string str) {
|
||||
int value;
|
||||
if (sscanf(str.c_str(), "%i", &value) == 1) {
|
||||
return value;
|
||||
} else {
|
||||
return rtc::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
rtc::Optional<std::string> ParseTypedParameter<std::string>(std::string str) {
|
||||
return std::move(str);
|
||||
}
|
||||
|
||||
FieldTrialFlag::FieldTrialFlag(std::string key) : FieldTrialFlag(key, false) {}
|
||||
|
||||
FieldTrialFlag::FieldTrialFlag(std::string key, bool default_value)
|
||||
: FieldTrialParameterInterface(key), value_(default_value) {}
|
||||
|
||||
bool FieldTrialFlag::Get() const {
|
||||
return value_;
|
||||
}
|
||||
|
||||
bool FieldTrialFlag::Parse(rtc::Optional<std::string> str_value) {
|
||||
// Only set the flag if there is no argument provided.
|
||||
if (str_value) {
|
||||
rtc::Optional<bool> opt_value = ParseTypedParameter<bool>(*str_value);
|
||||
if (!opt_value)
|
||||
return false;
|
||||
value_ = *opt_value;
|
||||
} else {
|
||||
value_ = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template class FieldTrialParameter<bool>;
|
||||
template class FieldTrialParameter<double>;
|
||||
template class FieldTrialParameter<int>;
|
||||
template class FieldTrialParameter<std::string>;
|
||||
|
||||
template class FieldTrialOptional<double>;
|
||||
template class FieldTrialOptional<int>;
|
||||
template class FieldTrialOptional<bool>;
|
||||
template class FieldTrialOptional<std::string>;
|
||||
|
||||
} // namespace webrtc
|
||||
146
rtc_base/experiments/field_trial_parser.h
Normal file
146
rtc_base/experiments/field_trial_parser.h
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright 2018 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 RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_
|
||||
#define RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
#include "api/optional.h"
|
||||
|
||||
// Field trial parser functionality. Provides funcitonality to parse field trial
|
||||
// argument strings in key:value format. Each parameter is described using
|
||||
// key:value, parameters are separated with a ,. Values can't include the comma
|
||||
// character, since there's no quote facility. For most types, white space is
|
||||
// ignored. Parameters are declared with a given type for which an
|
||||
// implementation of ParseTypedParameter should be provided. The
|
||||
// ParseTypedParameter implementation is given whatever is between the : and the
|
||||
// ,. FieldTrialOptional will use nullopt if the key is provided without :.
|
||||
|
||||
// Example string: "my_optional,my_int:3,my_string:hello"
|
||||
|
||||
// For further description of usage and behavior, see the examples in the unit
|
||||
// tests.
|
||||
|
||||
namespace webrtc {
|
||||
class FieldTrialParameterInterface {
|
||||
public:
|
||||
virtual ~FieldTrialParameterInterface();
|
||||
|
||||
protected:
|
||||
explicit FieldTrialParameterInterface(std::string key);
|
||||
friend void ParseFieldTrial(
|
||||
std::initializer_list<FieldTrialParameterInterface*> fields,
|
||||
std::string raw_string);
|
||||
virtual bool Parse(rtc::Optional<std::string> str_value) = 0;
|
||||
std::string Key() const;
|
||||
|
||||
private:
|
||||
const std::string key_;
|
||||
};
|
||||
|
||||
// ParseFieldTrial function parses the given string and fills the given fields
|
||||
// with extrated values if available.
|
||||
void ParseFieldTrial(
|
||||
std::initializer_list<FieldTrialParameterInterface*> fields,
|
||||
std::string raw_string);
|
||||
|
||||
// Specialize this in code file for custom types. Should return rtc::nullopt if
|
||||
// the given string cannot be properly parsed.
|
||||
template <typename T>
|
||||
rtc::Optional<T> ParseTypedParameter(std::string);
|
||||
|
||||
// This class uses the ParseTypedParameter function to implement a parameter
|
||||
// implementation with an enforced default value.
|
||||
template <typename T>
|
||||
class FieldTrialParameter : public FieldTrialParameterInterface {
|
||||
public:
|
||||
FieldTrialParameter(std::string key, T default_value)
|
||||
: FieldTrialParameterInterface(key), value_(default_value) {}
|
||||
T Get() const { return value_; }
|
||||
operator T() const { return Get(); }
|
||||
|
||||
protected:
|
||||
bool Parse(rtc::Optional<std::string> str_value) override {
|
||||
if (str_value) {
|
||||
rtc::Optional<T> value = ParseTypedParameter<T>(*str_value);
|
||||
if (value.has_value()) {
|
||||
value_ = value.value();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
T value_;
|
||||
};
|
||||
|
||||
// This class uses the ParseTypedParameter function to implement an optional
|
||||
// parameter implementation that can default to rtc::nullopt.
|
||||
template <typename T>
|
||||
class FieldTrialOptional : public FieldTrialParameterInterface {
|
||||
public:
|
||||
explicit FieldTrialOptional(std::string key)
|
||||
: FieldTrialParameterInterface(key) {}
|
||||
FieldTrialOptional(std::string key, rtc::Optional<T> default_value)
|
||||
: FieldTrialParameterInterface(key), value_(default_value) {}
|
||||
rtc::Optional<T> Get() const { return value_; }
|
||||
|
||||
protected:
|
||||
bool Parse(rtc::Optional<std::string> str_value) override {
|
||||
if (str_value) {
|
||||
rtc::Optional<T> value = ParseTypedParameter<T>(*str_value);
|
||||
if (!value.has_value())
|
||||
return false;
|
||||
value_ = value.value();
|
||||
} else {
|
||||
value_ = rtc::nullopt;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
rtc::Optional<T> value_;
|
||||
};
|
||||
|
||||
// Equivalent to a FieldTrialParameter<bool> in the case that both key and value
|
||||
// are present. If key is missing, evaluates to false. If key is present, but no
|
||||
// explicit value is provided, the flag evaluates to true.
|
||||
class FieldTrialFlag : public FieldTrialParameterInterface {
|
||||
public:
|
||||
explicit FieldTrialFlag(std::string key);
|
||||
FieldTrialFlag(std::string key, bool default_value);
|
||||
bool Get() const;
|
||||
|
||||
protected:
|
||||
bool Parse(rtc::Optional<std::string> str_value) override;
|
||||
|
||||
private:
|
||||
bool value_;
|
||||
};
|
||||
|
||||
// Accepts true, false, else parsed with sscanf %i, true if != 0.
|
||||
extern template class FieldTrialParameter<bool>;
|
||||
// Interpreted using sscanf %lf.
|
||||
extern template class FieldTrialParameter<double>;
|
||||
// Interpreted using sscanf %i.
|
||||
extern template class FieldTrialParameter<int>;
|
||||
// Using the given value as is.
|
||||
extern template class FieldTrialParameter<std::string>;
|
||||
|
||||
extern template class FieldTrialOptional<double>;
|
||||
extern template class FieldTrialOptional<int>;
|
||||
extern template class FieldTrialOptional<bool>;
|
||||
extern template class FieldTrialOptional<std::string>;
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_
|
||||
131
rtc_base/experiments/field_trial_parser_unittest.cc
Normal file
131
rtc_base/experiments/field_trial_parser_unittest.cc
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2018 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_base/experiments/field_trial_parser.h"
|
||||
#include "rtc_base/gunit.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
#include "test/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
const char kDummyExperiment[] = "WebRTC-DummyExperiment";
|
||||
|
||||
struct DummyExperiment {
|
||||
FieldTrialFlag enabled = FieldTrialFlag("Enabled");
|
||||
FieldTrialParameter<double> factor = FieldTrialParameter<double>("f", 0.5);
|
||||
FieldTrialParameter<int> retries = FieldTrialParameter<int>("r", 5);
|
||||
FieldTrialParameter<bool> ping = FieldTrialParameter<bool>("p", 0);
|
||||
FieldTrialParameter<std::string> hash =
|
||||
FieldTrialParameter<std::string>("h", "a80");
|
||||
|
||||
explicit DummyExperiment(std::string field_trial) {
|
||||
ParseFieldTrial({&enabled, &factor, &retries, &ping, &hash}, field_trial);
|
||||
}
|
||||
DummyExperiment() {
|
||||
std::string trial_string = field_trial::FindFullName(kDummyExperiment);
|
||||
ParseFieldTrial({&enabled, &factor, &retries, &ping, &hash}, trial_string);
|
||||
}
|
||||
};
|
||||
|
||||
enum class CustomEnum {
|
||||
kDefault,
|
||||
kRed,
|
||||
kBlue,
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// Providing a custom parser for an enum can make the trial string easier to
|
||||
// read, but also adds more code and makes the string more verbose.
|
||||
template <>
|
||||
rtc::Optional<CustomEnum> ParseTypedParameter<CustomEnum>(std::string str) {
|
||||
if (str == "default")
|
||||
return CustomEnum::kDefault;
|
||||
else if (str == "red")
|
||||
return CustomEnum::kRed;
|
||||
else if (str == "blue")
|
||||
return CustomEnum::kBlue;
|
||||
return rtc::nullopt;
|
||||
}
|
||||
|
||||
TEST(FieldTrialParserTest, ParsesValidParameters) {
|
||||
DummyExperiment exp("Enabled,f:-1.7,r:2,p:1,h:x7c");
|
||||
EXPECT_TRUE(exp.enabled.Get());
|
||||
EXPECT_EQ(exp.factor.Get(), -1.7);
|
||||
EXPECT_EQ(exp.retries.Get(), 2);
|
||||
EXPECT_EQ(exp.ping.Get(), true);
|
||||
EXPECT_EQ(exp.hash.Get(), "x7c");
|
||||
}
|
||||
TEST(FieldTrialParserTest, InitializesFromFieldTrial) {
|
||||
test::ScopedFieldTrials field_trials(
|
||||
"WebRTC-OtherExperiment/Disabled/"
|
||||
"WebRTC-DummyExperiment/Enabled,f:-1.7,r:2,p:1,h:x7c/"
|
||||
"WebRTC-AnotherExperiment/Enabled,f:-3.1,otherstuff:beef/");
|
||||
DummyExperiment exp;
|
||||
EXPECT_TRUE(exp.enabled.Get());
|
||||
EXPECT_EQ(exp.factor.Get(), -1.7);
|
||||
EXPECT_EQ(exp.retries.Get(), 2);
|
||||
EXPECT_EQ(exp.ping.Get(), true);
|
||||
EXPECT_EQ(exp.hash.Get(), "x7c");
|
||||
}
|
||||
TEST(FieldTrialParserTest, UsesDefaults) {
|
||||
DummyExperiment exp("");
|
||||
EXPECT_FALSE(exp.enabled.Get());
|
||||
EXPECT_EQ(exp.factor.Get(), 0.5);
|
||||
EXPECT_EQ(exp.retries.Get(), 5);
|
||||
EXPECT_EQ(exp.ping.Get(), false);
|
||||
EXPECT_EQ(exp.hash.Get(), "a80");
|
||||
}
|
||||
TEST(FieldTrialParserTest, CanHandleMixedInput) {
|
||||
DummyExperiment exp("p:true,h:,Enabled");
|
||||
EXPECT_TRUE(exp.enabled.Get());
|
||||
EXPECT_EQ(exp.factor.Get(), 0.5);
|
||||
EXPECT_EQ(exp.retries.Get(), 5);
|
||||
EXPECT_EQ(exp.ping.Get(), true);
|
||||
EXPECT_EQ(exp.hash.Get(), "");
|
||||
}
|
||||
TEST(FieldTrialParserTest, IgnoresNewKey) {
|
||||
DummyExperiment exp("Disabled,r:-11,foo");
|
||||
EXPECT_FALSE(exp.enabled.Get());
|
||||
EXPECT_EQ(exp.factor.Get(), 0.5);
|
||||
EXPECT_EQ(exp.retries.Get(), -11);
|
||||
}
|
||||
TEST(FieldTrialParserTest, IgnoresInvalid) {
|
||||
DummyExperiment exp("Enabled,f,p:,r:%,,:foo,h");
|
||||
EXPECT_TRUE(exp.enabled.Get());
|
||||
EXPECT_EQ(exp.factor.Get(), 0.5);
|
||||
EXPECT_EQ(exp.retries.Get(), 5);
|
||||
EXPECT_EQ(exp.ping.Get(), false);
|
||||
EXPECT_EQ(exp.hash.Get(), "a80");
|
||||
}
|
||||
TEST(FieldTrialParserTest, ParsesOptionalParameters) {
|
||||
FieldTrialOptional<int> max_count("c", rtc::nullopt);
|
||||
ParseFieldTrial({&max_count}, "");
|
||||
EXPECT_FALSE(max_count.Get().has_value());
|
||||
ParseFieldTrial({&max_count}, "c:10");
|
||||
EXPECT_EQ(max_count.Get().value(), 10);
|
||||
ParseFieldTrial({&max_count}, "c");
|
||||
EXPECT_FALSE(max_count.Get().has_value());
|
||||
ParseFieldTrial({&max_count}, "c:20");
|
||||
EXPECT_EQ(max_count.Get().value(), 20);
|
||||
ParseFieldTrial({&max_count}, "c:");
|
||||
EXPECT_EQ(max_count.Get().value(), 20);
|
||||
FieldTrialOptional<std::string> optional_string("s", std::string("ab"));
|
||||
ParseFieldTrial({&optional_string}, "s:");
|
||||
EXPECT_EQ(optional_string.Get().value(), "");
|
||||
ParseFieldTrial({&optional_string}, "s");
|
||||
EXPECT_FALSE(optional_string.Get().has_value());
|
||||
}
|
||||
TEST(FieldTrialParserTest, ParsesCustomEnumParameter) {
|
||||
FieldTrialParameter<CustomEnum> my_enum("e", CustomEnum::kDefault);
|
||||
ParseFieldTrial({&my_enum}, "");
|
||||
EXPECT_EQ(my_enum.Get(), CustomEnum::kDefault);
|
||||
ParseFieldTrial({&my_enum}, "e:red");
|
||||
EXPECT_EQ(my_enum.Get(), CustomEnum::kRed);
|
||||
}
|
||||
} // namespace webrtc
|
||||
92
rtc_base/experiments/field_trial_units.cc
Normal file
92
rtc_base/experiments/field_trial_units.cc
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2018 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_base/experiments/field_trial_units.h"
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include "api/optional.h"
|
||||
|
||||
// Large enough to fit "seconds", the longest supported unit name.
|
||||
#define RTC_TRIAL_UNIT_LENGTH_STR "7"
|
||||
#define RTC_TRIAL_UNIT_SIZE 8
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
struct ValueWithUnit {
|
||||
double value;
|
||||
std::string unit;
|
||||
};
|
||||
|
||||
rtc::Optional<ValueWithUnit> ParseValueWithUnit(std::string str) {
|
||||
if (str == "inf") {
|
||||
return ValueWithUnit{std::numeric_limits<double>::infinity(), ""};
|
||||
} else if (str == "-inf") {
|
||||
return ValueWithUnit{-std::numeric_limits<double>::infinity(), ""};
|
||||
} else {
|
||||
double double_val;
|
||||
char unit_char[RTC_TRIAL_UNIT_SIZE];
|
||||
unit_char[0] = 0;
|
||||
if (sscanf(str.c_str(), "%lf%" RTC_TRIAL_UNIT_LENGTH_STR "s", &double_val,
|
||||
unit_char) >= 1) {
|
||||
return ValueWithUnit{double_val, unit_char};
|
||||
}
|
||||
}
|
||||
return rtc::nullopt;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
template <>
|
||||
rtc::Optional<DataRate> ParseTypedParameter<DataRate>(std::string str) {
|
||||
rtc::Optional<ValueWithUnit> result = ParseValueWithUnit(str);
|
||||
if (result) {
|
||||
if (result->unit.empty() || result->unit == "kbps") {
|
||||
return DataRate::kbps(result->value);
|
||||
} else if (result->unit == "bps") {
|
||||
return DataRate::bps(result->value);
|
||||
}
|
||||
}
|
||||
return rtc::nullopt;
|
||||
}
|
||||
|
||||
template <>
|
||||
rtc::Optional<DataSize> ParseTypedParameter<DataSize>(std::string str) {
|
||||
rtc::Optional<ValueWithUnit> result = ParseValueWithUnit(str);
|
||||
if (result) {
|
||||
if (result->unit.empty() || result->unit == "bytes")
|
||||
return DataSize::bytes(result->value);
|
||||
}
|
||||
return rtc::nullopt;
|
||||
}
|
||||
|
||||
template <>
|
||||
rtc::Optional<TimeDelta> ParseTypedParameter<TimeDelta>(std::string str) {
|
||||
rtc::Optional<ValueWithUnit> result = ParseValueWithUnit(str);
|
||||
if (result) {
|
||||
if (result->unit == "s" || result->unit == "seconds") {
|
||||
return TimeDelta::seconds(result->value);
|
||||
} else if (result->unit == "us") {
|
||||
return TimeDelta::us(result->value);
|
||||
} else if (result->unit.empty() || result->unit == "ms") {
|
||||
return TimeDelta::ms(result->value);
|
||||
}
|
||||
}
|
||||
return rtc::nullopt;
|
||||
}
|
||||
|
||||
template class FieldTrialParameter<DataRate>;
|
||||
template class FieldTrialParameter<DataSize>;
|
||||
template class FieldTrialParameter<TimeDelta>;
|
||||
|
||||
template class FieldTrialOptional<DataRate>;
|
||||
template class FieldTrialOptional<DataSize>;
|
||||
template class FieldTrialOptional<TimeDelta>;
|
||||
} // namespace webrtc
|
||||
29
rtc_base/experiments/field_trial_units.h
Normal file
29
rtc_base/experiments/field_trial_units.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2018 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 RTC_BASE_EXPERIMENTS_FIELD_TRIAL_UNITS_H_
|
||||
#define RTC_BASE_EXPERIMENTS_FIELD_TRIAL_UNITS_H_
|
||||
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
|
||||
#include "api/units/data_rate.h"
|
||||
#include "api/units/data_size.h"
|
||||
#include "api/units/time_delta.h"
|
||||
|
||||
namespace webrtc {
|
||||
extern template class FieldTrialParameter<DataRate>;
|
||||
extern template class FieldTrialParameter<DataSize>;
|
||||
extern template class FieldTrialParameter<TimeDelta>;
|
||||
|
||||
extern template class FieldTrialOptional<DataRate>;
|
||||
extern template class FieldTrialOptional<DataSize>;
|
||||
extern template class FieldTrialOptional<TimeDelta>;
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_FIELD_TRIAL_UNITS_H_
|
||||
62
rtc_base/experiments/field_trial_units_unittest.cc
Normal file
62
rtc_base/experiments/field_trial_units_unittest.cc
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2018 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 <string>
|
||||
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
#include "rtc_base/experiments/field_trial_units.h"
|
||||
#include "rtc_base/gunit.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
struct DummyExperiment {
|
||||
FieldTrialParameter<DataRate> target_rate =
|
||||
FieldTrialParameter<DataRate>("t", DataRate::kbps(100));
|
||||
FieldTrialParameter<TimeDelta> period =
|
||||
FieldTrialParameter<TimeDelta>("p", TimeDelta::ms(100));
|
||||
FieldTrialOptional<DataSize> max_buffer =
|
||||
FieldTrialOptional<DataSize>("b", rtc::nullopt);
|
||||
|
||||
explicit DummyExperiment(std::string field_trial) {
|
||||
ParseFieldTrial({&target_rate, &max_buffer, &period}, field_trial);
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST(FieldTrialParserUnitsTest, FallsBackToDefaults) {
|
||||
DummyExperiment exp("");
|
||||
EXPECT_EQ(exp.target_rate.Get(), DataRate::kbps(100));
|
||||
EXPECT_FALSE(exp.max_buffer.Get().has_value());
|
||||
EXPECT_EQ(exp.period.Get(), TimeDelta::ms(100));
|
||||
}
|
||||
TEST(FieldTrialParserUnitsTest, ParsesUnitParameters) {
|
||||
DummyExperiment exp("t:300kbps,b:5bytes,p:300ms");
|
||||
EXPECT_EQ(exp.target_rate.Get(), DataRate::kbps(300));
|
||||
EXPECT_EQ(*exp.max_buffer.Get(), DataSize::bytes(5));
|
||||
EXPECT_EQ(exp.period.Get(), TimeDelta::ms(300));
|
||||
}
|
||||
TEST(FieldTrialParserUnitsTest, ParsesDefaultUnitParameters) {
|
||||
DummyExperiment exp("t:300,b:5,p:300");
|
||||
EXPECT_EQ(exp.target_rate.Get(), DataRate::kbps(300));
|
||||
EXPECT_EQ(*exp.max_buffer.Get(), DataSize::bytes(5));
|
||||
EXPECT_EQ(exp.period.Get(), TimeDelta::ms(300));
|
||||
}
|
||||
TEST(FieldTrialParserUnitsTest, ParsesInfinityParameter) {
|
||||
DummyExperiment exp("t:inf,p:inf");
|
||||
EXPECT_EQ(exp.target_rate.Get(), DataRate::Infinity());
|
||||
EXPECT_EQ(exp.period.Get(), TimeDelta::PlusInfinity());
|
||||
}
|
||||
TEST(FieldTrialParserUnitsTest, ParsesOtherUnitParameters) {
|
||||
DummyExperiment exp("t:300bps,p:0.3 seconds,b:8 bytes");
|
||||
EXPECT_EQ(exp.target_rate.Get(), DataRate::bps(300));
|
||||
EXPECT_EQ(*exp.max_buffer.Get(), DataSize::bytes(8));
|
||||
EXPECT_EQ(exp.period.Get(), TimeDelta::ms(300));
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
Loading…
x
Reference in New Issue
Block a user