h2load: Print "space savings" to measure header compression efficiency

This commit is contained in:
Tatsuhiro Tsujikawa 2015-11-04 01:03:35 +09:00
parent 58d636abdb
commit 0dc7fee713
6 changed files with 41 additions and 13 deletions

View File

@ -33,10 +33,14 @@ traffic
requests were made via TLS, this value is the number of decrpyted
bytes.
headers
The number of response header bytes from the server without
decompression. For HTTP/2, this is the sum of the payload of
HEADERS frame. For SPDY, this is the sum of the payload of
SYN_REPLY frame.
The number of response header bytes from the server without
decompression. The ``space savings`` shows efficiency of header
compression. Let ``decompressed(headers)`` to the number of bytes
used for header fields after decompression. The ``space savings``
is calculated by (1 - ``headers`` / ``decompressed(headers)``) *
100. For HTTP/1.1, this is usually 0.00%, since it does not have
header compression. For HTTP/2 and SPDY, it shows some insightful
numbers.
data
The number of response body bytes received from the server.

View File

@ -95,8 +95,8 @@ RequestStat::RequestStat() : data_offset(0), completed(false) {}
Stats::Stats(size_t req_todo)
: req_todo(0), req_started(0), req_done(0), req_success(0),
req_status_success(0), req_failed(0), req_error(0), req_timedout(0),
bytes_total(0), bytes_head(0), bytes_body(0), status(),
req_stats(req_todo) {}
bytes_total(0), bytes_head(0), bytes_head_decomp(0), bytes_body(0),
status(), req_stats(req_todo) {}
Stream::Stream() : status_success(-1) {}
@ -2073,6 +2073,7 @@ int main(int argc, char **argv) {
stats.req_error += s.req_error;
stats.bytes_total += s.bytes_total;
stats.bytes_head += s.bytes_head;
stats.bytes_head_decomp += s.bytes_head_decomp;
stats.bytes_body += s.bytes_body;
for (size_t i = 0; i < stats.status.size(); ++i) {
@ -2102,7 +2103,13 @@ int main(int argc, char **argv) {
bps = stats.bytes_total / secd.count();
}
std::cout << R"(
double header_space_savings = 0.;
if (stats.bytes_head_decomp > 0) {
header_space_savings =
1. - static_cast<double>(stats.bytes_head) / stats.bytes_head_decomp;
}
std::cout << std::fixed << std::setprecision(2) << R"(
finished in )" << util::format_duration(duration) << ", " << rps << " req/s, "
<< util::utos_with_funit(bps) << R"(B/s
requests: )" << stats.req_todo << " total, " << stats.req_started
@ -2113,7 +2120,8 @@ requests: )" << stats.req_todo << " total, " << stats.req_started
status codes: )" << stats.status[2] << " 2xx, " << stats.status[3] << " 3xx, "
<< stats.status[4] << " 4xx, " << stats.status[5] << R"( 5xx
traffic: )" << stats.bytes_total << " bytes total, " << stats.bytes_head
<< " bytes headers, " << stats.bytes_body << R"( bytes data
<< " bytes headers (space savings " << header_space_savings * 100
<< "%), " << stats.bytes_body << R"( bytes data
min max mean sd +/- sd
time for request: )" << std::setw(10) << util::format_duration(ts.request.min)
<< " " << std::setw(10) << util::format_duration(ts.request.max)

View File

@ -166,8 +166,12 @@ struct Stats {
// The number of bytes received on the "wire". If SSL/TLS is used,
// this is the number of decrypted bytes the application received.
int64_t bytes_total;
// The number of bytes received in HEADERS frame payload.
// The number of bytes received for header fields. This is
// compressed version.
int64_t bytes_head;
// The number of bytes received for header fields after they are
// decompressed.
int64_t bytes_head_decomp;
// The number of bytes received in DATA frame.
int64_t bytes_body;
// The number of each HTTP status category, status[i] is status code

View File

@ -99,6 +99,7 @@ int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) {
auto client = session->get_client();
client->worker->stats.bytes_head += len;
client->worker->stats.bytes_head_decomp += len;
return 0;
}
} // namespace
@ -109,6 +110,7 @@ int htp_hdr_valcb(http_parser *htp, const char *data, size_t len) {
auto client = session->get_client();
client->worker->stats.bytes_head += len;
client->worker->stats.bytes_head_decomp += len;
return 0;
}
} // namespace

View File

@ -51,6 +51,7 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
return 0;
}
client->on_header(frame->hd.stream_id, name, namelen, value, valuelen);
client->worker->stats.bytes_head_decomp += namelen + valuelen;
return 0;
}
} // namespace
@ -63,7 +64,9 @@ int on_frame_recv_callback(nghttp2_session *session, const nghttp2_frame *frame,
frame->headers.cat != NGHTTP2_HCAT_RESPONSE) {
return 0;
}
client->worker->stats.bytes_head += frame->hd.length;
client->worker->stats.bytes_head +=
frame->hd.length - frame->headers.padlen -
((frame->hd.flags & NGHTTP2_FLAG_PRIORITY) ? 5 : 0);
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
client->record_ttfb();
}

View File

@ -65,11 +65,18 @@ void on_ctrl_recv_callback(spdylay_session *session, spdylay_frame_type type,
for (auto p = frame->syn_reply.nv; *p; p += 2) {
auto name = *p;
auto value = *(p + 1);
auto namelen = strlen(name);
auto valuelen = strlen(value);
client->on_header(frame->syn_reply.stream_id,
reinterpret_cast<const uint8_t *>(name), strlen(name),
reinterpret_cast<const uint8_t *>(value), strlen(value));
reinterpret_cast<const uint8_t *>(name), namelen,
reinterpret_cast<const uint8_t *>(value), valuelen);
client->worker->stats.bytes_head_decomp += namelen + valuelen;
}
client->worker->stats.bytes_head += frame->syn_reply.hd.length;
// Strictly speaking, we have to subtract 2 (unused field) if SPDY
// version is 2. But it is already deprecated, and we don't do
// extra work for it.
client->worker->stats.bytes_head += frame->syn_reply.hd.length - 4;
if (frame->syn_stream.hd.flags & SPDYLAY_CTRL_FLAG_FIN) {
client->record_ttfb();