uint64_t *ttfb_pct; // counts per ttfb value for percentile
uint64_t *ttlb_pct; // counts per ttlb value for percentile
uint64_t tot_sc[5]; // total status codes on this thread: 1xx,2xx,3xx,4xx,5xx
+ uint64_t vtot_sc[HLD_HTTP_VER_MAX][5]; // by version total status codes
+ // on this thread: 1xx,2xx,3xx,4xx,5xx
struct task *rate_task; // task used when <arg_rate> is set
__attribute__((aligned(64))) union { } __pad;
};
int usr_tid;
int usr_cnt; // user counter incremented by <mtask> main task
int running_tasks; // tasks counter for the users and for the conn rate
+unsigned int hld_ver_flags; // flags to identify the HTTP versions used
char *hld_args[MAX_LINE_ARGS + 1];
{
int th;
uint64_t cur_conn, tot_conn, tot_req, tot_err, tot_rcvd, bytes;
- uint64_t tot_ttfb, tot_ttlb, tot_fbs, tot_lbs, tot_sc[5];
+ uint64_t tot_ttfb, tot_ttlb, tot_fbs, tot_lbs, tot_sc[5], vtot_sc[HLD_HTTP_VER_MAX][5];
static uint64_t prev_totc, prev_totr, prev_totb;
- static uint64_t prev_ttfb, prev_ttlb, prev_fbs, prev_lbs, prev_sc[5];
+ static uint64_t prev_ttfb, prev_ttlb, prev_fbs, prev_lbs, prev_sc[5],
+ prev_vsc[HLD_HTTP_VER_MAX][5];
static struct timeval prev_date = TV_UNSET;
double interval;
cur_conn = tot_conn = tot_req = tot_err = tot_rcvd = 0;
tot_ttfb = tot_ttlb = tot_fbs = tot_lbs = 0;
- tot_sc[0] = tot_sc[1] = tot_sc[2] = tot_sc[3] = tot_sc[4] = 0;
+ if (arg_hscd)
+ tot_sc[0] = tot_sc[1] = tot_sc[2] = tot_sc[3] = tot_sc[4] = 0;
+ if (arg_hscd == 2) {
+ int v;
+
+ for (v = HLD_HTTP_VER_0; v < HLD_HTTP_VER_MAX; v++)
+ vtot_sc[v][0] = vtot_sc[v][1] = vtot_sc[v][2] = vtot_sc[v][3] = vtot_sc[v][4] = 0;
+ }
for (th = 0; th < arg_thrd; th++) {
cur_conn += HA_ATOMIC_LOAD(&thrs_info[th].curconn);
tot_ttlb += HA_ATOMIC_LOAD(&thrs_info[th].tot_ttlb);
tot_fbs += HA_ATOMIC_LOAD(&thrs_info[th].tot_fbs);
tot_lbs += HA_ATOMIC_LOAD(&thrs_info[th].tot_lbs);
- tot_sc[0]+= HA_ATOMIC_LOAD(&thrs_info[th].tot_sc[0]);
- tot_sc[1]+= HA_ATOMIC_LOAD(&thrs_info[th].tot_sc[1]);
- tot_sc[2]+= HA_ATOMIC_LOAD(&thrs_info[th].tot_sc[2]);
- tot_sc[3]+= HA_ATOMIC_LOAD(&thrs_info[th].tot_sc[3]);
- tot_sc[4]+= HA_ATOMIC_LOAD(&thrs_info[th].tot_sc[4]);
+ if (arg_hscd) {
+ tot_sc[0]+= HA_ATOMIC_LOAD(&thrs_info[th].tot_sc[0]);
+ tot_sc[1]+= HA_ATOMIC_LOAD(&thrs_info[th].tot_sc[1]);
+ tot_sc[2]+= HA_ATOMIC_LOAD(&thrs_info[th].tot_sc[2]);
+ tot_sc[3]+= HA_ATOMIC_LOAD(&thrs_info[th].tot_sc[3]);
+ tot_sc[4]+= HA_ATOMIC_LOAD(&thrs_info[th].tot_sc[4]);
+ }
+ if (arg_hscd == 2) {
+ int v;
+
+ for (v = HLD_HTTP_VER_0; v < HLD_HTTP_VER_MAX; v++) {
+ if (!(hld_ver_flags & (1U << v)))
+ continue;
+
+ vtot_sc[v][0]+= HA_ATOMIC_LOAD(&thrs_info[th].vtot_sc[v][0]);
+ vtot_sc[v][1]+= HA_ATOMIC_LOAD(&thrs_info[th].vtot_sc[v][1]);
+ vtot_sc[v][2]+= HA_ATOMIC_LOAD(&thrs_info[th].vtot_sc[v][2]);
+ vtot_sc[v][3]+= HA_ATOMIC_LOAD(&thrs_info[th].vtot_sc[v][3]);
+ vtot_sc[v][4]+= HA_ATOMIC_LOAD(&thrs_info[th].vtot_sc[v][4]);
+ }
+ }
+
+
}
if (tv_isset(&prev_date))
/* status codes distribution */
if (arg_hscd)
- printf("%3llu %3llu %3llu %3llu %3llu ",
+ printf("%3llu %3llu %3llu %3llu %3llu",
(unsigned long long)(tot_sc[0] - prev_sc[0]),
(unsigned long long)(tot_sc[1] - prev_sc[1]),
(unsigned long long)(tot_sc[2] - prev_sc[2]),
(unsigned long long)(tot_sc[3] - prev_sc[3]),
(unsigned long long)(tot_sc[4] - prev_sc[4]));
+ if (arg_hscd == 2) {
+ int v;
+
+ for (v = HLD_HTTP_VER_0; v < HLD_HTTP_VER_MAX; v++) {
+ if (!(hld_ver_flags & (1U << v)))
+ continue;
+
+ printf(" %3llu %3llu %3llu %3llu %3llu",
+ (unsigned long long)(vtot_sc[v][0] - prev_vsc[v][0]),
+ (unsigned long long)(vtot_sc[v][1] - prev_vsc[v][1]),
+ (unsigned long long)(vtot_sc[v][2] - prev_vsc[v][2]),
+ (unsigned long long)(vtot_sc[v][3] - prev_vsc[v][3]),
+ (unsigned long long)(vtot_sc[v][4] - prev_vsc[v][4]));
+ }
+
+ }
putchar('\n');
fflush(stdout);
prev_lbs = tot_lbs;
prev_ttfb = tot_ttfb;
prev_ttlb = tot_ttlb;
- prev_sc[0]= tot_sc[0];
- prev_sc[1]= tot_sc[1];
- prev_sc[2]= tot_sc[2];
- prev_sc[3]= tot_sc[3];
- prev_sc[4]= tot_sc[4];
+ if (arg_hscd) {
+ prev_sc[0]= tot_sc[0];
+ prev_sc[1]= tot_sc[1];
+ prev_sc[2]= tot_sc[2];
+ prev_sc[3]= tot_sc[3];
+ prev_sc[4]= tot_sc[4];
+ }
+ if (arg_hscd == 2) {
+ int v;
+
+ for (v = HLD_HTTP_VER_0; v < HLD_HTTP_VER_MAX; v++) {
+ prev_vsc[v][0] = vtot_sc[v][0];
+ prev_vsc[v][1] = vtot_sc[v][1];
+ prev_vsc[v][2] = vtot_sc[v][2];
+ prev_vsc[v][3] = vtot_sc[v][3];
+ prev_vsc[v][4] = vtot_sc[v][4];
+ }
+ }
prev_date = hld_now;
}
" err cps rps bps ttfb");
if (arg_hscd)
printf(" 1xx 2xx 3xx 4xx 5xx");
+ if (arg_hscd == 2) {
+ int i;
+
+ for (i = 0 ; i < 4; i++) {
+ if (!(hld_ver_flags & (1 << i)))
+ continue;
+ printf(" (h%d)1xx 2xx 3xx 4xx 5xx", i);
+ }
+ }
+
+
putchar('\n');
}
TRACE_PRINTF(TRACE_LEVEL_PROTO, HLD_STRM_EV_RX, hs, 0, 0, 0,
"HTTP status: %d cur_read=%d",
status, (int)cur_read);
- thrs_info[tid].tot_sc[status * 41 / 4096 - 1]++;
+ if (arg_hscd)
+ thrs_info[tid].tot_sc[status * 41 / 4096 - 1]++;
+ if (arg_hscd == 2) {
+ thrs_info[tid].vtot_sc[hs->url->cfg->http_ver][status * 41 / 4096 - 1]++;
+ }
if (hs->url->tot_req > 1 || !arg_accu) {
ttfb = tv_us(tv_diff(&hs->req_date, &date));
thrs_info[tid].tot_fbs++;
task_destroy((*usr)->task);
session_free((*usr)->sess);
ha_free(usr);
+
+ TRACE_LEAVE(HLD_EV_USR_TASK);
}
static struct task *hld_usr_task(struct task *t, void *context, unsigned int state)
" -e stop upon first connection error\n"
" -h(0|1|2|2c|3) use h0 (hq-interop for QUIC), h1, h2, h2c or h3 (QUIC/TCP) protocols (*)\n"
" -(0|1|2|2c|3) same as above (*)\n"
+ " -hs show HTTP status codes distribution\n"
+ " -hsv show HTTP status codes distribution ((global + per HTTP version)\n"
" -l enable long output format; double for raw values\n"
" -m <streams> maximum concurrent streams (1)\n"
" -n <reqs> maximum total requests (-1)\n"
" --defaults <str> add a string to default section\n"
" --global <str> add a string to global section\n"
" --server <opts> set server <opt> options as defined for \"server\" haproxy keyword\n"
- " --show-status-codes show HTTP status codes distribution\n"
" --traces enable the traces for all the HTTP protocols\n"
"SSL options:\n"
" --tls-ciphers <ciphers> for TLS1.2 and below (*)\n"
* Return the URL if succeeded, NULL if not.
*/
static struct hld_url_cfg *hld_alloc_url(char *url, int is_quic,
- char *alpn_param, int h2c_param)
+ char *alpn_param, int h2c_param,
+ enum hld_http_ver http_ver)
{
int ssl = 0;
char *addr = NULL, *raw_addr = NULL, *path = NULL;
hld_url_cfg->ssl = ssl;
hld_url_cfg->is_quic = is_quic;
hld_url_cfg->h2c = h2c_param;
+ hld_url_cfg->http_ver = http_ver;
hld_url_cfg->addr = addr;
hld_url_cfg->raw_addr = raw_addr;
if (alpn_param) {
struct hbuf gbuf = HBUF_NULL; // "global" section
struct hbuf tbuf = HBUF_NULL; // "traces" section
struct hbuf dbuf = HBUF_NULL; // "default" section
+ int http_ver = HLD_HTTP_VER_1;
if (argc <= 1)
hld_usage(progname, argc);
argc--; argv++;
while (argc > 0) {
+
if (**argv == '-') {
char *opt = *argv + 1;
free(srv_opts);
srv_opts = strdup(opt);
}
- else if (strcmp(opt, "show-status-codes") == 0) {
- arg_hscd = 1;
- }
else if (strcmp(opt, "tls-ciphers") == 0) {
argv++, argc--;
if ((argc <= 0 || **argv == '-'))
strcmp(opt, "h0") == 0) {
alpn = "hq-interop";
h2c = 0;
+ http_ver = HLD_HTTP_VER_0;
}
else if (strcmp(opt, "1") == 0 ||
strcmp(opt, "h1") == 0) {
alpn = "http/1.1";
h2c = 0;
+ http_ver = HLD_HTTP_VER_1;
}
else if (strcmp(opt, "2") == 0 ||
strcmp(opt, "h2") == 0) {
alpn = "h2";
h2c = 0;
+ http_ver = HLD_HTTP_VER_2;
}
else if (strcmp(opt, "2c") == 0 ||
strcmp(opt, "h2c") == 0) {
alpn = NULL;
h2c = 1;
+ http_ver = HLD_HTTP_VER_2;
}
else if (strcmp(opt, "3") == 0 ||
strcmp(opt, "h3") == 0) {
#if defined(USE_QUIC)
alpn = "h3";
h2c = 0;
+ http_ver = HLD_HTTP_VER_3;
#else
ha_warning("QUIC support not compiled in. Rebuild with USE_QUIC=1.\n");
goto leave;
arg_serr = 1;
}
+ else if (strcmp(opt, "hs") == 0) {
+ arg_hscd = 1;
+ }
+ else if (strcmp(opt, "hsv") == 0) {
+ arg_hscd = 2;
+ }
else if (*opt == 'l') {
arg_long++;
while (*++opt && *opt == 'l')
struct hld_url_cfg *url;
is_quic = strncmp(*argv, "quic://", 7) == 0;
+ if (is_quic)
+ http_ver = HLD_HTTP_VER_3;
+ hld_ver_flags |= (1 << http_ver);
url = hld_alloc_url(*argv, is_quic,
is_quic ? "h3" : alpn,
- is_quic ? 0 : h2c);
+ is_quic ? 0 : h2c, http_ver);
if (!url) {
ha_alert("could not parse a new URL\n");
goto leave;
}
-
+ /* default version flag value */
+ http_ver = HLD_HTTP_VER_3;
}
argv++; argc--;