static void output_results()

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);
}