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

View File

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

View File

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