/*
httperf -- a tool for measuring web server performance
Copyright (C) 2000 Hewlett-Packard Company
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of httperf, a web server performance measurment
tool.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA
*/
/* Session statistics collector. */
#include <assert.h>
#include <float.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <httperf.h>
#include <call.h>
#include <event.h>
#include <session.h>
#include <stats.h>
static struct
{
u_int num_rate_samples;
u_int num_completed_since_last_sample;
Time rate_sum;
Time rate_sum2;
Time rate_min;
Time rate_max;
u_int num_completed;
Time lifetime_sum;
u_int num_failed;
Time failtime_sum;
u_int num_conns; /* total # of connections on successful sessions */
/* session-length histogram: */
u_int longest_session;
u_int len_hist_alloced;
u_int *len_hist;
}
st;
#define SESS_PRIVATE_DATA(c) \
((Sess_Private_Data *) ((char *)(c) + sess_private_data_offset))
typedef struct Sess_Private_Data
{
u_int num_calls_completed; /* how many calls completed? */
u_int num_conns; /* # of connections on this session */
Time birth_time; /* when this session got created */
}
Sess_Private_Data;
static size_t sess_private_data_offset = -1;
static void
perf_sample (Event_Type et, Object *obj, Any_Type reg_arg, Any_Type call_arg)
{
Time weight = call_arg.d;
double rate;
assert (et == EV_PERF_SAMPLE);
rate = weight*st.num_completed_since_last_sample;
st.num_completed_since_last_sample = 0;
if (verbose)
printf ("session-rate = %-8.1f\n", rate);
++st.num_rate_samples;
st.rate_sum += rate;
st.rate_sum2 += SQUARE (rate);
if (rate < st.rate_min)
st.rate_min = rate;
if (rate > st.rate_max)
st.rate_max = rate;
}
static void
sess_created (Event_Type et, Object *obj, Any_Type regarg, Any_Type callarg)
{
Sess_Private_Data *priv;
Sess *sess;
assert (et == EV_SESS_NEW && object_is_sess (obj));
sess = (Sess *) obj;
priv = SESS_PRIVATE_DATA (sess);
priv->birth_time = timer_now ();
}
static void
sess_destroyed (Event_Type et, Object *obj, Any_Type regarg, Any_Type callarg)
{
size_t old_size, new_size;
Sess_Private_Data *priv;
Sess *sess;
Time delta, now = timer_now ();
assert (et == EV_SESS_DESTROYED && object_is_sess (obj));
sess = (Sess *) obj;
priv = SESS_PRIVATE_DATA (sess);
delta = (now - priv->birth_time);
if (sess->failed)
{
++st.num_failed;
st.failtime_sum += delta;
}
else
{
st.num_conns += priv->num_conns;
++st.num_completed_since_last_sample;
++st.num_completed;
st.lifetime_sum += delta;
}
if (priv->num_calls_completed > st.longest_session)
{
st.longest_session = priv->num_calls_completed;
if (st.longest_session >= st.len_hist_alloced)
{
old_size = st.len_hist_alloced*sizeof (st.len_hist[0]);
st.len_hist_alloced = st.longest_session + 16;
new_size = st.len_hist_alloced*sizeof (st.len_hist[0]);
st.len_hist = realloc (st.len_hist, new_size);
if (!st.len_hist)
{
fprintf (stderr, "%s.sess_stat: Out of memory\n", prog_name);
exit (1);
}
memset ((char *) st.len_hist + old_size, 0, new_size - old_size);
}
}
++st.len_hist[priv->num_calls_completed];
}
static void
conn_connected (Event_Type et, Object *obj, Any_Type regarg, Any_Type callarg)
{
Sess_Private_Data *priv;
Sess *sess;
Conn *conn;
assert (et == EV_CONN_CONNECTED && object_is_conn (obj));
conn = (Conn *) obj;
sess = session_get_sess_from_conn (conn);
priv = SESS_PRIVATE_DATA (sess);
++priv->num_conns;
}
static void
call_done (Event_Type et, Object *obj, Any_Type regarg, Any_Type callarg)
{
Sess_Private_Data *priv;
Sess *sess;
Call *call;
assert (et == EV_CALL_RECV_STOP && object_is_call (obj));
call = (Call *) obj;
sess = session_get_sess_from_call (call);
priv = SESS_PRIVATE_DATA (sess);
++priv->num_calls_completed;
}
static void
init (void)
{
Any_Type arg;
size_t size;
sess_private_data_offset = object_expand (OBJ_SESS,
sizeof (Sess_Private_Data));
st.len_hist_alloced = 16;
size = st.len_hist_alloced*sizeof (st.len_hist[0]);
st.len_hist = malloc (size);
memset (st.len_hist, 0, size);
st.rate_min = DBL_MAX;
if (!st.len_hist)
{
fprintf (stderr, "%s.sess_stat: Out of memory\n", prog_name);
exit (1);
}
arg.l = 0;
event_register_handler (EV_PERF_SAMPLE, perf_sample, arg);
event_register_handler (EV_SESS_NEW, sess_created, arg);
event_register_handler (EV_SESS_DESTROYED, sess_destroyed, arg);
event_register_handler (EV_CONN_CONNECTED, conn_connected, arg);
event_register_handler (EV_CALL_RECV_STOP, call_done, arg);
}
static void
dump (void)
{
double min, avg, stddev, delta;
int i;
delta = test_time_stop - test_time_start;
avg = 0;
stddev = 0;
if (delta > 0)
avg = st.num_completed / delta;
if (st.num_rate_samples > 1)
stddev = STDDEV (st.rate_sum, st.rate_sum2, st.num_rate_samples);
if (st.num_rate_samples > 0)
min = st.rate_min;
else
min = 0.0;
printf ("\nSession rate [sess/s]: min %.2f avg %.2f max %.2f "
"stddev %.2f (%u/%u)\n", min, avg, st.rate_max, stddev,
st.num_completed, st.num_completed + st.num_failed);
printf ("Session: avg %.2f connections/session\n",
st.num_completed > 0 ? st.num_conns/(double) st.num_completed : 0.0);
avg = 0.0;
if (st.num_completed > 0)
avg = st.lifetime_sum/st.num_completed;
printf ("Session lifetime [s]: %.1f\n", avg);
avg = 0.0;
if (st.num_failed > 0)
avg = st.failtime_sum/st.num_failed;
printf ("Session failtime [s]: %.1f\n", avg);
printf ("Session length histogram:");
for (i = 0; i <= st.longest_session; ++i)
printf (" %u", st.len_hist[i]);
putchar ('\n');
}
Stat_Collector session_stat =
{
"collects session-related statistics",
init,
no_op,
no_op,
dump
};
syntax highlighted by Code2HTML, v. 0.9.1