in support/ab.c [1180:1463]
static void output_results(void)
{
double timetaken;
timetaken = (double) (lasttime - start) / APR_USEC_PER_SEC;
printf("\n\n");
printf("Server Software: %s\n", servername);
printf("Server Hostname: %s\n", hostname);
printf("Server Port: %hu\n", port);
#ifdef USE_SSL
if (is_ssl && metrics.ssl_info[0]) {
printf("SSL/TLS Protocol: %s\n", metrics.ssl_info);
}
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
if (is_ssl && metrics.ssl_tmp_key[0]) {
printf("Server Temp Key: %s\n", metrics.ssl_tmp_key);
}
#endif
#ifdef HAVE_TLSEXT
if (is_ssl && tls_sni) {
printf("TLS Server Name: %s\n", tls_sni);
}
#endif
#endif
printf("\n");
printf("Document Path: %s\n", path);
if (nolength)
printf("Document Length: Variable\n");
else
printf("Document Length: %" APR_SIZE_T_FMT " bytes\n", metrics.doclen);
printf("\n");
printf("Number of workers: %d\n", num_workers);
printf("Concurrency Level: %d\n", concurrency);
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)
printf(" (Connect: %d, Receive: %d, Length: %d, Exceptions: %d)\n",
metrics.err_conn, metrics.err_recv, metrics.err_length, metrics.err_except);
if (metrics.epipe)
printf("Write errors: %d\n", metrics.epipe);
if (metrics.err_response)
printf("Non-2xx responses: %d\n", metrics.err_response);
if (keepalive) {
printf("Keep-Alive requests: %" APR_INT64_T_FMT "\n", metrics.doneka);
if (metrics.aborted_ka) {
printf("Keep-Alive aborts: %d\n", metrics.aborted_ka);
}
}
printf("Total transferred: %" APR_INT64_T_FMT " bytes\n", metrics.totalread);
if (send_body)
printf("Total body sent: %" APR_INT64_T_FMT "\n", metrics.totalposted);
printf("HTML transferred: %" APR_INT64_T_FMT " bytes\n", metrics.totalbread);
/* avoid divide by zero */
if (timetaken && metrics.done) {
printf("Requests per second: %.2f [#/sec] (mean)\n",
(double) metrics.done / timetaken);
printf("Time per request: %.3f [ms] (mean)\n",
(double) concurrency * timetaken * 1000 / metrics.done);
printf("Time per request: %.3f [ms] (mean, across all concurrent requests)\n",
(double) timetaken * 1000 / metrics.done);
printf("Transfer rate: %.2f [Kbytes/sec] received\n",
(double) metrics.totalread / 1024 / timetaken);
if (send_body) {
printf(" %.2f kb/s sent\n",
(double) metrics.totalposted / 1024 / timetaken);
printf(" %.2f kb/s total\n",
(double) (metrics.totalread + metrics.totalposted) / 1024 / timetaken);
}
}
if (metrics.done > 0) {
/* work out connection times */
apr_int64_t i, count = ap_min(metrics.done, requests);
apr_time_t totalcon = 0, total = 0, totald = 0, totalwait = 0;
apr_time_t meancon, meantot, meand, meanwait;
apr_interval_time_t mincon = AB_TIME_MAX, mintot = AB_TIME_MAX,
mind = AB_TIME_MAX, minwait = AB_TIME_MAX;
apr_interval_time_t maxcon = 0, maxtot = 0, maxd = 0, maxwait = 0;
apr_interval_time_t mediancon = 0, mediantot = 0, mediand = 0, medianwait = 0;
double sdtot = 0, sdcon = 0, sdd = 0, sdwait = 0;
for (i = 0; i < count; i++) {
struct data *s = &stats[i];
mincon = ap_min(mincon, s->ctime);
mintot = ap_min(mintot, s->time);
mind = ap_min(mind, s->time - s->ctime);
minwait = ap_min(minwait, s->waittime);
maxcon = ap_max(maxcon, s->ctime);
maxtot = ap_max(maxtot, s->time);
maxd = ap_max(maxd, s->time - s->ctime);
maxwait = ap_max(maxwait, s->waittime);
totalcon += s->ctime;
total += s->time;
totald += s->time - s->ctime;
totalwait += s->waittime;
}
meancon = totalcon / count;
meantot = total / count;
meand = totald / count;
meanwait = totalwait / count;
/* calculating the sample variance: the sum of the squared deviations, divided by n-1 */
for (i = 0; i < count; i++) {
struct data *s = &stats[i];
double a;
a = ((double)s->time - meantot);
sdtot += a * a;
a = ((double)s->ctime - meancon);
sdcon += a * a;
a = ((double)s->time - (double)s->ctime - meand);
sdd += a * a;
a = ((double)s->waittime - meanwait);
sdwait += a * a;
}
sdtot = (count > 1) ? sqrt(sdtot / (count - 1)) : 0;
sdcon = (count > 1) ? sqrt(sdcon / (count - 1)) : 0;
sdd = (count > 1) ? sqrt(sdd / (count - 1)) : 0;
sdwait = (count > 1) ? sqrt(sdwait / (count - 1)) : 0;
/*
* XXX: what is better; this hideous cast of the compradre function; or
* the four warnings during compile ? dirkx just does not know and
* hates both/
*/
qsort(stats, count, sizeof(struct data),
(int (*) (const void *, const void *)) compradre);
if ((count > 1) && (count % 2))
mediancon = (stats[count / 2].ctime + stats[count / 2 + 1].ctime) / 2;
else
mediancon = stats[count / 2].ctime;
qsort(stats, count, sizeof(struct data),
(int (*) (const void *, const void *)) compri);
if ((count > 1) && (count % 2))
mediand = (stats[count / 2].time + stats[count / 2 + 1].time \
-stats[count / 2].ctime - stats[count / 2 + 1].ctime) / 2;
else
mediand = stats[count / 2].time - stats[count / 2].ctime;
qsort(stats, count, sizeof(struct data),
(int (*) (const void *, const void *)) compwait);
if ((count > 1) && (count % 2))
medianwait = (stats[count / 2].waittime + stats[count / 2 + 1].waittime) / 2;
else
medianwait = stats[count / 2].waittime;
qsort(stats, count, sizeof(struct data),
(int (*) (const void *, const void *)) comprando);
if ((count > 1) && (count % 2))
mediantot = (stats[count / 2].time + stats[count / 2 + 1].time) / 2;
else
mediantot = stats[count / 2].time;
printf("\nConnection Times (ms)\n");
/*
* Reduce stats from apr time to milliseconds
*/
mincon = ap_round_ms(mincon);
mind = ap_round_ms(mind);
minwait = ap_round_ms(minwait);
mintot = ap_round_ms(mintot);
meancon = ap_round_ms(meancon);
meand = ap_round_ms(meand);
meanwait = ap_round_ms(meanwait);
meantot = ap_round_ms(meantot);
mediancon = ap_round_ms(mediancon);
mediand = ap_round_ms(mediand);
medianwait = ap_round_ms(medianwait);
mediantot = ap_round_ms(mediantot);
maxcon = ap_round_ms(maxcon);
maxd = ap_round_ms(maxd);
maxwait = ap_round_ms(maxwait);
maxtot = ap_round_ms(maxtot);
sdcon = ap_double_ms(sdcon);
sdd = ap_double_ms(sdd);
sdwait = ap_double_ms(sdwait);
sdtot = ap_double_ms(sdtot);
if (confidence) {
#define CONF_FMT_STRING "%5" APR_TIME_T_FMT " %4" APR_TIME_T_FMT " %5.1f %6" APR_TIME_T_FMT " %7" APR_TIME_T_FMT "\n"
printf(" min mean[+/-sd] median max\n");
printf("Connect: " CONF_FMT_STRING,
mincon, meancon, sdcon, mediancon, maxcon);
printf("Processing: " CONF_FMT_STRING,
mind, meand, sdd, mediand, maxd);
printf("Waiting: " CONF_FMT_STRING,
minwait, meanwait, sdwait, medianwait, maxwait);
printf("Total: " CONF_FMT_STRING,
mintot, meantot, sdtot, mediantot, maxtot);
#undef CONF_FMT_STRING
#define SANE(what,mean,median,sd) \
{ \
double d = (double)mean - median; \
if (d < 0) d = -d; \
if (d > 2 * sd ) \
printf("ERROR: The median and mean for " what " are more than twice the standard\n" \
" deviation apart. These results are NOT reliable.\n"); \
else if (d > sd ) \
printf("WARNING: The median and mean for " what " are not within a normal deviation\n" \
" These results are probably not that reliable.\n"); \
}
SANE("the initial connection time", meancon, mediancon, sdcon);
SANE("the processing time", meand, mediand, sdd);
SANE("the waiting time", meanwait, medianwait, sdwait);
SANE("the total time", meantot, mediantot, sdtot);
}
else {
printf(" min avg max\n");
#define CONF_FMT_STRING "%5" APR_TIME_T_FMT " %5" APR_TIME_T_FMT "%5" APR_TIME_T_FMT "\n"
printf("Connect: " CONF_FMT_STRING, mincon, meancon, maxcon);
printf("Processing: " CONF_FMT_STRING, mind, meand, maxd);
printf("Waiting: " CONF_FMT_STRING, minwait, meanwait, maxwait);
printf("Total: " CONF_FMT_STRING, mintot, meantot, maxtot);
#undef CONF_FMT_STRING
}
/* Sorted on total connect times */
if (percentile && (count > 1)) {
printf("\nPercentage of the requests served within a certain time (ms)\n");
for (i = 0; i < sizeof(percs) / sizeof(int); i++) {
if (percs[i] <= 0)
printf(" 0%% <0> (never)\n");
else if (percs[i] >= 100)
printf(" 100%% %5" APR_TIME_T_FMT " (longest request)\n",
ap_round_ms(stats[count - 1].time));
else
printf(" %d%% %5" APR_TIME_T_FMT "\n", percs[i],
ap_round_ms(stats[(unsigned long)count * percs[i] / 100].time));
}
}
if (csvperc) {
FILE *out = fopen(csvperc, "w");
if (!out) {
perror("Cannot open CSV output file");
exit(1);
}
fprintf(out, "" "Percentage served" "," "Time in ms" "\n");
for (i = 0; i <= 100; i++) {
double t;
if (i == 0)
t = ap_double_ms(stats[0].time);
else if (i == 100)
t = ap_double_ms(stats[count - 1].time);
else
t = ap_double_ms(stats[(unsigned long) (0.5 + (double)count * i / 100.0)].time);
fprintf(out, "%" APR_INT64_T_FMT ",%.3f\n", i, t);
}
fclose(out);
}
if (gnuplot) {
char tmstring[APR_CTIME_LEN];
FILE *out = fopen(gnuplot, "w");
if (!out) {
perror("Cannot open gnuplot output file");
exit(1);
}
fprintf(out, "starttime\tseconds\tctime\tdtime\tttime\twait\n");
for (i = 0; i < count; i++) {
(void) apr_ctime(tmstring, stats[i].starttime);
fprintf(out, "%s\t%" APR_TIME_T_FMT "\t%" APR_TIME_T_FMT
"\t%" APR_TIME_T_FMT "\t%" APR_TIME_T_FMT
"\t%" APR_TIME_T_FMT "\n", tmstring,
apr_time_sec(stats[i].starttime),
ap_round_ms(stats[i].ctime),
ap_round_ms(stats[i].time - stats[i].ctime),
ap_round_ms(stats[i].time),
ap_round_ms(stats[i].waittime));
}
fclose(out);
}
}
fflush(stdout);
}