diff options
author | Yann Ylavic <ylavic@apache.org> | 2023-06-20 17:53:11 +0200 |
---|---|---|
committer | Yann Ylavic <ylavic@apache.org> | 2023-06-20 17:53:11 +0200 |
commit | 5d22e551c5f45fa500b8e109373c03a4786157c3 (patch) | |
tree | 7cb2188d2ca61f7b04fde5bc2709427e1666030c /support | |
parent | ab: Follow up to r1910515: Update global counter too.. (diff) | |
download | apache2-5d22e551c5f45fa500b8e109373c03a4786157c3.tar.xz apache2-5d22e551c5f45fa500b8e109373c03a4786157c3.zip |
ab: More accurate stats for time limited (-t) runs.
When ab runs for a limited time, the number of requests configured (or the
default MAX_REQUESTS if not configured) may be lower than than the number
of requests actually/finally achieved, in which case the stats per request
is a window of the actual stats since we can't store all the results.
Rather than taking the last N requests of the run for the stats, do the mean
of all the requests reusing the same window slot, and print that.
If no number of requests is configured for a time limited run, it will stop
only at the end of the time (i.e. MAX_REQUESTS is ignored for the end of
test condition). So MAX_REQUESTS is renamed to TIMED_REQUESTS while at it.
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1910517 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'support')
-rw-r--r-- | support/ab.c | 47 |
1 files changed, 35 insertions, 12 deletions
diff --git a/support/ab.c b/support/ab.c index 055d345541..2ff3187832 100644 --- a/support/ab.c +++ b/support/ab.c @@ -254,8 +254,8 @@ typedef STACK_OF(X509) X509_STACK_TYPE; #define AB_MAX LLONG_MAX #endif -/* maximum number of requests on a time limited test */ -#define MAX_REQUESTS (INT_MAX > 50000 ? 50000 : INT_MAX) +/* default number of requests on a time limited test */ +#define TIMED_REQUESTS (INT_MAX > 50000 ? 50000 : INT_MAX) #define ROUND_UP(x, y) ((((x) + (y) - 1) / (y)) * (y)) @@ -386,7 +386,7 @@ int recverrok = 0; /* ok to proceed after socket receive errors */ enum {NO_METH = 0, GET, HEAD, PUT, POST, CUSTOM_METHOD} method = NO_METH; const char *method_str[] = {"bug", "GET", "HEAD", "PUT", "POST", ""}; int send_body = 0; /* non-zero if sending body with request */ -int requests = 1; /* Number of requests to make */ +int requests = 0; /* Number of requests to make */ int num_workers = 1; /* Number of worker threads to use */ int heartbeatres = 100; /* How often do we say we're alive */ int concurrency = 1; /* Number of multiple requests to make */ @@ -394,6 +394,7 @@ int percentile = 1; /* Show percentile served */ int nolength = 0; /* Accept variable document length */ int confidence = 1; /* Show confidence estimator and warnings */ int tlimit = 0; /* time limit in secs */ +int rlimited = 0; /* whether there is a requests limit */ int keepalive = 0; /* try and do keepalive connections */ int windowsize = 0; /* we use the OS default window size */ char servername[1024]; /* name that server reports */ @@ -478,12 +479,12 @@ static apr_thread_cond_t *workers_can_start; static APR_INLINE int worker_should_stop(struct worker *worker) { return (lasttime >= stoptime - || (!tlimit && worker->metrics.done >= worker->requests)); + || (rlimited && worker->metrics.done >= worker->requests)); } static APR_INLINE int worker_can_start_connection(struct worker *worker) { return !(worker_should_stop(worker) - || (!tlimit && worker->started >= worker->requests)); + || (rlimited && worker->started >= worker->requests)); } static void workers_may_exit(int); @@ -1075,7 +1076,7 @@ static int compwait(struct data * a, struct data * b) static void consolidate_metrics(void) { - int i; + int i, j; for (i = 0; i < num_workers; i++) { struct worker *worker = &workers[i]; @@ -1112,6 +1113,21 @@ static void consolidate_metrics(void) sizeof(metrics.ssl_tmp_key)); } #endif + + if (worker->metrics.done > worker->requests) { + /* Mean of the cumulative stats accross the window */ + int n = (worker->metrics.done + worker->requests - 1) / worker->requests; + int m = (worker->metrics.done % worker->requests); + for (j = 0; j < worker->requests; j++) { + struct data *s = &worker->stats[j]; + if (j == m) { + n--; + } + s->waittime /= n; + s->ctime /= n; + s->time /= n; + } + } } } @@ -1152,6 +1168,7 @@ static void output_results(void) printf("Concurrency achieved: %d\n", metrics.concurrent); printf("Rampup delay: %" APR_TIME_T_FMT " [ms]\n", apr_time_as_msec(ramp)); printf("Time taken for tests: %.3f seconds\n", timetaken); + printf("Number of requests: %d%s\n", requests, rlimited ? "" : " (window)"); printf("Complete requests: %" APR_INT64_T_FMT "\n", metrics.done); printf("Failed requests: %" APR_INT64_T_FMT "\n", metrics.bad); if (metrics.bad) @@ -1750,10 +1767,13 @@ static void finalize_connection(struct connection *c, int reuse) apr_time_t tnow = lasttime = c->end = apr_time_now(); struct data *s = &worker->stats[worker->metrics.done++ % worker->requests]; - s->starttime = c->start; - s->time = ap_max(0, c->end - c->start); - s->ctime = ap_max(0, c->connect - c->start); - s->waittime = ap_max(0, c->beginread - c->endwrite); + /* Cumulative for when worker->metrics.done > worker->requests (tlimit), + * consolidate_metrics() will do the mean. + */ + s->starttime = c->start; /* use last.. */ + s->time += ap_max(0, c->end - c->start); + s->ctime += ap_max(0, c->connect - c->start); + s->waittime += ap_max(0, c->beginread - c->endwrite); if (heartbeatres) { static apr_int64_t reqs_count64; @@ -3007,8 +3027,6 @@ int main(int argc, const char * const argv[]) tlimit = atoi(opt_arg); if (tlimit < 0) fatal_error("Invalid negative timelimit\n"); - requests = MAX_REQUESTS; /* need to size data array on - * something */ break; case 'T': content_type = apr_pstrdup(cntxt, opt_arg); @@ -3198,6 +3216,11 @@ int main(int argc, const char * const argv[]) usage(argv[0]); } + rlimited = !tlimit || requests > 0; + if (requests == 0) { + requests = tlimit ? TIMED_REQUESTS : 1; + } + #if APR_HAS_THREADS if (num_workers == 0) { #ifdef _SC_NPROCESSORS_ONLN |