h2load: Add qlog output support

This commit is contained in:
Hajime Fujita 2021-03-12 19:12:46 +00:00 committed by Tatsuhiro Tsujikawa
parent 1eb818b64c
commit 48e10c57da
3 changed files with 60 additions and 1 deletions

View File

@ -111,6 +111,7 @@ Config::Config()
encoder_header_table_size(4_k), encoder_header_table_size(4_k),
data_fd(-1), data_fd(-1),
log_fd(-1), log_fd(-1),
qlog_file_base(),
port(0), port(0),
default_port(0), default_port(0),
connect_to_port(0), connect_to_port(0),
@ -2200,6 +2201,13 @@ Options:
response time when using one worker thread, but may response time when using one worker thread, but may
appear slightly out of order with multiple threads due appear slightly out of order with multiple threads due
to buffering. Status code is -1 for failed streams. to buffering. Status code is -1 for failed streams.
--qlog-file-base=<PATH>
Enable qlog output and specify base file name for qlogs.
Qlog is emitted for each connection.
For a given base name "base", each output file name
becomes "base.M.N.qlog" where M is worker ID and N is
client ID (e.g. "base.0.3.qlog").
Only effective in QUIC runs.
--connect-to=<HOST>[:<PORT>] --connect-to=<HOST>[:<PORT>]
Host and port to connect instead of using the authority Host and port to connect instead of using the authority
in <URI>. in <URI>.
@ -2238,6 +2246,7 @@ int main(int argc, char **argv) {
std::string datafile; std::string datafile;
std::string logfile; std::string logfile;
std::string qlog_base;
bool nreqs_set_manually = false; bool nreqs_set_manually = false;
while (1) { while (1) {
static int flag = 0; static int flag = 0;
@ -2274,6 +2283,7 @@ int main(int argc, char **argv) {
{"groups", required_argument, &flag, 13}, {"groups", required_argument, &flag, 13},
{"tls13-ciphers", required_argument, &flag, 14}, {"tls13-ciphers", required_argument, &flag, 14},
{"no-udp-gso", no_argument, &flag, 15}, {"no-udp-gso", no_argument, &flag, 15},
{"qlog-file-base", required_argument, &flag, 16},
{nullptr, 0, nullptr, 0}}; {nullptr, 0, nullptr, 0}};
int option_index = 0; int option_index = 0;
auto c = getopt_long(argc, argv, auto c = getopt_long(argc, argv,
@ -2536,6 +2546,10 @@ int main(int argc, char **argv) {
// --no-udp-gso // --no-udp-gso
config.no_udp_gso = true; config.no_udp_gso = true;
break; break;
case 16:
// --qlog-file-base
qlog_base = optarg;
break;
} }
break; break;
default: default:
@ -2720,6 +2734,14 @@ int main(int argc, char **argv) {
} }
} }
if (!qlog_base.empty()) {
if (!config.is_quic()) {
std::cerr << "Warning: --qlog-file-base: only effective in quic, ignoring." << std::endl;
} else {
config.qlog_file_base = qlog_base;
}
}
struct sigaction act {}; struct sigaction act {};
act.sa_handler = SIG_IGN; act.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &act, nullptr); sigaction(SIGPIPE, &act, nullptr);

View File

@ -109,6 +109,8 @@ struct Config {
int data_fd; int data_fd;
// file descriptor to write per-request stats to. // file descriptor to write per-request stats to.
int log_fd; int log_fd;
// base file name of qlog output files
std::string qlog_file_base;
uint16_t port; uint16_t port;
uint16_t default_port; uint16_t default_port;
uint16_t connect_to_port; uint16_t connect_to_port;
@ -340,6 +342,7 @@ struct Client {
std::array<Crypto, 2> crypto; std::array<Crypto, 2> crypto;
size_t max_pktlen; size_t max_pktlen;
bool close_requested; bool close_requested;
FILE *qlog_file;
} quic; } quic;
ev_timer request_timeout_watcher; ev_timer request_timeout_watcher;
addrinfo *next_addr; addrinfo *next_addr;
@ -481,6 +484,7 @@ struct Client {
const uint8_t *data, size_t datalen); const uint8_t *data, size_t datalen);
int quic_pkt_timeout(); int quic_pkt_timeout();
void quic_restart_pkt_timer(); void quic_restart_pkt_timer();
void quic_write_qlog(const void *data, size_t datalen);
}; };
} // namespace h2load } // namespace h2load

View File

@ -34,6 +34,8 @@
#include "h2load_http3_session.h" #include "h2load_http3_session.h"
#include <sstream>
namespace h2load { namespace h2load {
namespace { namespace {
@ -284,6 +286,20 @@ auto quic_method = SSL_QUIC_METHOD{
}; };
} // namespace } // namespace
// qlog write callback -- excerpted from ngtcp2/examples/client_base.cc
namespace {
void qlog_write_cb(void *user_data, uint32_t flags, const void *data,
size_t datalen) {
auto c = static_cast<Client *>(user_data);
c->quic_write_qlog(data, datalen);
}
} // namespace
void Client::quic_write_qlog(const void *data, size_t datalen) {
assert(quic.qlog_file != nullptr);
fwrite(data, 1, datalen, quic.qlog_file);
}
int Client::quic_init(const sockaddr *local_addr, socklen_t local_addrlen, int Client::quic_init(const sockaddr *local_addr, socklen_t local_addrlen,
const sockaddr *remote_addr, socklen_t remote_addrlen) { const sockaddr *remote_addr, socklen_t remote_addrlen) {
int rv; int rv;
@ -354,6 +370,17 @@ int Client::quic_init(const sockaddr *local_addr, socklen_t local_addrlen,
settings.log_printf = debug_log_printf; settings.log_printf = debug_log_printf;
} }
settings.initial_ts = timestamp(worker->loop); settings.initial_ts = timestamp(worker->loop);
if (!config->qlog_file_base.empty()) {
assert(quic.qlog_file == nullptr);
std::ostringstream oss(config->qlog_file_base, std::ios::app);
oss << '.' << worker->id << '.' << id << ".qlog";
quic.qlog_file = fopen(oss.str().c_str(), "w");
if (quic.qlog_file == nullptr) {
std::cerr << "Failed to open a qlog file: " << oss.str() << std::endl;
return -1;
}
settings.qlog.write = qlog_write_cb;
}
ngtcp2_transport_params params; ngtcp2_transport_params params;
ngtcp2_transport_params_default(&params); ngtcp2_transport_params_default(&params);
@ -393,7 +420,13 @@ int Client::quic_init(const sockaddr *local_addr, socklen_t local_addrlen,
return 0; return 0;
} }
void Client::quic_free() { ngtcp2_conn_del(quic.conn); } void Client::quic_free() {
ngtcp2_conn_del(quic.conn);
if (quic.qlog_file != nullptr) {
fclose(quic.qlog_file);
quic.qlog_file = nullptr;
}
}
void Client::quic_close_connection() { void Client::quic_close_connection() {
if (!quic.conn) { if (!quic.conn) {