h2load: Print "space savings" to measure header compression efficiency
This commit is contained in:
parent
58d636abdb
commit
0dc7fee713
|
@ -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.
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue