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