Skip to content

Commit b239070

Browse files
authored
support to change loss dynamically in gym (#13)
* support change loss rate dynamically in gym and make a test script * bugfix : error when handling trace with no loss and update related test script * remove hardcode in the test script about loss rate * optimized the test scripts about loss rate 1. support to set run_times to control the times that the trace is run 2. support to set bandwidth_bps to control send rate 3. reduced error rate indicators
1 parent cc842e7 commit b239070

File tree

9 files changed

+276
-0
lines changed

9 files changed

+276
-0
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"type": "video",
3+
"downlink": {},
4+
"uplink": {
5+
"trace_pattern": [
6+
{
7+
"duration": 200,
8+
"capacity": 1000,
9+
"loss": 0,
10+
"rtt": 0,
11+
"jitter": 0,
12+
"time": 0.0
13+
}
14+
]
15+
}
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"type": "video",
3+
"downlink": {},
4+
"uplink": {
5+
"trace_pattern": [
6+
{
7+
"duration": 200,
8+
"capacity": 1000,
9+
"loss": 0.1,
10+
"rtt": 0,
11+
"jitter": 0,
12+
"time": 0.0
13+
}
14+
]
15+
}
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"type": "video",
3+
"downlink": {},
4+
"uplink": {
5+
"trace_pattern": [
6+
{
7+
"duration": 200,
8+
"capacity": 1000,
9+
"loss": 0.5,
10+
"rtt": 0,
11+
"jitter": 0,
12+
"time": 0.0
13+
}
14+
]
15+
}
16+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"type": "video",
3+
"downlink": {},
4+
"uplink": {
5+
"trace_pattern": [
6+
{
7+
"duration": 500,
8+
"capacity": 1000,
9+
"loss": 0,
10+
"rtt": 0,
11+
"jitter": 0,
12+
"time": 0.0
13+
},
14+
{
15+
"duration": 500,
16+
"capacity": 1000,
17+
"loss": 0.2,
18+
"rtt": 0,
19+
"jitter": 0,
20+
"time": 0.0
21+
}
22+
]
23+
}
24+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"type": "video",
3+
"downlink": {},
4+
"uplink": {
5+
"trace_pattern": [
6+
{
7+
"duration": 500,
8+
"capacity": 1000,
9+
"loss": 0,
10+
"rtt": 0,
11+
"jitter": 0,
12+
"time": 0.0
13+
},
14+
{
15+
"duration": 500,
16+
"capacity": 1000,
17+
"loss": 0.2,
18+
"rtt": 0,
19+
"jitter": 0,
20+
"time": 0.0
21+
},
22+
{
23+
"duration": 500,
24+
"capacity": 1000,
25+
"loss": 0.1,
26+
"rtt": 0,
27+
"jitter": 0,
28+
"time": 0.0
29+
}
30+
]
31+
}
32+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"type": "video",
3+
"downlink": {},
4+
"uplink": {
5+
"trace_pattern": [
6+
{
7+
"duration": 500,
8+
"capacity": 1000,
9+
"loss": 0,
10+
"rtt": 0,
11+
"jitter": 0,
12+
"time": 0.0
13+
},
14+
{
15+
"duration": 500,
16+
"capacity": 1000,
17+
"loss": 0.2,
18+
"rtt": 0,
19+
"jitter": 0,
20+
"time": 0.0
21+
},
22+
{
23+
"duration": 500,
24+
"capacity": 1000,
25+
"loss": 0.5,
26+
"rtt": 0,
27+
"jitter": 0,
28+
"time": 0.0
29+
},
30+
{
31+
"duration": 500,
32+
"capacity": 1000,
33+
"loss": 0.2,
34+
"rtt": 0,
35+
"jitter": 0,
36+
"time": 0.0
37+
}
38+
]
39+
}
40+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
4+
from alphartc_gym import gym
5+
import os, json
6+
7+
8+
ERROR_STATIC = 0.05
9+
ERROR_DYNAMICAL = 0.07
10+
11+
12+
def get_gym_stats(trace_path, duration_time_ms=3000, bandwidth_bps=1000000):
13+
total_stats = []
14+
g = gym.Gym()
15+
g.reset(trace_path=trace_path, duration_time_ms=duration_time_ms)
16+
17+
while True:
18+
stats, done = g.step(bandwidth_bps)
19+
if not done:
20+
total_stats += stats
21+
else:
22+
return total_stats
23+
24+
25+
def get_info_from_trace(trace_file):
26+
with open(trace_file, 'r') as f:
27+
return json.loads(f.read())
28+
29+
30+
def get_abs_path_by_name(trace_name):
31+
trace_path = os.path.join(
32+
os.path.dirname(__file__),
33+
"data/loss",
34+
trace_name)
35+
return trace_path
36+
37+
38+
def single_loss_available(trace_path):
39+
total_stats = get_gym_stats(trace_path)
40+
assert (total_stats)
41+
42+
for stats in total_stats:
43+
assert (isinstance(stats, dict))
44+
45+
46+
def single_loss_persistence(trace_path, run_times=1, bandwidth_bps=1000000):
47+
# get information from trace
48+
trace_data = get_info_from_trace(trace_path)
49+
trace_pattern = trace_data["uplink"]["trace_pattern"]
50+
predict_error_rate = trace_pattern[0]["loss"]
51+
duration_time_ms = sum([item["duration"] for item in trace_pattern]) * run_times
52+
53+
total_stats = get_gym_stats(trace_path, duration_time_ms=duration_time_ms, bandwidth_bps=bandwidth_bps)
54+
assert (total_stats)
55+
56+
mp_src_seq = {}
57+
now_total, now_loss = 0, 0
58+
for i in range(len(total_stats)):
59+
ssrc = total_stats[i]["ssrc"]
60+
if ssrc not in mp_src_seq:
61+
mp_src_seq[ssrc] = 0
62+
# calculate loss packet
63+
if mp_src_seq[ssrc] + 1 < total_stats[i]["sequence_number"]:
64+
while mp_src_seq[ssrc] + 1 < total_stats[i]["sequence_number"]:
65+
now_total += 1
66+
now_loss += 1
67+
mp_src_seq[ssrc] += 1
68+
now_total += 1
69+
mp_src_seq[ssrc] += 1
70+
assert abs(now_loss / now_total - predict_error_rate) <= predict_error_rate * ERROR_STATIC
71+
72+
73+
def single_loss_dynamically(trace_path, run_times=1, bandwidth_bps=1000000):
74+
# get information from trace
75+
trace_data = get_info_from_trace(trace_path)
76+
trace_pattern = trace_data["uplink"]["trace_pattern"]
77+
trace_duration_time_ms = sum([item["duration"] for item in trace_pattern])
78+
predict_error_rate = sum([item["loss"] * (item["duration"] / trace_duration_time_ms) for item in trace_pattern])
79+
duration_time_ms = sum([item["duration"] for item in trace_pattern]) * run_times
80+
81+
total_stats = get_gym_stats(trace_path, duration_time_ms=duration_time_ms, bandwidth_bps=bandwidth_bps)
82+
assert (total_stats)
83+
84+
mp_src_seq = {}
85+
now_total, now_loss = 0, 0
86+
for i in range(len(total_stats)):
87+
ssrc = total_stats[i]["ssrc"]
88+
if ssrc not in mp_src_seq:
89+
mp_src_seq[ssrc] = 0
90+
# calculate loss packet
91+
if mp_src_seq[ssrc] + 1 < total_stats[i]["sequence_number"]:
92+
while mp_src_seq[ssrc] + 1 < total_stats[i]["sequence_number"]:
93+
now_total += 1
94+
now_loss += 1
95+
mp_src_seq[ssrc] += 1
96+
now_total += 1
97+
mp_src_seq[ssrc] += 1
98+
assert abs(now_loss / now_total - predict_error_rate) <= predict_error_rate * ERROR_DYNAMICAL
99+
100+
101+
def test_loss_available():
102+
traces_name = ["trace_loss_0.json", "trace_loss_0dot1.json", "trace_loss_0dot5.json"]
103+
for trace in traces_name:
104+
trace_path = get_abs_path_by_name(trace)
105+
single_loss_available(trace_path)
106+
107+
108+
def test_loss_persistence():
109+
traces_name = ["trace_loss_0.json", "trace_loss_0dot1.json", "trace_loss_0dot5.json"]
110+
for trace in traces_name:
111+
trace_path = get_abs_path_by_name(trace)
112+
single_loss_persistence(trace_path, run_times=1000, bandwidth_bps=300000)
113+
114+
def test_loss_dynamically():
115+
traces_name = ["trace_loss_pattern_2.json", "trace_loss_pattern_3.json", "trace_loss_pattern_4.json"]
116+
for trace in traces_name:
117+
trace_path = get_abs_path_by_name(trace)
118+
single_loss_dynamically(trace_path, run_times=1000, bandwidth_bps=300000)

ns-app/scratch/webrtc_test/trace_player.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
#include "ns3/point-to-point-net-device.h"
44
#include "ns3/simulator.h"
55
#include "ns3/string.h"
6+
#include "ns3/error-model.h"
7+
#include "ns3/double.h"
8+
#include "ns3/pointer.h"
69
#include "ns3/channel.h"
710

811
#include <nlohmann/json.hpp>
@@ -42,6 +45,9 @@ void TracePlayer::LoadTrace() {
4245
TraceItem ti;
4346
ti.capacity_ = lexical_cast<decltype(ti.capacity_)>(trace["capacity"]);
4447
ti.duration_ms_ = lexical_cast<decltype(ti.duration_ms_)>(trace["duration"]);
48+
if (trace.find("loss") != trace.end()) {
49+
ti.loss_rate_ = lexical_cast<double>(trace["loss"]);
50+
}
4551
if (trace.find("rtt") != trace.end()) {
4652
ti.rtt_ms_ = lexical_cast<std::uint64_t>(trace["rtt"]);
4753
}
@@ -69,6 +75,13 @@ void TracePlayer::PlayTrace(size_t trace_index) {
6975
dynamic_cast<PointToPointNetDevice *>(PeekPointer(node->GetDevice(j)));
7076
if (device) {
7177
device->SetDataRate(DataRate(trace.capacity_ * 1e3));
78+
// set loss rate in every device
79+
if (trace.loss_rate_) {
80+
Ptr<RateErrorModel> em = CreateObjectWithAttributes<RateErrorModel> ("RanVar", StringValue("ns3::UniformRandomVariable[Min=0.0|Max=1.0]"), \
81+
"ErrorRate", DoubleValue (trace.loss_rate_.value()), \
82+
"ErrorUnit", StringValue("ERROR_UNIT_PACKET"));
83+
device->SetAttribute("ReceiveErrorModel", PointerValue (em));
84+
}
7285
}
7386
}
7487
}

ns-app/scratch/webrtc_test/trace_player.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
struct TraceItem {
1111
std::uint64_t capacity_;
1212
std::uint64_t duration_ms_;
13+
boost::optional<double> loss_rate_;
1314
boost::optional<std::uint64_t> rtt_ms_;
1415
};
1516

0 commit comments

Comments
 (0)