Skip to content

Commit 8720cfd

Browse files
authored
FEAT: reeduce packet copying number (#563)
closes #560
1 parent 6a1a2a3 commit 8720cfd

53 files changed

Lines changed: 347 additions & 352 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
build/
33
CMakePresets.json
44
**/__pycache__/*
5-
_output/
5+
_output/
6+
.claude/

source/network/connection/flow/packet.hpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22

3+
#include <memory>
34
#include <string>
45

56
#include "four_tuple.hpp"
@@ -12,7 +13,9 @@ using PathHash = std::uint32_t;
1213

1314
struct Packet;
1415

15-
using OnPacketDeliveryCallback = std::function<void(const Packet&)>;
16+
using PacketPtr = std::shared_ptr<Packet>;
17+
18+
using OnPacketDeliveryCallback = std::function<void(PacketPtr)>;
1619

1720
struct Packet : FourTuple {
1821
Packet(SizeByte a_size = SizeByte(0ul), Id a_source_id = "",
@@ -32,8 +35,8 @@ struct Packet : FourTuple {
3235

3336
// Note: callback takes packet itself because it might be changed while
3437
// travelling along the net
35-
OnPacketDeliveryCallback callback =
36-
[]([[maybe_unused]] const Packet& packet) {};
38+
OnPacketDeliveryCallback callback = []([[maybe_unused]] PacketPtr packet) {
39+
};
3740
TimeNs generated_time; // Note: ACK's generated time is the data packet
3841
// generated time
3942
TimeNs sent_time; // Note: ACK's sent time is the data packet sent time

source/network/connection/flow/packet_ack_info.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace sim {
88
struct PacketAckInfo {
99
TimeNs rtt;
1010
const utils::Statistics<TimeNs>& rtt_stat;
11-
const Packet& ack;
11+
PacketPtr ack;
1212
};
1313

1414
} // namespace sim

source/network/connection/flow/tcp/tcp_flow.cpp

Lines changed: 55 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -72,155 +72,150 @@ TcpFlow::TcpFlow(Id a_id, FlowFourTuple a_four_tuple, bool a_ecn_capable,
7272
}
7373
}
7474

75-
Packet TcpFlow::create_data_packet(PacketInfo info,
76-
std::shared_ptr<IHost> sender,
77-
std::shared_ptr<IHost> receiver) {
78-
Packet packet;
79-
packet.packet_num = m_next_packet_num++;
80-
81-
packet.flags = m_flag_manager;
82-
packet.flags.set_flag(m_packet_type_label, PacketType::DATA)
75+
PacketPtr TcpFlow::create_data_packet(PacketInfo info,
76+
std::shared_ptr<IHost> sender,
77+
std::shared_ptr<IHost> receiver) {
78+
auto packet = std::make_shared<Packet>();
79+
packet->packet_num = m_next_packet_num++;
80+
81+
packet->flags = m_flag_manager;
82+
packet->flags.set_flag(m_packet_type_label, PacketType::DATA)
8383
.log_err_if_not_present("Failed to set packet type (DATA)");
8484

8585
set_avg_rtt_if_present(packet);
8686

87-
packet.data_id = std::move(info.id);
88-
packet.sender_id = sender->get_id();
89-
packet.sender_port = m_context.sender_port;
90-
packet.receiver_port = m_context.receiver_port;
91-
packet.receiver_id = receiver->get_id();
92-
packet.size = info.packet_size;
87+
packet->data_id = std::move(info.id);
88+
packet->sender_id = sender->get_id();
89+
packet->sender_port = m_context.sender_port;
90+
packet->receiver_port = m_context.receiver_port;
91+
packet->receiver_id = receiver->get_id();
92+
packet->size = info.packet_size;
9393

9494
std::shared_ptr<TcpFlow> flow = shared_from_this();
9595

96-
packet.callback = [flow, delivery_callback = info.callback](
97-
const Packet& delivered_packet) {
96+
packet->callback = [flow, delivery_callback =
97+
info.callback](PacketPtr delivered_packet) {
9898
flow->process_data_packet(delivered_packet, delivery_callback);
9999
};
100-
packet.generated_time = info.generated_time;
101-
packet.sent_time = Scheduler::get_instance().get_current_time();
102-
packet.delivered_data_size_at_origin = m_context.delivered_size;
100+
packet->generated_time = info.generated_time;
101+
packet->sent_time = Scheduler::get_instance().get_current_time();
102+
packet->delivered_data_size_at_origin = m_context.delivered_size;
103103

104-
packet.ecn_capable_transport = m_ecn_capable;
105-
packet.congestion_experienced = false;
104+
packet->ecn_capable_transport = m_ecn_capable;
105+
packet->congestion_experienced = false;
106106

107107
return packet;
108108
}
109109

110-
void TcpFlow::set_avg_rtt_if_present(Packet& packet) {
110+
void TcpFlow::set_avg_rtt_if_present(PacketPtr packet) {
111111
std::optional<TimeNs> avg_rtt = m_context.rtt_statistics.get_mean();
112112
if (avg_rtt.has_value()) {
113-
set_avg_rtt_flag(packet.flags, avg_rtt.value())
113+
set_avg_rtt_flag(packet->flags, avg_rtt.value())
114114
.log_err_if_not_present("Failed to set average RTT");
115115
}
116116
}
117117

118-
void TcpFlow::send_data_packet(Packet data) {
118+
void TcpFlow::send_data_packet(PacketPtr data) {
119119
TimeNs now = Scheduler::get_instance().get_current_time();
120120

121121
Scheduler::get_instance().add(
122122
now + m_rto.current,
123123
[flow = shared_from_this(), data]() { flow->on_timeout(data); });
124-
m_context.sent_size += data.size;
124+
m_context.sent_size += data->size;
125125

126-
data.sent_time = now;
126+
data->sent_time = now;
127127
m_context.sender->enqueue_packet(data);
128128
}
129129

130-
void TcpFlow::process_data_packet(const Packet& data,
130+
void TcpFlow::process_data_packet(PacketPtr data,
131131
const PacketCallback& callback) {
132-
m_packet_reordering.add_record(data.packet_num);
132+
m_packet_reordering.add_record(data->packet_num);
133133
m_metrics.packet_reordering->add_record(
134134
Scheduler::get_instance().get_current_time(),
135135
m_packet_reordering.value());
136-
Packet ack = data;
137-
ack.sender_id = IdWithHash(m_context.receiver->get_id());
138-
ack.sender_port = m_context.receiver_port;
139-
ack.receiver_id = IdWithHash(m_context.sender->get_id());
140-
ack.receiver_port = m_context.sender_port;
141-
ack.size = SizeByte(1ul);
142-
ack.ttl = M_MAX_TTL;
143-
auto exp_void = ack.flags.set_flag(m_packet_type_label, PacketType::ACK);
136+
auto ack = std::make_shared<Packet>(*data);
137+
ack->sender_id = IdWithHash(m_context.receiver->get_id());
138+
ack->sender_port = m_context.receiver_port;
139+
ack->receiver_id = IdWithHash(m_context.sender->get_id());
140+
ack->receiver_port = m_context.sender_port;
141+
ack->size = SizeByte(1ul);
142+
ack->ttl = M_MAX_TTL;
143+
auto exp_void = ack->flags.set_flag(m_packet_type_label, PacketType::ACK);
144144
if (!exp_void.has_value()) {
145145
LOG_ERROR(
146146
fmt::format("Flow {}: could not set type label to ack packet {}",
147-
m_id, ack.to_string()));
147+
m_id, ack->to_string()));
148148
}
149-
SizeByte data_packet_size = data.size;
149+
SizeByte data_packet_size = data->size;
150150

151151
std::shared_ptr<TcpFlow> flow = shared_from_this();
152-
ack.callback = [flow, callback,
153-
data_packet_size](const Packet& delivered_ack) {
152+
ack->callback = [flow, callback,
153+
data_packet_size](PacketPtr delivered_ack) {
154154
flow->process_ack(delivered_ack, data_packet_size, callback);
155155
};
156156

157-
m_context.receiver->enqueue_packet(ack);
157+
m_context.receiver->enqueue_packet(std::move(ack));
158158
}
159159

160-
void TcpFlow::process_ack(const Packet& ack, SizeByte data_packet_size,
160+
void TcpFlow::process_ack(PacketPtr ack, SizeByte data_packet_size,
161161
PacketCallback callback) {
162162
TimeNs now = Scheduler::get_instance().get_current_time();
163163

164-
// here ack.sent_time is the time when corresponding DATA packet was sent
165-
// (see process_data_packet)
166-
TimeNs rtt = now - ack.sent_time;
164+
TimeNs rtt = now - ack->sent_time;
167165

168166
m_context.rtt_statistics.add_record(rtt);
169167

170168
m_metrics.rtt->add_record(now, rtt.value());
171169

172170
update_rto_on_ack();
173171

174-
if (!m_ack_monitor.confirm_one(ack.packet_num)) {
172+
if (!m_ack_monitor.confirm_one(ack->packet_num)) {
175173
LOG_WARN(
176174
fmt::format("Flow {} got ack {} that confirms nothing; ignored",
177-
m_id, ack.to_string()));
175+
m_id, ack->to_string()));
178176
return;
179177
}
180178
m_context.last_ack_receive_time = now;
181179

182180
m_context.delivered_size += data_packet_size;
183181

184182
SpeedGbps delivery_rate =
185-
(m_context.delivered_size - ack.delivered_data_size_at_origin) /
186-
(now - ack.generated_time);
183+
(m_context.delivered_size - ack->delivered_data_size_at_origin) /
184+
(now - ack->generated_time);
187185

188186
m_metrics.delivery_rate->add_record(now, delivery_rate.value());
189187
m_context.delivery_rate_statistics.add_record(delivery_rate);
190188

191189
callback({PacketAckInfo{rtt, m_context.rtt_statistics, ack}});
192190
}
193191

194-
// After ACK with a valid RTT: formula + transition to STEADY (once)
195192
void TcpFlow::update_rto_on_ack() {
196193
auto mean = m_context.rtt_statistics.get_mean().value();
197194
TimeNs std = m_context.rtt_statistics.get_std().value();
198195
m_rto.current = std::min(mean * 2 + std * 4, m_rto.max);
199196
m_rto.is_steady = true;
200197
}
201198

202-
void TcpFlow::on_timeout(const Packet& data) {
203-
if (m_ack_monitor.is_confirmed(data.packet_num)) {
204-
LOG_INFO(fmt::format(
205-
"Flow {}: packet {} is confirmed when timeout reached; no "
206-
"retransmit",
207-
m_id, data.packet_num));
199+
void TcpFlow::on_timeout(PacketPtr data) {
200+
if (m_ack_monitor.is_confirmed(data->packet_num)) {
201+
LOG_INFO(
202+
fmt::format("Flow {}: packet {} is confirmed when timeout reached; "
203+
"no retransmit",
204+
m_id, data->packet_num));
208205
return;
209206
}
210207
update_rto_on_timeout();
211208
retransmit_packet(data);
212209
}
213210

214-
// Before the first ACK: exponential growth by timeout
215211
void TcpFlow::update_rto_on_timeout() {
216212
if (!m_rto.is_steady) {
217213
m_rto.current = std::min(m_rto.current * 2, m_rto.max);
218214
}
219-
// in STEADY, don't touch RTO by timeout
220215
}
221216

222-
void TcpFlow::retransmit_packet(const Packet& data) {
223-
m_context.retransmit_size += data.size;
217+
void TcpFlow::retransmit_packet(PacketPtr data) {
218+
m_context.retransmit_size += data->size;
224219
send_data_packet(data);
225220
}
226221

source/network/connection/flow/tcp/tcp_flow.hpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#pragma once
2+
#include <memory>
3+
24
#include "../i_flow.hpp"
35
#include "metrics/metrics_table/i_metricable.hpp"
46
#include "metrics/packet_reordering/simple_packet_reordering.hpp"
@@ -41,24 +43,24 @@ class TcpFlow : public IFlow, public std::enable_shared_from_this<TcpFlow> {
4143
TcpFlow(Id a_id, FlowFourTuple a_four_tuple, bool a_ecn_capable, RTO a_rto,
4244
TcpFlowMetricsFilters a_metrics_flags);
4345

44-
Packet create_data_packet(PacketInfo info, std::shared_ptr<IHost> sender,
45-
std::shared_ptr<IHost> receiver);
46+
PacketPtr create_data_packet(PacketInfo info, std::shared_ptr<IHost> sender,
47+
std::shared_ptr<IHost> receiver);
4648

47-
void set_avg_rtt_if_present(Packet& packet);
49+
void set_avg_rtt_if_present(PacketPtr packet);
4850

49-
void send_data_packet(Packet data);
51+
void send_data_packet(PacketPtr data);
5052

51-
void process_data_packet(const Packet& data_packet,
53+
void process_data_packet(PacketPtr data_packet,
5254
const PacketCallback& callback);
5355

54-
void process_ack(const Packet& ack, SizeByte data_packet_size,
56+
void process_ack(PacketPtr ack, SizeByte data_packet_size,
5557
PacketCallback callback);
5658

5759
void update_rto_on_ack();
5860

59-
void on_timeout(const Packet& data);
61+
void on_timeout(PacketPtr data);
6062
void update_rto_on_timeout();
61-
void retransmit_packet(const Packet& data);
63+
void retransmit_packet(PacketPtr data);
6264

6365
private:
6466
// flag labels

source/network/connection/mplb/cc/tahoe/tcp_tahoe_cc.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ TcpTahoeCC::TcpTahoeCC(double a_start_cwnd, double a_sstresh)
1313

1414
void TcpTahoeCC::on_ack(const PacketAckInfo& info) {
1515
m_last_avg_rtt = info.rtt_stat.get_mean().value();
16-
if (info.ack.congestion_experienced) {
16+
if (info.ack->congestion_experienced) {
1717
on_timeout();
1818
} else if (m_cwnd < m_ssthresh) {
1919
// Slow start

0 commit comments

Comments
 (0)