static void output_results()

in wb/wb.c [1862:2216]


static void output_results(int sig)
{
    double timetaken;

    if (sig) {
        lasttime = apr_time_now();  /* record final time if interrupted */
    }
    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 && ssl_info) {
        printf("SSL/TLS Protocol:       %s\n", ssl_info);
    }
    if (is_ssl && ssl_tmp_key) {
        printf("Server Temp Key:        %s\n", ssl_tmp_key);
    }
#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", doclen);
    printf("\n");
    printf("Concurrency Level:      %d\n", concurrency);
    printf("Time taken for tests:   %.3f seconds\n", timetaken);
    printf("Complete requests:      %d\n", done);

#ifdef _WAF_BENCH_ // print color text for bad results
    //if (bad > 0) 
        printf("\033[0;31m"); // RED color for failed requests
#endif //_WAF_BENCH_ print color text

    printf("Failed requests:        %d\n", bad);
    if (bad)
        printf("   (Connect: %d, Receive: %d, Length: %d, Exceptions: %d)\n",
            err_conn, err_recv, err_length, err_except);
    if (epipe)
        printf("Write errors:           %d\n", epipe);
    if (err_response) {
        printf("Non-2xx responses:      %d\n", err_response);
        for (unsigned int i = 0; i < sizeof(respcodes) / sizeof(respcodes[0]); i++) {
            if (respcodes[i] > 0) {
                printf("%d responses: %d\n", i, respcodes[i]);
            }
        }
    }
#ifdef _WAF_BENCH_ // return to no-color
    //if (bad > 0) 
        printf("\033[0m"); // no color
#endif //_WAF_BENCH_ return to no-color
    if (keepalive)
        printf("Keep-Alive requests:    %d\n", doneka);
    printf("Total transferred:      %" APR_INT64_T_FMT " bytes\n", totalread);
    if (send_body)
        printf("Total body sent:        %" APR_INT64_T_FMT "\n",
               totalposted);
    printf("HTML transferred:       %" APR_INT64_T_FMT " bytes\n", totalbread);

    /* avoid divide by zero */
    if (timetaken && done) {
        
#ifdef _WAF_BENCH_ // print color text
        printf("\033[1;33m"); // Yellow color for RPS numbers
#endif //_WAF_BENCH_ print color text

        printf("Requests per second:    %.2f [#/sec] (mean)\n",
               (double) done / timetaken);
               
#ifdef _WAF_BENCH_ // print no-color text
        printf("\033[0m"); // no color
#endif //_WAF_BENCH_ print no-color text
        
        printf("Time per request:       %.3f [ms] (mean)\n",
               (double) concurrency * timetaken * 1000 / done);
#ifdef _WAF_BENCH_ // when concurrency == 1, we can avoid print duplicated results
        if (concurrency > 1)
#endif //_WAF_BENCH_ when concurrency == 1, we can avoid print duplicated results
        printf("Time per request:       %.3f [ms] (mean, across all concurrent requests)\n",
               (double) timetaken * 1000 / done);
        printf("Transfer rate:          %.2f [Kbytes/sec] received\n",
               (double) totalread / 1024 / timetaken);
        if (send_body) {
            printf("                        %.2f kb/s sent\n",
               (double) totalposted / 1024 / timetaken);
            printf("                        %.2f kb/s total\n",
               (double) (totalread + totalposted) / 1024 / timetaken);
        }
    }

#ifdef _WAF_BENCH_ // real sent# might be greater than g_stats_window;
    done = ap_min(done, g_stats_window);
    printf("Total samples of stats: %d",done);
#endif //_WAF_BENCH_ real sent# might be greater than g_stats_window;

    if (done > 0) {
        /* work out connection times */
        int i;
        apr_time_t totalcon = 0, total = 0, totald = 0, totalwait = 0;
        apr_time_t meancon, meantot, meand, meanwait;
        apr_interval_time_t mincon = AB_MAX, mintot = AB_MAX, mind = AB_MAX,
                            minwait = AB_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 < done; 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 / done;
        meantot = total / done;
        meand = totald / done;
        meanwait = totalwait / done;

        /* calculating the sample variance: the sum of the squared deviations, divided by n-1 */
        for (i = 0; i < done; 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 = (done > 1) ? sqrt(sdtot / (done - 1)) : 0;
        sdcon = (done > 1) ? sqrt(sdcon / (done - 1)) : 0;
        sdd = (done > 1) ? sqrt(sdd / (done - 1)) : 0;
        sdwait = (done > 1) ? sqrt(sdwait / (done - 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, done, sizeof(struct data),
              (int (*) (const void *, const void *)) compradre);
        if ((done > 1) && (done % 2))
            mediancon = (stats[done / 2].ctime + stats[done / 2 + 1].ctime) / 2;
        else
            mediancon = stats[done / 2].ctime;

        qsort(stats, done, sizeof(struct data),
              (int (*) (const void *, const void *)) compri);
        if ((done > 1) && (done % 2))
            mediand = (stats[done / 2].time + stats[done / 2 + 1].time \
            -stats[done / 2].ctime - stats[done / 2 + 1].ctime) / 2;
        else
            mediand = stats[done / 2].time - stats[done / 2].ctime;

        qsort(stats, done, sizeof(struct data),
              (int (*) (const void *, const void *)) compwait);
        if ((done > 1) && (done % 2))
            medianwait = (stats[done / 2].waittime + stats[done / 2 + 1].waittime) / 2;
        else
            medianwait = stats[done / 2].waittime;

        qsort(stats, done, sizeof(struct data),
              (int (*) (const void *, const void *)) comprando);
        if ((done > 1) && (done % 2))
            mediantot = (stats[done / 2].time + stats[done / 2 + 1].time) / 2;
        else
            mediantot = stats[done / 2].time;
#ifdef _WAF_BENCH_ // microsec-granularity in output-results
        if (g_us_granularity)
            printf("\nConnection Times (us)\n");            
        else {
#endif // _WAF_BENCH_ // microsec-granularity in output-results
            
        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);

#ifdef _WAF_BENCH_ // microsec-granularity in output-results
        }
#endif // _WAF_BENCH_ // microsec-granularity in output-results
        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 && (done > 1)) {
#ifdef _WAF_BENCH_ // microsec-granularity in output-results
            if (g_us_granularity)
            printf("\nPercentage of the requests served within a certain time (us)\n");
            else
#endif // _WAF_BENCH_ // microsec-granularity in output-results
            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",
#ifdef _WAF_BENCH_ // microsec-granularity in output-results
                    g_us_granularity?stats[done - 1].time:
#endif // _WAF_BENCH_ // microsec-granularity in output-results
                           ap_round_ms(stats[done - 1].time));
                else
                    printf("  %d%%  %5" APR_TIME_T_FMT "\n", percs[i],
#ifdef _WAF_BENCH_ // microsec-granularity in output-results
                        g_us_granularity?stats[(unsigned long)done * percs[i] / 100].time:
#endif // _WAF_BENCH_ // microsec-granularity in output-results
                           ap_round_ms(stats[(unsigned long)done * percs[i] / 100].time));
            }
        }
        if (csvperc) {
            FILE *out = fopen(csvperc, "w");
            if (!out) {
                perror("Cannot open CSV output file");
                exit(1);
            }
#ifdef _WAF_BENCH_ // microsec-granularity in output-results
            if (g_us_granularity)
            fprintf(out, "" "Percentage served" "," "Time in us" "\n");
            else
#endif // _WAF_BENCH_ // microsec-granularity in output-results
            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[done - 1].time);
                else
                    t = ap_double_ms(stats[(unsigned long) (0.5 + (double)done * i / 100.0)].time);
#ifdef _WAF_BENCH_ // microsec-granularity in output-results
            if (g_us_granularity)
                t = t * 1000; // convert back to us             
#endif // _WAF_BENCH_ // microsec-granularity in output-results
                fprintf(out, "%d,%.3f\n", i, t);
            }
            fclose(out);
        }
        if (gnuplot) {
            FILE *out = fopen(gnuplot, "w");
            char tmstring[APR_CTIME_LEN];
            if (!out) {
                perror("Cannot open gnuplot output file");
                exit(1);
            }
            fprintf(out, "starttime\tseconds\tctime\tdtime\tttime\twait\n");
            for (i = 0; i < done; 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),
#ifdef _WAF_BENCH_ // microsec-granularity in output-results
                        g_us_granularity?stats[i].ctime:
#endif // _WAF_BENCH_ // microsec-granularity in output-results
                        ap_round_ms(stats[i].ctime),
#ifdef _WAF_BENCH_ // microsec-granularity in output-results
                        g_us_granularity?stats[i].time - stats[i].ctime:
#endif // _WAF_BENCH_ // microsec-granularity in output-results
                        ap_round_ms(stats[i].time - stats[i].ctime),
#ifdef _WAF_BENCH_ // microsec-granularity in output-results
                        g_us_granularity?stats[i].time:
#endif // _WAF_BENCH_ // microsec-granularity in output-results
                        ap_round_ms(stats[i].time),
#ifdef _WAF_BENCH_ // microsec-granularity in output-results
                        g_us_granularity?stats[i].waittime:
#endif // _WAF_BENCH_ // microsec-granularity in output-results
                        ap_round_ms(stats[i].waittime));
            }
            fclose(out);
        }
    }

    if (sig) {
        exit(1);
    }
}