Using NetworkEmulationManager in Scenario tests.

Bug: webrtc:9510
Change-Id: Ib619526269c58f0c46c0c1f01ba6c0efa5f79ba5
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/132781
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Artem Titov <titovartem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27635}
This commit is contained in:
Sebastian Jansson 2019-04-15 21:10:00 +02:00 committed by Commit Bot
parent 884adca3a0
commit a4c22b9662
8 changed files with 43 additions and 212 deletions

View File

@ -33,35 +33,26 @@ SimulatedNetwork::Config CreateSimulationConfig(
}
} // namespace
void NullReceiver::OnPacketReceived(EmulatedIpPacket packet) {}
SimulationNode::SimulationNode(NetworkSimulationConfig config,
SimulatedNetwork* behavior,
EmulatedNetworkNode* network_node)
: config_(config), simulation_(behavior), network_node_(network_node) {}
ActionReceiver::ActionReceiver(std::function<void()> action)
: action_(action) {}
void ActionReceiver::OnPacketReceived(EmulatedIpPacket packet) {
action_();
}
std::unique_ptr<SimulationNode> SimulationNode::Create(
Clock* clock,
rtc::TaskQueue* task_queue,
std::unique_ptr<SimulatedNetwork> SimulationNode::CreateBehavior(
NetworkSimulationConfig config) {
SimulatedNetwork::Config sim_config = CreateSimulationConfig(config);
auto network = absl::make_unique<SimulatedNetwork>(sim_config);
SimulatedNetwork* simulation_ptr = network.get();
return std::unique_ptr<SimulationNode>(new SimulationNode(
clock, task_queue, config, std::move(network), simulation_ptr));
return absl::make_unique<SimulatedNetwork>(sim_config);
}
void SimulationNode::UpdateConfig(
std::function<void(NetworkSimulationConfig*)> modifier) {
modifier(&config_);
SimulatedNetwork::Config sim_config = CreateSimulationConfig(config_);
simulated_network_->SetConfig(sim_config);
simulation_->SetConfig(sim_config);
}
void SimulationNode::PauseTransmissionUntil(Timestamp until) {
simulated_network_->PauseTransmissionUntil(until.us());
simulation_->PauseTransmissionUntil(until.us());
}
ColumnPrinter SimulationNode::ConfigPrinter() const {
@ -73,15 +64,6 @@ ColumnPrinter SimulationNode::ConfigPrinter() const {
});
}
SimulationNode::SimulationNode(
Clock* clock,
rtc::TaskQueue* task_queue,
NetworkSimulationConfig config,
std::unique_ptr<NetworkBehaviorInterface> behavior,
SimulatedNetwork* simulation)
: EmulatedNetworkNode(clock, task_queue, std::move(behavior)),
simulated_network_(simulation),
config_(config) {}
NetworkNodeTransport::NetworkNodeTransport(Clock* sender_clock,
Call* sender_call)
@ -162,57 +144,5 @@ void NetworkNodeTransport::Disconnect() {
send_net_ = nullptr;
}
CrossTrafficSource::CrossTrafficSource(EmulatedNetworkReceiverInterface* target,
rtc::IPAddress receiver_ip,
CrossTrafficConfig config)
: target_(target),
receiver_address_(receiver_ip, 0),
config_(config),
random_(config.random_seed) {}
CrossTrafficSource::~CrossTrafficSource() = default;
DataRate CrossTrafficSource::TrafficRate() const {
return config_.peak_rate * intensity_;
}
void CrossTrafficSource::Process(Timestamp at_time, TimeDelta delta) {
time_since_update_ += delta;
if (config_.mode == CrossTrafficConfig::Mode::kRandomWalk) {
if (time_since_update_ >= config_.random_walk.update_interval) {
intensity_ += random_.Gaussian(config_.random_walk.bias,
config_.random_walk.variance) *
time_since_update_.seconds<double>();
intensity_ = rtc::SafeClamp(intensity_, 0.0, 1.0);
time_since_update_ = TimeDelta::Zero();
}
} else if (config_.mode == CrossTrafficConfig::Mode::kPulsedPeaks) {
if (intensity_ == 0 && time_since_update_ >= config_.pulsed.hold_duration) {
intensity_ = 1;
time_since_update_ = TimeDelta::Zero();
} else if (intensity_ == 1 &&
time_since_update_ >= config_.pulsed.send_duration) {
intensity_ = 0;
time_since_update_ = TimeDelta::Zero();
}
}
pending_size_ += TrafficRate() * delta;
if (pending_size_ > config_.min_packet_size) {
target_->OnPacketReceived(EmulatedIpPacket(
/*from=*/rtc::SocketAddress(), receiver_address_,
rtc::CopyOnWriteBuffer(pending_size_.bytes()), at_time));
pending_size_ = DataSize::Zero();
}
}
ColumnPrinter CrossTrafficSource::StatsPrinter() {
return ColumnPrinter::Lambda("cross_traffic_rate",
[this](rtc::SimpleStringBuilder& sb) {
sb.AppendFormat("%.0lf",
TrafficRate().bps() / 8.0);
},
32);
}
} // namespace test
} // namespace webrtc

View File

@ -30,42 +30,23 @@
namespace webrtc {
namespace test {
class NullReceiver : public EmulatedNetworkReceiverInterface {
class SimulationNode {
public:
void OnPacketReceived(EmulatedIpPacket packet) override;
};
class ActionReceiver : public EmulatedNetworkReceiverInterface {
public:
explicit ActionReceiver(std::function<void()> action);
virtual ~ActionReceiver() = default;
SimulationNode(NetworkSimulationConfig config,
SimulatedNetwork* behavior,
EmulatedNetworkNode* network_node);
static std::unique_ptr<SimulatedNetwork> CreateBehavior(
NetworkSimulationConfig config);
void OnPacketReceived(EmulatedIpPacket packet) override;
private:
std::function<void()> action_;
};
class SimulationNode : public EmulatedNetworkNode {
public:
void UpdateConfig(std::function<void(NetworkSimulationConfig*)> modifier);
void PauseTransmissionUntil(Timestamp until);
ColumnPrinter ConfigPrinter() const;
EmulatedNetworkNode* node() { return this; }
EmulatedNetworkNode* node() { return network_node_; }
private:
friend class Scenario;
SimulationNode(Clock* clock,
rtc::TaskQueue* task_queue,
NetworkSimulationConfig config,
std::unique_ptr<NetworkBehaviorInterface> behavior,
SimulatedNetwork* simulation);
static std::unique_ptr<SimulationNode> Create(Clock* clock,
rtc::TaskQueue* task_queue,
NetworkSimulationConfig config);
SimulatedNetwork* const simulated_network_;
NetworkSimulationConfig config_;
SimulatedNetwork* const simulation_;
EmulatedNetworkNode* const network_node_;
};
class NetworkNodeTransport : public Transport {
@ -99,31 +80,6 @@ class NetworkNodeTransport : public Transport {
DataSize packet_overhead_ RTC_GUARDED_BY(crit_sect_) = DataSize::Zero();
rtc::NetworkRoute current_network_route_ RTC_GUARDED_BY(crit_sect_);
};
// CrossTrafficSource is created by a Scenario and generates cross traffic. It
// provides methods to access and print internal state.
class CrossTrafficSource {
public:
DataRate TrafficRate() const;
ColumnPrinter StatsPrinter();
~CrossTrafficSource();
private:
friend class Scenario;
CrossTrafficSource(EmulatedNetworkReceiverInterface* target,
rtc::IPAddress receiver_ip,
CrossTrafficConfig config);
void Process(Timestamp at_time, TimeDelta delta);
EmulatedNetworkReceiverInterface* const target_;
const rtc::SocketAddress receiver_address_;
CrossTrafficConfig config_;
webrtc::Random random_;
TimeDelta time_since_update_ = TimeDelta::Zero();
double intensity_ = 0;
DataSize pending_size_ = DataSize::Zero();
};
} // namespace test
} // namespace webrtc
#endif // TEST_SCENARIO_NETWORK_NODE_H_

View File

@ -73,6 +73,7 @@ Scenario::Scenario(
clock_(time_controller_->GetClock()),
audio_decoder_factory_(CreateBuiltinAudioDecoderFactory()),
audio_encoder_factory_(CreateBuiltinAudioEncoderFactory()),
network_manager_(time_controller_.get()),
task_queue_(time_controller_->GetTaskQueueFactory()->CreateTaskQueue(
"Scenario",
TaskQueueFactory::Priority::NORMAL)) {}
@ -192,6 +193,7 @@ SimulatedTimeClient* Scenario::CreateSimulatedTimeClient(
simulated_time_clients_.emplace_back(client);
return client;
}
EmulatedNetworkNode* Scenario::CreateSimulationNode(
std::function<void(NetworkSimulationConfig*)> config_modifier) {
NetworkSimulationConfig config;
@ -201,7 +203,8 @@ EmulatedNetworkNode* Scenario::CreateSimulationNode(
EmulatedNetworkNode* Scenario::CreateSimulationNode(
NetworkSimulationConfig config) {
return CreateMutableSimulationNode(config);
return network_manager_.CreateEmulatedNode(
SimulationNode::CreateBehavior(config));
}
SimulationNode* Scenario::CreateMutableSimulationNode(
@ -213,55 +216,29 @@ SimulationNode* Scenario::CreateMutableSimulationNode(
SimulationNode* Scenario::CreateMutableSimulationNode(
NetworkSimulationConfig config) {
auto network_node = SimulationNode::Create(clock_, &task_queue_, config);
SimulationNode* sim_node = network_node.get();
network_nodes_.emplace_back(std::move(network_node));
return sim_node;
std::unique_ptr<SimulatedNetwork> behavior =
SimulationNode::CreateBehavior(config);
SimulatedNetwork* behavior_ptr = behavior.get();
auto* emulated_node =
network_manager_.CreateEmulatedNode(std::move(behavior));
simulation_nodes_.emplace_back(
new SimulationNode(config, behavior_ptr, emulated_node));
return simulation_nodes_.back().get();
}
void Scenario::TriggerPacketBurst(std::vector<EmulatedNetworkNode*> over_nodes,
size_t num_packets,
size_t packet_size) {
rtc::IPAddress route_ip(next_route_id_++);
EmulatedNetworkNode::CreateRoute(route_ip, over_nodes, &null_receiver_);
for (size_t i = 0; i < num_packets; ++i)
over_nodes[0]->OnPacketReceived(EmulatedIpPacket(
/*from=*/rtc::SocketAddress(), /*to=*/rtc::SocketAddress(route_ip, 0),
rtc::CopyOnWriteBuffer(packet_size), Now()));
network_manager_.CreateTrafficRoute(over_nodes)
->TriggerPacketBurst(num_packets, packet_size);
}
void Scenario::NetworkDelayedAction(
std::vector<EmulatedNetworkNode*> over_nodes,
size_t packet_size,
std::function<void()> action) {
rtc::IPAddress route_ip(next_route_id_++);
action_receivers_.emplace_back(new ActionReceiver(action));
EmulatedNetworkNode::CreateRoute(route_ip, over_nodes,
action_receivers_.back().get());
over_nodes[0]->OnPacketReceived(EmulatedIpPacket(
/*from=*/rtc::SocketAddress(), /*to=*/rtc::SocketAddress(route_ip, 0),
rtc::CopyOnWriteBuffer(packet_size), Now()));
}
CrossTrafficSource* Scenario::CreateCrossTraffic(
std::vector<EmulatedNetworkNode*> over_nodes,
std::function<void(CrossTrafficConfig*)> config_modifier) {
CrossTrafficConfig cross_config;
config_modifier(&cross_config);
return CreateCrossTraffic(over_nodes, cross_config);
}
CrossTrafficSource* Scenario::CreateCrossTraffic(
std::vector<EmulatedNetworkNode*> over_nodes,
CrossTrafficConfig config) {
rtc::IPAddress route_ip(next_route_id_++);
cross_traffic_sources_.emplace_back(
new CrossTrafficSource(over_nodes.front(), route_ip, config));
CrossTrafficSource* node = cross_traffic_sources_.back().get();
EmulatedNetworkNode::CreateRoute(route_ip, over_nodes, &null_receiver_);
Every(config.min_packet_interval,
[this, node](TimeDelta delta) { node->Process(Now(), delta); });
return node;
network_manager_.CreateTrafficRoute(over_nodes)
->NetworkDelayedAction(packet_size, action);
}
VideoStreamPair* Scenario::CreateVideoStream(

View File

@ -23,6 +23,7 @@
#include "test/scenario/audio_stream.h"
#include "test/scenario/call_client.h"
#include "test/scenario/column_printer.h"
#include "test/scenario/network/network_emulation_manager.h"
#include "test/scenario/network_node.h"
#include "test/scenario/scenario_config.h"
#include "test/scenario/simulated_time.h"
@ -48,6 +49,7 @@ class Scenario {
bool real_time);
RTC_DISALLOW_COPY_AND_ASSIGN(Scenario);
~Scenario();
NetworkEmulationManagerImpl* net() { return &network_manager_; }
EmulatedNetworkNode* CreateSimulationNode(NetworkSimulationConfig config);
EmulatedNetworkNode* CreateSimulationNode(
@ -102,13 +104,6 @@ class Scenario {
std::pair<CallClient*, CallClient*> clients,
AudioStreamConfig config);
CrossTrafficSource* CreateCrossTraffic(
std::vector<EmulatedNetworkNode*> over_nodes,
std::function<void(CrossTrafficConfig*)> config_modifier);
CrossTrafficSource* CreateCrossTraffic(
std::vector<EmulatedNetworkNode*> over_nodes,
CrossTrafficConfig config);
// Runs the provided function with a fixed interval. For real time tests,
// |function| starts being called after |interval| from the call to Every().
void Every(TimeDelta interval, std::function<void(TimeDelta)> function);
@ -168,21 +163,16 @@ class Scenario {
private:
TimeDelta TimeUntilTarget(TimeDelta target_time_offset);
NullReceiver null_receiver_;
const std::unique_ptr<LogWriterFactoryInterface> log_writer_factory_;
std::unique_ptr<TimeController> time_controller_;
Clock* clock_;
std::vector<std::unique_ptr<CallClient>> clients_;
std::vector<std::unique_ptr<CallClientPair>> client_pairs_;
std::vector<std::unique_ptr<EmulatedNetworkNode>> network_nodes_;
std::vector<std::unique_ptr<CrossTrafficSource>> cross_traffic_sources_;
std::vector<std::unique_ptr<VideoStreamPair>> video_streams_;
std::vector<std::unique_ptr<AudioStreamPair>> audio_streams_;
std::vector<std::unique_ptr<SimulatedTimeClient>> simulated_time_clients_;
std::vector<std::unique_ptr<ActionReceiver>> action_receivers_;
std::vector<std::unique_ptr<SimulationNode>> simulation_nodes_;
std::vector<std::unique_ptr<StatesPrinter>> printers_;
int64_t next_route_id_ = 40000;
@ -190,6 +180,7 @@ class Scenario {
rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory_;
Timestamp start_time_ = Timestamp::PlusInfinity();
NetworkEmulationManagerImpl network_manager_;
// Defined last so it's destroyed first.
rtc::TaskQueue task_queue_;
};

View File

@ -43,9 +43,5 @@ AudioStreamConfig::Stream::Stream() = default;
AudioStreamConfig::Stream::Stream(const AudioStreamConfig::Stream&) = default;
AudioStreamConfig::Stream::~Stream() = default;
CrossTrafficConfig::CrossTrafficConfig() = default;
CrossTrafficConfig::CrossTrafficConfig(const CrossTrafficConfig&) = default;
CrossTrafficConfig::~CrossTrafficConfig() = default;
} // namespace test
} // namespace webrtc

View File

@ -237,26 +237,6 @@ struct NetworkSimulationConfig {
bool codel_active_queue_management = false;
DataSize packet_overhead = DataSize::Zero();
};
struct CrossTrafficConfig {
CrossTrafficConfig();
CrossTrafficConfig(const CrossTrafficConfig&);
~CrossTrafficConfig();
enum Mode { kRandomWalk, kPulsedPeaks } mode = kRandomWalk;
int random_seed = 1;
DataRate peak_rate = DataRate::kbps(100);
DataSize min_packet_size = DataSize::bytes(200);
TimeDelta min_packet_interval = TimeDelta::ms(1);
struct RandomWalk {
TimeDelta update_interval = TimeDelta::ms(200);
double variance = 0.6;
double bias = -0.1;
} random_walk;
struct PulsedPeaks {
TimeDelta send_duration = TimeDelta::ms(100);
TimeDelta hold_duration = TimeDelta::ms(2000);
} pulsed;
};
} // namespace test
} // namespace webrtc

View File

@ -191,11 +191,11 @@ TEST_P(BbrScenarioTest, ReceivesVideo) {
}
});
}
CrossTrafficConfig cross_config;
RandomWalkConfig cross_config;
cross_config.peak_rate = conf_.scenario.cross_traffic;
cross_config.random_seed = conf_.scenario.random_seed;
CrossTrafficSource* cross_traffic =
s.CreateCrossTraffic({send_net}, cross_config);
auto* cross_traffic = s.net()->CreateRandomWalkCrossTraffic(
s.net()->CreateTrafficRoute({send_net->node()}), cross_config);
s.CreatePrinter("send.stats.txt", TimeDelta::ms(100),
{alice->StatsPrinter(), alice_video->send()->StatsPrinter(),

View File

@ -40,8 +40,9 @@ TEST(ScenarioTest, StartsAndStopsWithoutErrors) {
s.CreateAudioStream(route->forward(), audio_stream_config);
s.CreateAudioStream(route->reverse(), audio_stream_config);
CrossTrafficConfig cross_traffic_config;
s.CreateCrossTraffic({alice_net}, cross_traffic_config);
RandomWalkConfig cross_traffic_config;
s.net()->CreateRandomWalkCrossTraffic(
s.net()->CreateTrafficRoute({alice_net}), cross_traffic_config);
s.NetworkDelayedAction({alice_net, bob_net}, 100,
[&packet_received] { packet_received = true; });