From 48e10c57da8c7ab385053c24f978d21f62a1e182 Mon Sep 17 00:00:00 2001 From: Hajime Fujita Date: Fri, 12 Mar 2021 19:12:46 +0000 Subject: [PATCH] h2load: Add qlog output support --- src/h2load.cc | 22 ++++++++++++++++++++++ src/h2load.h | 4 ++++ src/h2load_quic.cc | 35 ++++++++++++++++++++++++++++++++++- 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/h2load.cc b/src/h2load.cc index d8c2e5f6..dc713c2a 100644 --- a/src/h2load.cc +++ b/src/h2load.cc @@ -111,6 +111,7 @@ Config::Config() encoder_header_table_size(4_k), data_fd(-1), log_fd(-1), + qlog_file_base(), port(0), default_port(0), connect_to_port(0), @@ -2200,6 +2201,13 @@ Options: response time when using one worker thread, but may appear slightly out of order with multiple threads due to buffering. Status code is -1 for failed streams. + --qlog-file-base= + 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 and port to connect instead of using the authority in . @@ -2238,6 +2246,7 @@ int main(int argc, char **argv) { std::string datafile; std::string logfile; + std::string qlog_base; bool nreqs_set_manually = false; while (1) { static int flag = 0; @@ -2274,6 +2283,7 @@ int main(int argc, char **argv) { {"groups", required_argument, &flag, 13}, {"tls13-ciphers", required_argument, &flag, 14}, {"no-udp-gso", no_argument, &flag, 15}, + {"qlog-file-base", required_argument, &flag, 16}, {nullptr, 0, nullptr, 0}}; int option_index = 0; auto c = getopt_long(argc, argv, @@ -2536,6 +2546,10 @@ int main(int argc, char **argv) { // --no-udp-gso config.no_udp_gso = true; break; + case 16: + // --qlog-file-base + qlog_base = optarg; + break; } break; 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 {}; act.sa_handler = SIG_IGN; sigaction(SIGPIPE, &act, nullptr); diff --git a/src/h2load.h b/src/h2load.h index afb369a6..431cd999 100644 --- a/src/h2load.h +++ b/src/h2load.h @@ -109,6 +109,8 @@ struct Config { int data_fd; // file descriptor to write per-request stats to. int log_fd; + // base file name of qlog output files + std::string qlog_file_base; uint16_t port; uint16_t default_port; uint16_t connect_to_port; @@ -340,6 +342,7 @@ struct Client { std::array crypto; size_t max_pktlen; bool close_requested; + FILE *qlog_file; } quic; ev_timer request_timeout_watcher; addrinfo *next_addr; @@ -481,6 +484,7 @@ struct Client { const uint8_t *data, size_t datalen); int quic_pkt_timeout(); void quic_restart_pkt_timer(); + void quic_write_qlog(const void *data, size_t datalen); }; } // namespace h2load diff --git a/src/h2load_quic.cc b/src/h2load_quic.cc index 9d8693f0..aa7bf291 100644 --- a/src/h2load_quic.cc +++ b/src/h2load_quic.cc @@ -34,6 +34,8 @@ #include "h2load_http3_session.h" +#include + namespace h2load { namespace { @@ -284,6 +286,20 @@ auto quic_method = SSL_QUIC_METHOD{ }; } // 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(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, const sockaddr *remote_addr, socklen_t remote_addrlen) { 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.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_default(¶ms); @@ -393,7 +420,13 @@ int Client::quic_init(const sockaddr *local_addr, socklen_t local_addrlen, 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() { if (!quic.conn) {