"Fossies" - the Fresh Open Source Software Archive

Member "httperf-0.9.0/src/stat/basic.c" (7 Apr 2007, 14627 Bytes) of package /linux/www/old/httperf-0.9.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "basic.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2     httperf -- a tool for measuring web server performance
    3     Copyright 2000-2007 Hewlett-Packard Company and Contributors listed in
    4     AUTHORS file. Originally contributed by David Mosberger-Tang
    5 
    6     This file is part of httperf, a web server performance measurment
    7     tool.
    8 
    9     This program is free software; you can redistribute it and/or
   10     modify it under the terms of the GNU General Public License as
   11     published by the Free Software Foundation; either version 2 of the
   12     License, or (at your option) any later version.
   13     
   14     In addition, as a special exception, the copyright holders give
   15     permission to link the code of this work with the OpenSSL project's
   16     "OpenSSL" library (or with modified versions of it that use the same
   17     license as the "OpenSSL" library), and distribute linked combinations
   18     including the two.  You must obey the GNU General Public License in
   19     all respects for all of the code used other than "OpenSSL".  If you
   20     modify this file, you may extend this exception to your version of the
   21     file, but you are not obligated to do so.  If you do not wish to do
   22     so, delete this exception statement from your version.
   23 
   24     This program is distributed in the hope that it will be useful,
   25     but WITHOUT ANY WARRANTY; without even the implied warranty of
   26     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   27     General Public License for more details.
   28 
   29     You should have received a copy of the GNU General Public License
   30     along with this program; if not, write to the Free Software
   31     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  
   32     02110-1301, USA
   33 */
   34 
   35 /* Basic statistics collector.  */
   36 
   37 #include "config.h"
   38 
   39 #include <assert.h>
   40 #include <errno.h>
   41 #include <float.h>
   42 #include <stdio.h>
   43 
   44 #include <httperf.h>
   45 #include <call.h>
   46 #include <event.h>
   47 #include <stats.h>
   48 
   49 /* Increase this if it does not cover at least 50% of all response
   50    times.  */
   51 #define MAX_LIFETIME    100.0       /* max. conn. lifetime in seconds */
   52 #define BIN_WIDTH   1e-3
   53 #define NUM_BINS    ((u_int) (MAX_LIFETIME / BIN_WIDTH))
   54 
   55 static struct
   56   {
   57     u_int num_conns_issued; /* total # of connections issued */
   58     u_int num_replies[6];   /* completion count per status class */
   59     u_int num_client_timeouts;  /* # of client timeouts */
   60     u_int num_sock_fdunavail;   /* # of times out of filedescriptors */
   61     u_int num_sock_ftabfull;    /* # of times file table was full */
   62     u_int num_sock_refused; /* # of ECONNREFUSED */
   63     u_int num_sock_reset;   /* # of ECONNRESET */
   64     u_int num_sock_timeouts;    /* # of ETIMEDOUT */
   65     u_int num_sock_addrunavail;/* # of EADDRNOTAVAIL */
   66     u_int num_other_errors; /* # of other errors */
   67     u_int max_conns;        /* max # of concurrent connections */
   68 
   69     u_int num_lifetimes;
   70     Time conn_lifetime_sum; /* sum of connection lifetimes */
   71     Time conn_lifetime_sum2;    /* sum of connection lifetimes squared */
   72     Time conn_lifetime_min; /* minimum connection lifetime */
   73     Time conn_lifetime_max; /* maximum connection lifetime */
   74 
   75     u_int num_reply_rates;
   76     Time reply_rate_sum;
   77     Time reply_rate_sum2;
   78     Time reply_rate_min;
   79     Time reply_rate_max;
   80 
   81     u_int num_connects;     /* # of completed connect()s */
   82     Time conn_connect_sum;  /* sum of connect times */
   83 
   84     u_int num_responses;
   85     Time call_response_sum; /* sum of response times */
   86 
   87     Time call_xfer_sum;     /* sum of response times */
   88 
   89     u_int num_sent;     /* # of requests sent */
   90     size_t req_bytes_sent;
   91 
   92     u_int num_received;     /* # of replies received */
   93     u_wide hdr_bytes_received;  /* sum of all header bytes */
   94     u_wide reply_bytes_received;    /* sum of all data bytes */
   95     u_wide footer_bytes_received;   /* sum of all footer bytes */
   96 
   97     u_int conn_lifetime_hist[NUM_BINS]; /* histogram of connection lifetimes */
   98   }
   99 basic;
  100 
  101 static u_int num_active_conns;
  102 static u_int num_replies;   /* # of replies received in this interval */
  103 
  104 static void
  105 perf_sample (Event_Type et, Object *obj, Any_Type reg_arg, Any_Type call_arg)
  106 {
  107   Time weight = call_arg.d;
  108   double rate;
  109 
  110   assert (et == EV_PERF_SAMPLE);
  111 
  112   rate = weight*num_replies;
  113 
  114   if (verbose)
  115     printf ("reply-rate = %-8.1f\n", rate);
  116 
  117   basic.reply_rate_sum += rate;
  118   basic.reply_rate_sum2 += SQUARE (rate);
  119   if (rate < basic.reply_rate_min)
  120     basic.reply_rate_min = rate;
  121   if (rate > basic.reply_rate_max)
  122     basic.reply_rate_max = rate;
  123   ++basic.num_reply_rates;
  124 
  125   /* prepare for next sample interval: */
  126   num_replies = 0;
  127 }
  128 
  129 static void
  130 conn_timeout (Event_Type et, Object *obj, Any_Type reg_arg, Any_Type call_arg)
  131 {
  132   assert (et == EV_CONN_TIMEOUT);
  133 
  134   ++basic.num_client_timeouts;
  135 }
  136 
  137 static void
  138 conn_fail (Event_Type et, Object *obj, Any_Type reg_arg, Any_Type call_arg)
  139 {
  140   static int first_time = 1;
  141   int err = call_arg.i;
  142 
  143   assert (et == EV_CONN_FAILED);
  144 
  145   switch (err)
  146     {
  147 #ifdef __linux__
  148     case EINVAL:    /* Linux has a strange way of saying "out of fds"... */
  149 #endif
  150     case EMFILE:    ++basic.num_sock_fdunavail; break;
  151     case ENFILE:    ++basic.num_sock_ftabfull; break;
  152     case ECONNREFUSED:  ++basic.num_sock_refused; break;
  153     case ETIMEDOUT: ++basic.num_sock_timeouts; break;
  154 
  155     case EPIPE:
  156     case ECONNRESET:
  157       ++basic.num_sock_reset;
  158       break;
  159 
  160     default:
  161       if (first_time)
  162     {
  163       first_time = 0;
  164       fprintf (stderr, "%s: connection failed with unexpected error %d\n",
  165            prog_name, errno);
  166     }
  167       ++basic.num_other_errors;
  168       break;
  169     }
  170 }
  171 
  172 static void
  173 conn_created (Event_Type et, Object *obj, Any_Type reg_arg, Any_Type c_arg)
  174 {
  175   ++num_active_conns;
  176   if (num_active_conns > basic.max_conns)
  177     basic.max_conns = num_active_conns;
  178 }
  179 
  180 static void
  181 conn_connecting (Event_Type et, Object *obj, Any_Type reg_arg, Any_Type c_arg)
  182 {
  183   Conn *s = (Conn *) obj;
  184 
  185   assert (et == EV_CONN_CONNECTING && object_is_conn (s));
  186 
  187   s->basic.time_connect_start = timer_now ();
  188   ++basic.num_conns_issued;
  189 }
  190 
  191 static void
  192 conn_connected (Event_Type et, Object *obj, Any_Type reg_arg,
  193         Any_Type call_arg)
  194 {
  195   Conn *s = (Conn *) obj;
  196 
  197   assert (et == EV_CONN_CONNECTED && object_is_conn (s));
  198   basic.conn_connect_sum += timer_now () - s->basic.time_connect_start;
  199   ++basic.num_connects;
  200 }
  201 
  202 static void
  203 conn_destroyed (Event_Type et, Object *obj, Any_Type reg_arg, Any_Type c_arg)
  204 {
  205   Conn *s = (Conn *) obj;
  206   Time lifetime;
  207   u_int bin;
  208 
  209   assert (et == EV_CONN_DESTROYED && object_is_conn (s)
  210       && num_active_conns > 0);
  211 
  212   if (s->basic.num_calls_completed > 0)
  213     {
  214       lifetime = timer_now () - s->basic.time_connect_start;
  215       basic.conn_lifetime_sum += lifetime;
  216       basic.conn_lifetime_sum2 += SQUARE (lifetime);
  217       if (lifetime < basic.conn_lifetime_min)
  218     basic.conn_lifetime_min = lifetime;
  219       if (lifetime > basic.conn_lifetime_max)
  220     basic.conn_lifetime_max = lifetime;
  221       ++basic.num_lifetimes;
  222 
  223       bin = lifetime*NUM_BINS/MAX_LIFETIME;
  224       if (bin >= NUM_BINS)
  225     bin = NUM_BINS;
  226       ++basic.conn_lifetime_hist[bin];
  227     }
  228   --num_active_conns;
  229 }
  230 
  231 static void
  232 send_start (Event_Type et, Object *obj, Any_Type reg_arg, Any_Type call_arg)
  233 {
  234   Call *c = (Call *) obj;
  235 
  236   assert (et == EV_CALL_SEND_START && object_is_call (c));
  237 
  238   c->basic.time_send_start = timer_now ();
  239 }
  240 
  241 static void
  242 send_stop (Event_Type et, Object *obj, Any_Type reg_arg, Any_Type call_arg)
  243 {
  244   Call *c = (Call *) obj;
  245 
  246   assert (et == EV_CALL_SEND_STOP && object_is_call (c));
  247 
  248   basic.req_bytes_sent += c->req.size;
  249   ++basic.num_sent;
  250 }
  251 
  252 static void
  253 recv_start (Event_Type et, Object *obj, Any_Type reg_arg, Any_Type call_arg)
  254 {
  255   Call *c = (Call *) obj;
  256   Time now;
  257 
  258   assert (et == EV_CALL_RECV_START && object_is_call (c));
  259 
  260   now = timer_now ();
  261 
  262   basic.call_response_sum += now - c->basic.time_send_start;
  263   c->basic.time_recv_start = now;
  264   ++basic.num_responses;
  265 }
  266 
  267 static void
  268 recv_stop (Event_Type et, Object *obj, Any_Type reg_arg, Any_Type call_arg)
  269 {
  270   Call *c = (Call *) obj;
  271   int index;
  272 
  273   assert (et == EV_CALL_RECV_STOP && object_is_call (c));
  274   assert (c->basic.time_recv_start > 0);
  275 
  276   basic.call_xfer_sum += timer_now () - c->basic.time_recv_start;
  277 
  278   basic.hdr_bytes_received += c->reply.header_bytes;
  279   basic.reply_bytes_received += c->reply.content_bytes;
  280   basic.footer_bytes_received += c->reply.footer_bytes;
  281 
  282   index = (c->reply.status / 100);
  283   assert ((unsigned) index < NELEMS (basic.num_replies));
  284   ++basic.num_replies[index];
  285   ++num_replies;
  286 
  287   ++c->conn->basic.num_calls_completed;
  288 }
  289 
  290 static void
  291 init (void)
  292 {
  293   Any_Type arg;
  294 
  295   basic.conn_lifetime_min = DBL_MAX;
  296   basic.reply_rate_min = DBL_MAX;
  297 
  298   arg.l = 0;
  299   event_register_handler (EV_PERF_SAMPLE, perf_sample, arg);
  300   event_register_handler (EV_CONN_FAILED, conn_fail, arg);
  301   event_register_handler (EV_CONN_TIMEOUT, conn_timeout, arg);
  302   event_register_handler (EV_CONN_NEW, conn_created, arg);
  303   event_register_handler (EV_CONN_CONNECTING, conn_connecting, arg);
  304   event_register_handler (EV_CONN_CONNECTED, conn_connected, arg);
  305   event_register_handler (EV_CONN_DESTROYED, conn_destroyed, arg);
  306   event_register_handler (EV_CALL_SEND_START, send_start, arg);
  307   event_register_handler (EV_CALL_SEND_STOP, send_stop, arg);
  308   event_register_handler (EV_CALL_RECV_START, recv_start, arg);
  309   event_register_handler (EV_CALL_RECV_STOP, recv_stop, arg);
  310 }
  311 
  312 static void
  313 dump (void)
  314 {
  315   Time conn_period = 0.0, call_period = 0.0;
  316   Time conn_time = 0.0, resp_time = 0.0, xfer_time = 0.0;
  317   Time call_size = 0.0, hdr_size = 0.0, reply_size = 0.0, footer_size = 0.0;
  318   Time lifetime_avg = 0.0, lifetime_stddev = 0.0, lifetime_median = 0.0;
  319   double reply_rate_avg = 0.0, reply_rate_stddev = 0.0;
  320   int i, total_replies = 0;
  321   Time delta, user, sys;
  322   u_wide total_size;
  323   Time time;
  324   u_int n;
  325 
  326   for (i = 1; i < NELEMS (basic.num_replies); ++i)
  327     total_replies += basic.num_replies[i];
  328 
  329   delta = test_time_stop - test_time_start;
  330 
  331   if (verbose > 1)
  332     {
  333       printf ("\nConnection lifetime histogram (time in ms):\n");
  334       for (i = 0; i < NUM_BINS; ++i)
  335     if (basic.conn_lifetime_hist[i])
  336       {
  337         if (i > 0 && basic.conn_lifetime_hist[i - 1] == 0)
  338           printf ("%14c\n", ':');
  339         time = (i + 0.5)*BIN_WIDTH;
  340         printf ("%16.1f %u\n", 1e3*time, basic.conn_lifetime_hist[i]);
  341       }
  342     }
  343 
  344   printf ("\nTotal: connections %u requests %u replies %u "
  345       "test-duration %.3f s\n",
  346       basic.num_conns_issued, basic.num_sent, total_replies,
  347       delta);
  348 
  349   putchar ('\n');
  350 
  351   if (basic.num_conns_issued)
  352     conn_period = delta/basic.num_conns_issued;
  353   printf ("Connection rate: %.1f conn/s (%.1f ms/conn, "
  354       "<=%u concurrent connections)\n",
  355       basic.num_conns_issued / delta, 1e3*conn_period, basic.max_conns);
  356 
  357   if (basic.num_lifetimes > 0)
  358     {
  359       lifetime_avg = (basic.conn_lifetime_sum / basic.num_lifetimes);
  360       if (basic.num_lifetimes > 1)
  361     lifetime_stddev = STDDEV (basic.conn_lifetime_sum,
  362                   basic.conn_lifetime_sum2,
  363                   basic.num_lifetimes);
  364       n = 0;
  365       for (i = 0; i < NUM_BINS; ++i)
  366     {
  367       n += basic.conn_lifetime_hist[i];
  368       if (n >= 0.5*basic.num_lifetimes)
  369         {
  370           lifetime_median = (i + 0.5)*BIN_WIDTH;
  371           break;
  372         }
  373     }
  374     }  
  375   printf ("Connection time [ms]: min %.1f avg %.1f max %.1f median %.1f "
  376       "stddev %.1f\n",
  377       basic.num_lifetimes > 0 ? 1e3 * basic.conn_lifetime_min : 0.0,
  378       1e3 * lifetime_avg,
  379       1e3 * basic.conn_lifetime_max, 1e3 * lifetime_median,
  380       1e3 * lifetime_stddev);
  381   if (basic.num_connects > 0)
  382     conn_time = basic.conn_connect_sum / basic.num_connects;
  383   printf ("Connection time [ms]: connect %.1f\n", 1e3*conn_time);
  384   printf ("Connection length [replies/conn]: %.3f\n",
  385       basic.num_lifetimes > 0
  386       ? total_replies/ (double) basic.num_lifetimes : 0.0);
  387   putchar ('\n');
  388 
  389   if (basic.num_sent > 0)
  390     call_period = delta/basic.num_sent;
  391   printf ("Request rate: %.1f req/s (%.1f ms/req)\n",
  392       basic.num_sent / delta, 1e3*call_period);
  393 
  394   if (basic.num_sent)
  395     call_size = basic.req_bytes_sent / basic.num_sent;
  396   printf ("Request size [B]: %.1f\n", call_size);
  397 
  398   putchar ('\n');
  399 
  400   if (basic.num_reply_rates > 0)
  401     {
  402       reply_rate_avg = (basic.reply_rate_sum / basic.num_reply_rates);
  403       if (basic.num_reply_rates > 1)
  404     reply_rate_stddev = STDDEV (basic.reply_rate_sum,
  405                     basic.reply_rate_sum2,
  406                     basic.num_reply_rates);
  407     }
  408   printf ("Reply rate [replies/s]: min %.1f avg %.1f max %.1f stddev %.1f "
  409       "(%u samples)\n",
  410       basic.num_reply_rates > 0 ? basic.reply_rate_min : 0.0,
  411       reply_rate_avg, basic.reply_rate_max,
  412       reply_rate_stddev, basic.num_reply_rates);
  413 
  414   if (basic.num_responses > 0)
  415     resp_time = basic.call_response_sum / basic.num_responses;
  416   if (total_replies > 0)
  417     xfer_time = basic.call_xfer_sum / total_replies;
  418   printf ("Reply time [ms]: response %.1f transfer %.1f\n",
  419       1e3*resp_time, 1e3*xfer_time);
  420 
  421   if (total_replies)
  422     {
  423       hdr_size = basic.hdr_bytes_received / total_replies;
  424       reply_size = basic.reply_bytes_received / total_replies;
  425       footer_size = basic.footer_bytes_received / total_replies;
  426     }
  427   printf ("Reply size [B]: header %.1f content %.1f footer %.1f "
  428       "(total %.1f)\n", hdr_size, reply_size, footer_size,
  429       hdr_size + reply_size + footer_size);
  430 
  431   printf ("Reply status: 1xx=%u 2xx=%u 3xx=%u 4xx=%u 5xx=%u\n",
  432       basic.num_replies[1], basic.num_replies[2], basic.num_replies[3],
  433       basic.num_replies[4], basic.num_replies[5]);
  434 
  435   putchar ('\n');
  436 
  437   user = (TV_TO_SEC (test_rusage_stop.ru_utime)
  438       - TV_TO_SEC (test_rusage_start.ru_utime));
  439   sys = (TV_TO_SEC (test_rusage_stop.ru_stime)
  440       - TV_TO_SEC (test_rusage_start.ru_stime));
  441   printf ("CPU time [s]: user %.2f system %.2f (user %.1f%% system %.1f%% "
  442       "total %.1f%%)\n", user, sys, 100.0*user/delta, 100.0*sys/delta,
  443       100.0*(user + sys)/delta);
  444 
  445   total_size = (basic.req_bytes_sent
  446         + basic.hdr_bytes_received + basic.reply_bytes_received);
  447   printf ("Net I/O: %.1f KB/s (%.1f*10^6 bps)\n",
  448       total_size/delta / 1024.0, 8e-6*total_size/delta);
  449 
  450   putchar ('\n');
  451 
  452   printf ("Errors: total %u client-timo %u socket-timo %u "
  453       "connrefused %u connreset %u\n"
  454       "Errors: fd-unavail %u addrunavail %u ftab-full %u other %u\n",
  455       (basic.num_client_timeouts + basic.num_sock_timeouts
  456        + basic.num_sock_fdunavail + basic.num_sock_ftabfull
  457        + basic.num_sock_refused + basic.num_sock_reset
  458        + basic.num_sock_addrunavail + basic.num_other_errors),
  459       basic.num_client_timeouts, basic.num_sock_timeouts,
  460       basic.num_sock_refused, basic.num_sock_reset,
  461       basic.num_sock_fdunavail, basic.num_sock_addrunavail,
  462       basic.num_sock_ftabfull, basic.num_other_errors);
  463 }
  464 
  465 Stat_Collector stats_basic =
  466   {
  467     "Basic statistics",
  468     init,
  469     no_op,
  470     no_op,
  471     dump
  472   };