Merge pull request #1695 from nghttp2/fix-perf-regression

nghttpx, h2load: Fix QUIC performance regression
This commit is contained in:
Tatsuhiro Tsujikawa 2022-04-06 21:08:45 +09:00 committed by GitHub
commit bfd08a46ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 81 additions and 43 deletions

View File

@ -345,11 +345,14 @@ struct Client {
struct {
bool send_blocked;
size_t num_blocked;
size_t num_blocked_sent;
struct {
Address remote_addr;
const uint8_t *data;
size_t datalen;
size_t max_udp_payload_size;
} blocked;
size_t gso_size;
} blocked[2];
std::unique_ptr<uint8_t[]> data;
} tx;
} quic;
@ -475,8 +478,8 @@ struct Client {
int write_quic();
int write_udp(const sockaddr *addr, socklen_t addrlen, const uint8_t *data,
size_t datalen, size_t gso_size);
void on_send_blocked(const ngtcp2_addr &remote_addr, size_t datalen,
size_t max_udp_payload_size);
void on_send_blocked(const ngtcp2_addr &remote_addr, const uint8_t *data,
size_t datalen, size_t gso_size);
int send_blocked_packet();
void quic_close_connection();

View File

@ -465,6 +465,7 @@ int Client::quic_init(const sockaddr *local_addr, socklen_t local_addrlen,
}
if (config->max_udp_payload_size) {
settings.max_udp_payload_size = config->max_udp_payload_size;
settings.no_udp_payload_size_shaping = 1;
}
ngtcp2_transport_params params;
@ -704,6 +705,7 @@ int Client::write_quic() {
#endif // !UDP_SEGMENT
uint8_t *bufpos = quic.tx.data.get();
ngtcp2_path_storage ps;
size_t gso_size = 0;
ngtcp2_path_storage_zero(&ps);
@ -767,11 +769,12 @@ int Client::write_quic() {
if (nwrite == 0) {
if (bufpos - quic.tx.data.get()) {
auto data = quic.tx.data.get();
auto datalen = bufpos - quic.tx.data.get();
rv = write_udp(ps.path.remote.addr, ps.path.remote.addrlen,
quic.tx.data.get(), datalen, max_udp_payload_size);
rv = write_udp(ps.path.remote.addr, ps.path.remote.addrlen, data,
datalen, gso_size);
if (rv == 1) {
on_send_blocked(ps.path.remote, datalen, max_udp_payload_size);
on_send_blocked(ps.path.remote, data, datalen, gso_size);
signal_write();
return 0;
}
@ -781,14 +784,37 @@ int Client::write_quic() {
bufpos += nwrite;
// Assume that the path does not change.
if (++pktcnt == max_pktcnt ||
static_cast<size_t>(nwrite) < max_udp_payload_size) {
auto datalen = bufpos - quic.tx.data.get();
rv = write_udp(ps.path.remote.addr, ps.path.remote.addrlen,
quic.tx.data.get(), datalen, max_udp_payload_size);
if (pktcnt == 0) {
gso_size = nwrite;
} else if (static_cast<size_t>(nwrite) > gso_size) {
auto data = quic.tx.data.get();
auto datalen = bufpos - quic.tx.data.get() - nwrite;
rv = write_udp(ps.path.remote.addr, ps.path.remote.addrlen, data, datalen,
gso_size);
if (rv == 1) {
on_send_blocked(ps.path.remote, datalen, max_udp_payload_size);
on_send_blocked(ps.path.remote, data, datalen, gso_size);
on_send_blocked(ps.path.remote, bufpos - nwrite, nwrite, 0);
} else {
auto data = bufpos - nwrite;
rv = write_udp(ps.path.remote.addr, ps.path.remote.addrlen, data,
nwrite, 0);
if (rv == 1) {
on_send_blocked(ps.path.remote, data, nwrite, 0);
}
}
signal_write();
return 0;
}
// Assume that the path does not change.
if (++pktcnt == max_pktcnt || static_cast<size_t>(nwrite) < gso_size) {
auto data = quic.tx.data.get();
auto datalen = bufpos - quic.tx.data.get();
rv = write_udp(ps.path.remote.addr, ps.path.remote.addrlen, data, datalen,
gso_size);
if (rv == 1) {
on_send_blocked(ps.path.remote, data, datalen, gso_size);
}
signal_write();
return 0;
@ -796,19 +822,22 @@ int Client::write_quic() {
}
}
void Client::on_send_blocked(const ngtcp2_addr &remote_addr, size_t datalen,
size_t max_udp_payload_size) {
assert(!quic.tx.send_blocked);
void Client::on_send_blocked(const ngtcp2_addr &remote_addr,
const uint8_t *data, size_t datalen,
size_t gso_size) {
assert(quic.tx.num_blocked || !quic.tx.send_blocked);
assert(quic.tx.num_blocked < 2);
quic.tx.send_blocked = true;
auto &p = quic.tx.blocked;
auto &p = quic.tx.blocked[quic.tx.num_blocked++];
memcpy(&p.remote_addr.su, remote_addr.addr, remote_addr.addrlen);
p.remote_addr.len = remote_addr.addrlen;
p.data = data;
p.datalen = datalen;
p.max_udp_payload_size = max_udp_payload_size;
p.gso_size = gso_size;
}
int Client::send_blocked_packet() {
@ -816,17 +845,22 @@ int Client::send_blocked_packet() {
assert(quic.tx.send_blocked);
auto &p = quic.tx.blocked;
for (; quic.tx.num_blocked_sent < quic.tx.num_blocked;
++quic.tx.num_blocked_sent) {
auto &p = quic.tx.blocked[quic.tx.num_blocked_sent];
rv = write_udp(&p.remote_addr.su.sa, p.remote_addr.len, quic.tx.data.get(),
p.datalen, p.max_udp_payload_size);
if (rv == 1) {
signal_write();
rv = write_udp(&p.remote_addr.su.sa, p.remote_addr.len, p.data, p.datalen,
p.gso_size);
if (rv == 1) {
signal_write();
return 0;
return 0;
}
}
quic.tx.send_blocked = false;
quic.tx.num_blocked = 0;
quic.tx.num_blocked_sent = 0;
return 0;
}

View File

@ -739,6 +739,7 @@ int Http3Upstream::write_streams() {
ngtcp2_path_storage ps, prev_ps;
size_t pktcnt = 0;
int rv;
size_t gso_size = 0;
auto ts = quic_timestamp();
ngtcp2_path_storage_zero(&ps);
@ -855,10 +856,10 @@ int Http3Upstream::write_streams() {
rv = send_packet(faddr, prev_ps.path.remote.addr,
prev_ps.path.remote.addrlen, prev_ps.path.local.addr,
prev_ps.path.local.addrlen, prev_pi, data, datalen,
max_udp_payload_size);
gso_size);
if (rv == SHRPX_ERR_SEND_BLOCKED) {
on_send_blocked(faddr, prev_ps.path.remote, prev_ps.path.local,
prev_pi, data, datalen, max_udp_payload_size);
prev_pi, data, datalen, gso_size);
ngtcp2_conn_update_pkt_tx_time(conn_, ts);
reset_idle_timer();
@ -884,8 +885,10 @@ int Http3Upstream::write_streams() {
if (pktcnt == 0) {
ngtcp2_path_copy(&prev_ps.path, &ps.path);
prev_pi = pi;
gso_size = nwrite;
} else if (!ngtcp2_path_eq(&prev_ps.path, &ps.path) ||
prev_pi.ecn != pi.ecn) {
prev_pi.ecn != pi.ecn ||
static_cast<size_t>(nwrite) > gso_size) {
auto faddr = static_cast<UpstreamAddr *>(prev_ps.path.user_data);
auto data = tx_.data.get();
auto datalen = bufpos - data - nwrite;
@ -893,15 +896,15 @@ int Http3Upstream::write_streams() {
rv = send_packet(faddr, prev_ps.path.remote.addr,
prev_ps.path.remote.addrlen, prev_ps.path.local.addr,
prev_ps.path.local.addrlen, prev_pi, data, datalen,
max_udp_payload_size);
gso_size);
switch (rv) {
case SHRPX_ERR_SEND_BLOCKED:
on_send_blocked(faddr, prev_ps.path.remote, prev_ps.path.local, prev_pi,
data, datalen, max_udp_payload_size);
data, datalen, gso_size);
on_send_blocked(static_cast<UpstreamAddr *>(ps.path.user_data),
ps.path.remote, ps.path.local, pi, bufpos - nwrite,
nwrite, max_udp_payload_size);
nwrite, 0);
signal_write_upstream_addr(faddr);
@ -912,10 +915,10 @@ int Http3Upstream::write_streams() {
rv = send_packet(faddr, ps.path.remote.addr, ps.path.remote.addrlen,
ps.path.local.addr, ps.path.local.addrlen, pi, data,
nwrite, max_udp_payload_size);
nwrite, 0);
if (rv == SHRPX_ERR_SEND_BLOCKED) {
on_send_blocked(faddr, ps.path.remote, ps.path.local, pi, data,
nwrite, max_udp_payload_size);
nwrite, 0);
}
signal_write_upstream_addr(faddr);
@ -928,18 +931,17 @@ int Http3Upstream::write_streams() {
return 0;
}
if (++pktcnt == max_pktcnt ||
static_cast<size_t>(nwrite) < max_udp_payload_size) {
if (++pktcnt == max_pktcnt || static_cast<size_t>(nwrite) < gso_size) {
auto faddr = static_cast<UpstreamAddr *>(ps.path.user_data);
auto data = tx_.data.get();
auto datalen = bufpos - data;
rv = send_packet(faddr, ps.path.remote.addr, ps.path.remote.addrlen,
ps.path.local.addr, ps.path.local.addrlen, pi, data,
datalen, max_udp_payload_size);
datalen, gso_size);
if (rv == SHRPX_ERR_SEND_BLOCKED) {
on_send_blocked(faddr, ps.path.remote, ps.path.local, pi, data, datalen,
max_udp_payload_size);
gso_size);
}
ngtcp2_conn_update_pkt_tx_time(conn_, ts);
@ -1875,7 +1877,7 @@ void Http3Upstream::on_send_blocked(const UpstreamAddr *faddr,
const ngtcp2_addr &local_addr,
const ngtcp2_pkt_info &pi,
const uint8_t *data, size_t datalen,
size_t max_udp_payload_size) {
size_t gso_size) {
assert(tx_.num_blocked || !tx_.send_blocked);
assert(tx_.num_blocked < 2);
@ -1892,7 +1894,7 @@ void Http3Upstream::on_send_blocked(const UpstreamAddr *faddr,
p.pi = pi;
p.data = data;
p.datalen = datalen;
p.max_udp_payload_size = max_udp_payload_size;
p.gso_size = gso_size;
}
int Http3Upstream::send_blocked_packet() {
@ -1905,7 +1907,7 @@ int Http3Upstream::send_blocked_packet() {
rv = send_packet(p.faddr, &p.remote_addr.su.sa, p.remote_addr.len,
&p.local_addr.su.sa, p.local_addr.len, p.pi, p.data,
p.datalen, p.max_udp_payload_size);
p.datalen, p.gso_size);
if (rv == SHRPX_ERR_SEND_BLOCKED) {
signal_write_upstream_addr(p.faddr);

View File

@ -160,8 +160,7 @@ public:
void on_send_blocked(const UpstreamAddr *faddr,
const ngtcp2_addr &remote_addr,
const ngtcp2_addr &local_addr, const ngtcp2_pkt_info &pi,
const uint8_t *data, size_t datalen,
size_t max_udp_payload_size);
const uint8_t *data, size_t datalen, size_t gso_size);
int send_blocked_packet();
void signal_write_upstream_addr(const UpstreamAddr *faddr);
@ -194,7 +193,7 @@ private:
ngtcp2_pkt_info pi;
const uint8_t *data;
size_t datalen;
size_t max_udp_payload_size;
size_t gso_size;
} blocked[2];
std::unique_ptr<uint8_t[]> data;
} tx_;