/*
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
*/
/*
Fundamentals:
There are three subsystems to httperf:
1) The load generator which determines what URI is fetched next.
2) The core engine that handles the mechanics of issuing a request.
3) The instrumentation infrastructure that measures various aspects
of the transaction(s).
Since there is considerable potential variation in all three, it
seems like an event-based approach might be ideal in tying the three
together. Ideally, it should be possible to write a new load
generator without modifications to the other subsystems. Similarly,
it should be possible to add instrumentation without requiring
changes to the load generator or http engine.
Axioms:
- The only point at which the client will fall back is if
the client itself is overloaded. There is no point trying
to fix up this case---simply declare defeat and abort the
test.
*/
#include "config.h"
#include <ctype.h>
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <core.h>
#include <event.h>
#include <httperf.h>
#include <conn.h>
#include <timer.h>
#ifdef __FreeBSD__
#include <machine/floatingpoint.h>
#endif
#ifdef HAVE_SSL
# include <openssl/rand.h>
#endif
#define RATE_INTERVAL 5.0
const char *prog_name;
int verbose;
Cmdline_Params param;
Time test_time_start;
Time test_time_stop;
struct rusage test_rusage_start;
struct rusage test_rusage_stop;
size_t object_type_size[OBJ_NUM_TYPES];
#ifdef HAVE_SSL
SSL_CTX *ssl_ctx;
#endif
#ifdef DEBUG
int debug_level;
#endif
static Time perf_sample_start;
static struct option longopts[] =
{
{"add-header", required_argument, (int *) ¶m.additional_header, 0},
{"burst-length", required_argument, ¶m.burst_len, 0},
{"client", required_argument, (int *) ¶m.client, 0},
{"close-with-reset", no_argument, ¶m.close_with_reset, 1},
{"debug", required_argument, 0, 'd'},
{"failure-status", required_argument, ¶m.failure_status, 0},
{"help", no_argument, 0, 'h'},
{"hog", no_argument, ¶m.hog, 1},
{"http-version", required_argument, (int *) ¶m.http_version, 0},
{"max-connections", required_argument, ¶m.max_conns, 0},
{"max-piped-calls", required_argument, ¶m.max_piped, 0},
{"method", required_argument, (int *) ¶m.method, 0},
{"no-host-hdr", no_argument, ¶m.no_host_hdr, 1},
{"num-calls", required_argument, (int *) ¶m.num_calls, 0},
{"num-conns", required_argument, (int *) ¶m.num_conns, 0},
{"period", required_argument, (int *) ¶m.rate.mean_iat, 0},
{"port", required_argument, (int *) ¶m.port, 0},
{"print-reply", optional_argument, ¶m.print_reply, 0},
{"print-request",optional_argument, ¶m.print_request, 0},
{"rate", required_argument, (int *) ¶m.rate, 0},
{"recv-buffer", required_argument, (int *) ¶m.recv_buffer_size, 0},
{"retry-on-failure", no_argument, ¶m.retry_on_failure, 1},
{"send-buffer", required_argument, (int *) ¶m.send_buffer_size, 0},
{"server", required_argument, (int *) ¶m.server, 0},
{"server-name", required_argument, (int *) ¶m.server_name, 0},
{"session-cookies", no_argument, (int *) ¶m.session_cookies, 1},
#ifdef HAVE_SSL
{"ssl", no_argument, ¶m.use_ssl, 1},
{"ssl-ciphers", required_argument, (int *) ¶m.ssl_cipher_list, 0},
{"ssl-no-reuse", no_argument, ¶m.ssl_reuse, 0},
#endif
{"think-timeout",required_argument, (int *) ¶m.think_timeout, 0},
{"timeout", required_argument, (int *) ¶m.timeout, 0},
{"uri", required_argument, (int *) ¶m.uri, 0},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
{"wlog", required_argument, (int *) ¶m.wlog, 0},
{"wsess", required_argument, (int *) ¶m.wsess, 0},
{"wsesslog", required_argument, (int *) ¶m.wsesslog, 0},
{"wsesspage", required_argument, (int *) ¶m.wsesspage, 0},
{"wset", required_argument, (int *) ¶m.wset, 0},
{0, 0, 0, 0}
};
static void
usage (void)
{
printf ("Usage: %s "
"[-hdvV] [--add-header S] [--burst-length N] [--client N/N]\n"
"\t[--close-with-reset] [--debug N] [--failure-status N]\n"
"\t[--help] [--hog] [--http-version S] [--max-connections N]\n"
"\t[--max-piped-calls N] [--method S] [--no-host-hdr]\n"
"\t[--num-calls N] [--num-conns N] [--period [d|u|e]T1[,T2]]\n"
"\t[--port N] "
"[--print-reply [header|body]] [--print-request [header|body]]\n"
"\t[--rate X] [--recv-buffer N] [--retry-on-failure] "
"[--send-buffer N]\n"
"\t[--server S] [--server-name S] [--session-cookies]\n"
#ifdef HAVE_SSL
"\t[--ssl] [--ssl-ciphers L] [--ssl-no-reuse]\n"
#endif
"\t[--think-timeout X] [--timeout X] [--uri S] [--verbose] "
"[--version]\n"
"\t[--wlog y|n,file] [--wsess N,N,X] [--wsesslog N,X,file]\n"
"\t[--wset N,X]\n",
prog_name);
}
void
panic (const char *msg, ...)
{
va_list va;
va_start (va, msg);
vfprintf (stderr, msg, va);
va_end (va);
exit (1);
}
void
no_op (void)
{
}
static void
perf_sample (Timer *t, Any_Type regarg)
{
Any_Type callarg;
callarg.d = 1.0 / (timer_now () - perf_sample_start);
event_signal (EV_PERF_SAMPLE, 0, callarg);
/* prepare for next sample interval: */
perf_sample_start = timer_now ();
timer_schedule (perf_sample, regarg, RATE_INTERVAL);
}
int
main (int argc, char **argv)
{
extern Load_Generator uri_fixed, uri_wlog, uri_wset, conn_rate, call_seq;
extern Load_Generator wsess, wsesslog, wsesspage, sess_cookie, misc;
extern Stat_Collector stats_basic, session_stat;
extern Stat_Collector stats_print_reply;
extern char *optarg;
int session_workload = 0;
int num_gen = 3;
Load_Generator *gen[5] =
{
&call_seq,
&uri_fixed,
&conn_rate,
};
int num_stats = 1;
Stat_Collector *stat[3] =
{
&stats_basic
};
int i, ch, longindex;
u_int minor, major;
char *end, *name;
Any_Type arg;
void *flag;
Time t;
#ifdef __FreeBSD__
/* This works around a bug in earlier versions of FreeBSD that cause
non-finite IEEE arithmetic to cause SIGFPE instead of the
non-finite arithmetic as defined by IEEE. */
fpsetmask (0);
#endif
object_type_size[OBJ_CONN] = sizeof (Conn);
object_type_size[OBJ_CALL] = sizeof (Call);
param.http_version = 0x10001; /* default to HTTP/1.1 */
param.client.id = 0;
param.client.num_clients = 1;
param.server = "localhost";
param.port = -1;
param.uri = "/";
param.num_calls = 1;
param.burst_len = 1;
param.num_conns = 1;
/* These should be set to the minimum of 2*bandwidth*delay and the
maximum request/reply size for single-call connections. */
param.send_buffer_size = 4096;
param.recv_buffer_size = 16384;
param.rate.dist = DETERMINISTIC;
#ifdef HAVE_SSL
param.ssl_reuse = 1;
#endif
/* get program name: */
prog_name = strrchr (argv[0], '/');
if (prog_name)
++prog_name;
else
prog_name = argv[0];
/* process command line options: */
while ((ch = getopt_long (argc, argv, "d:hvV", longopts, &longindex)) >= 0)
{
switch (ch)
{
case 0:
flag = longopts[longindex].flag;
if (flag == ¶m.method)
param.method = optarg;
else if (flag == ¶m.additional_header)
param.additional_header = optarg;
else if (flag == ¶m.num_calls)
{
errno = 0;
param.num_calls = strtoul (optarg, &end, 10);
if (errno == ERANGE || end == optarg || *end)
{
fprintf (stderr, "%s: illegal number of calls %s\n",
prog_name, optarg);
exit (1);
}
}
else if (flag == ¶m.http_version)
{
if (sscanf (optarg, "%u.%u", &major, &minor) != 2)
{
fprintf (stderr, "%s: illegal version number %s\n",
prog_name, optarg);
exit (1);
}
param.http_version = (major << 16) | (minor & 0xffff);
}
else if (flag == ¶m.burst_len)
{
errno = 0;
param.burst_len = strtoul (optarg, &end, 10);
if (errno == ERANGE || end == optarg || *end
|| param.burst_len < 1)
{
fprintf (stderr, "%s: illegal burst-length %s\n",
prog_name, optarg);
exit (1);
}
}
else if (flag == ¶m.failure_status)
{
errno = 0;
param.failure_status = strtoul (optarg, &end, 10);
if (errno == ERANGE || end == optarg || *end
|| param.failure_status <= 0)
{
fprintf (stderr, "%s: illegal failure status %s\n",
prog_name, optarg);
exit (1);
}
}
else if (flag == ¶m.num_conns)
{
errno = 0;
param.num_conns = strtoul (optarg, &end, 10);
if (errno == ERANGE || end == optarg || *end)
{
fprintf (stderr, "%s: illegal number of connections %s\n",
prog_name, optarg);
exit (1);
}
}
else if (flag == ¶m.max_conns)
{
errno = 0;
param.max_conns = strtoul (optarg, &end, 10);
if (errno == ERANGE || end == optarg || *end
|| param.max_conns < 0)
{
fprintf (stderr, "%s: illegal max. # of connection %s\n",
prog_name, optarg);
exit (1);
}
}
else if (flag == ¶m.max_piped)
{
errno = 0;
param.max_piped = strtoul (optarg, &end, 10);
if (errno == ERANGE || end == optarg || *end
|| param.max_piped < 0)
{
fprintf (stderr, "%s: illegal max. # of piped calls %s\n",
prog_name, optarg);
exit (1);
}
}
else if (flag == ¶m.port)
{
errno = 0;
param.port = strtoul (optarg, &end, 10);
if (errno == ERANGE || end == optarg || *end
|| (unsigned) param.port > 0xffff)
{
fprintf (stderr, "%s: illegal port number %s\n",
prog_name, optarg);
exit (1);
}
}
else if (flag == ¶m.print_request || flag == ¶m.print_reply)
{
int val;
if (!optarg)
val = PRINT_HEADER | PRINT_BODY;
else
switch (tolower (optarg[0]))
{
case 'h': val = PRINT_HEADER; break;
case 'b': val = PRINT_BODY; break;
default: val = PRINT_HEADER | PRINT_BODY; break;
}
*(int *) flag = val;
}
else if (flag == ¶m.rate)
{
errno = 0;
param.rate.rate_param = strtod (optarg, &end);
if (errno == ERANGE || end == optarg || *end)
{
fprintf (stderr, "%s: illegal request rate %s\n",
prog_name, optarg);
exit (1);
}
if (param.rate.rate_param <= 0.0)
param.rate.mean_iat = 0.0;
else
param.rate.mean_iat = 1/param.rate.rate_param;
param.rate.dist = DETERMINISTIC;
}
else if (flag == ¶m.rate.mean_iat) /* --period */
{
param.rate.dist = DETERMINISTIC;
if (!isdigit (*optarg))
switch (tolower(*optarg++))
{
case 'd': param.rate.dist = DETERMINISTIC; break;
case 'u': param.rate.dist = UNIFORM; break;
case 'e': param.rate.dist = EXPONENTIAL; break;
default:
fprintf (stderr, "%s: illegal interarrival distribution "
"'%c' in %s\n",
prog_name, optarg[-1], optarg - 1);
exit (1);
}
/* remaining params depend on selected distribution: */
errno = 0;
switch (param.rate.dist)
{
case DETERMINISTIC:
case EXPONENTIAL:
param.rate.mean_iat = strtod (optarg, &end);
if (errno == ERANGE || end == optarg || *end
|| param.rate.mean_iat < 0)
{
fprintf (stderr, "%s: illegal mean interarrival "
"time %s\n", prog_name, optarg);
exit (1);
}
break;
case UNIFORM:
param.rate.min_iat = strtod (optarg, &end);
if (errno == ERANGE || end == optarg
|| param.rate.min_iat < 0)
{
fprintf (stderr, "%s: illegal minimum interarrival "
"time %s\n", prog_name, optarg);
exit (1);
}
if (*end != ',')
{
fprintf (stderr, "%s: minimum interarrival time not "
"followed by `,MAX_IAT' (rest: `%s')\n",
prog_name, end);
exit (1);
}
optarg = end + 1;
param.rate.max_iat = strtod (optarg, &end);
if (errno == ERANGE || end == optarg || *end
|| param.rate.max_iat < 0)
{
fprintf (stderr, "%s: illegal request period %s\n",
prog_name, optarg);
exit (1);
}
param.rate.mean_iat = 0.5*(param.rate.min_iat
+ param.rate.max_iat);
break;
default:
fprintf (stderr, "%s: internal error parsing %s\n",
prog_name, optarg);
exit (1);
break;
}
param.rate.rate_param = ((param.rate.mean_iat <= 0.0)
? 0.0 : (1.0 / param.rate.mean_iat));
}
else if (flag == ¶m.recv_buffer_size)
{
errno = 0;
param.recv_buffer_size = strtoul (optarg, &end, 10);
if (errno == ERANGE || end == optarg || *end
|| param.port > 0xffff)
{
fprintf (stderr, "%s: illegal receive buffer size %s\n",
prog_name, optarg);
exit (1);
}
}
else if (flag == ¶m.send_buffer_size)
{
errno = 0;
param.send_buffer_size = strtoul (optarg, &end, 10);
if (errno == ERANGE || end == optarg || *end
|| param.port > 0xffff)
{
fprintf (stderr, "%s: illegal send buffer size %s\n",
prog_name, optarg);
exit (1);
}
}
else if (flag == ¶m.client)
{
errno = 0;
param.client.id = strtoul (optarg, &end, 0);
if (end == optarg || errno == ERANGE)
{
fprintf (stderr, "%s: bad client id (rest: `%s')\n",
prog_name, optarg);
exit (1);
}
if (*end != '/')
{
fprintf (stderr,
"%s: client id not followed by `/' (rest: `%s')\n",
prog_name, end);
exit (1);
}
optarg = end + 1;
param.client.num_clients = strtoul (optarg, &end, 0);
if (end == optarg || errno == ERANGE
|| param.client.id >= param.client.num_clients)
{
fprintf (stderr, "%s: bad number of clients (rest: `%s')\n",
prog_name, optarg);
exit (1);
}
}
else if (flag == ¶m.server)
param.server = optarg;
else if (flag == ¶m.server_name)
param.server_name = optarg;
#ifdef HAVE_SSL
else if (flag == ¶m.ssl_cipher_list)
param.ssl_cipher_list = optarg;
#endif
else if (flag == ¶m.uri)
param.uri = optarg;
else if (flag == ¶m.think_timeout)
{
errno = 0;
param.think_timeout = strtod (optarg, &end);
if (errno == ERANGE || end == optarg || *end)
{
fprintf (stderr, "%s: illegal think timeout value %s\n",
prog_name, optarg);
exit (1);
}
}
else if (flag == ¶m.timeout)
{
errno = 0;
param.timeout = strtod (optarg, &end);
if (errno == ERANGE || end == optarg || *end)
{
fprintf (stderr, "%s: illegal connect timeout %s\n",
prog_name, optarg);
exit (1);
}
}
else if (flag == ¶m.wlog)
{
gen[1] = &uri_wlog; /* XXX fix me---somehow */
param.wlog.do_loop = (*optarg == 'y') || (*optarg == 'Y');
param.wlog.file = optarg + 2;
}
else if (flag == ¶m.wsess)
{
num_gen = 2; /* XXX fix me---somehow */
gen[0] = &wsess;
stat[num_stats++] = &session_stat;
errno = 0;
name = "bad number of sessions (1st param)";
param.wsess.num_sessions = strtoul (optarg, &end, 0);
if (end == optarg || errno == ERANGE)
goto bad_wsess_param;
optarg = end + 1;
name = "bad number of calls per session (2nd param)";
if (*end != ',')
goto bad_wsess_param;
optarg = end + 1;
param.wsess.num_calls = strtoul (optarg, &end, 0);
if (end == optarg || errno == ERANGE)
goto bad_wsess_param;
name = "bad user think time (3rd param)";
if (*end != ',')
goto bad_wsess_param;
optarg = end + 1;
param.wsess.think_time = strtod (optarg, &end);
if (end == optarg || errno == ERANGE
|| param.wsess.think_time < 0.0)
goto bad_wsess_param;
name = "extraneous parameter";
if (*end)
{
bad_wsess_param:
fprintf (stderr, "%s: %s in --wsess arg (rest: `%s')",
prog_name, name, end);
if (errno)
fprintf (stderr, ": %s", strerror (errno));
fputc ('\n', stderr);
exit (1);
}
session_workload = 1;
}
else if (flag == ¶m.wsesspage)
{
num_gen = 2; /* XXX fix me---somehow */
gen[0] = &wsesspage;
stat[num_stats++] = &session_stat;
errno = 0;
name = "bad number of sessions (1st param)";
param.wsesspage.num_sessions = strtoul (optarg, &end, 0);
if (end == optarg || errno == ERANGE)
goto bad_wsesspage_param;
optarg = end + 1;
name = "bad number of user requests per session (2nd param)";
if (*end != ',')
goto bad_wsesspage_param;
optarg = end + 1;
param.wsesspage.num_reqs = strtoul (optarg, &end, 0);
if (end == optarg || errno == ERANGE)
goto bad_wsesspage_param;
name = "bad user think time (3rd param)";
if (*end != ',')
goto bad_wsesspage_param;
optarg = end + 1;
param.wsesspage.think_time = strtod (optarg, &end);
if (end == optarg || errno == ERANGE
|| param.wsesspage.think_time < 0.0)
goto bad_wsesspage_param;
name = "extraneous parameter";
if (*end)
{
bad_wsesspage_param:
fprintf (stderr, "%s: %s in --wsesspage arg (rest: `%s')",
prog_name, name, end);
if (errno)
fprintf (stderr, ": %s", strerror (errno));
fputc ('\n', stderr);
exit (1);
}
session_workload = 1;
}
else if (flag == ¶m.wsesslog)
{
num_gen = 1; /* XXX fix me---somehow */
gen[0] = &wsesslog;
stat[num_stats++] = &session_stat;
errno = 0;
name = "bad number of sessions (1st param)";
param.wsesslog.num_sessions = strtoul (optarg, &end, 0);
if (end == optarg || errno == ERANGE)
goto bad_wsesslog_param;
optarg = end + 1;
name = "bad user think time (2nd param)";
if (*end != ',')
goto bad_wsesslog_param;
optarg = end + 1;
param.wsesslog.think_time = strtod (optarg, &end);
if (end == optarg || errno == ERANGE
|| param.wsesslog.think_time < 0.0)
goto bad_wsesslog_param;
name = "bad session filename (3rd param)";
if (*end != ',')
goto bad_wsesslog_param;
optarg = end + 1;
/* simulate parsing of string */
param.wsesslog.file = optarg;
if ((end = strchr (optarg, ',')) == NULL)
/* must be last param, position end at final \0 */
end = optarg + strlen(optarg);
else
/* terminate end of string */
*end++ = '\0';
optarg = end;
name = "extraneous parameter";
if (*end)
{
bad_wsesslog_param:
fprintf (stderr, "%s: %s in --wsesslog arg (rest: `%s')",
prog_name, name, end);
if (errno)
fprintf (stderr, ": %s", strerror (errno));
fputc ('\n', stderr);
exit (1);
}
session_workload = 1;
}
else if (flag == ¶m.wset)
{
gen[1] = &uri_wset; /* XXX fix me---somehow */
errno = 0;
name = "bad working set size (1st parameter)";
param.wset.num_files = strtoul (optarg, &end, 0);
if (end == optarg || errno == ERANGE)
goto bad_wset_param;
name = "bad target miss rate (2nd parameter)";
if (*end != ',')
goto bad_wset_param;
optarg = end + 1;
param.wset.target_miss_rate = strtod (optarg, &end);
if (end == optarg || errno == ERANGE
|| param.wset.target_miss_rate < 0.0
|| param.wset.target_miss_rate > 1.0)
goto bad_wset_param;
name = "extraneous parameter";
if (*end)
{
bad_wset_param:
fprintf (stderr, "%s: %s in --wset arg (rest: `%s')",
prog_name, name, optarg);
if (errno)
fprintf (stderr, ": %s", strerror (errno));
fputc ('\n', stderr);
exit (1);
}
}
break;
case 'd':
#ifdef DEBUG
errno = 0;
debug_level = strtoul (optarg, &end, 10);
if (errno == ERANGE || end == optarg || *end)
{
fprintf (stderr, "%s: illegal debug level %s\n",
prog_name, optarg);
exit (1);
}
#else
fprintf (stderr, "%s: sorry, need to recompile with -DDEBUG on...\n",
prog_name);
#endif
break;
case 'v':
++verbose;
break;
case 'V':
printf ("%s: httperf-"VERSION" compiled "__DATE__" with"
#ifndef DEBUG
"out"
#endif
" DEBUG with"
#ifndef TIME_SYSCALLS
"out"
#endif
" TIME_SYSCALLS.\n", prog_name);
break;
case 'h':
usage ();
exit (0);
case ':':
fprintf (stderr, "%s: parameter missing for option %s\n",
prog_name, longopts[longindex].name);
exit (1);
case '?':
/* Invalid or ambiguous option name or extraneous parameter.
getopt_long () already issued an explanation to the user,
so all we do is call it quites. */
exit (1);
default:
fprintf (stderr,
"%s: getopt_long: unexpected value (%d)\n",
prog_name, ch);
exit (1);
}
}
#ifdef HAVE_SSL
if (param.use_ssl)
{
char buf[1024];
if (param.port < 0)
param.port = 443;
SSL_load_error_strings ();
SSLeay_add_ssl_algorithms ();
/* for some strange reason, SSLv23_client_method () doesn't work here */
ssl_ctx = SSL_CTX_new (SSLv3_client_method ());
if (!ssl_ctx)
{
ERR_print_errors_fp (stderr);
exit (-1);
}
memset (buf, 0, sizeof (buf));
RAND_seed (buf, sizeof (buf));
}
#endif
if (param.port < 0)
param.port = 80;
if (param.print_reply || param.print_request)
stat[num_stats++] = &stats_print_reply;
if (param.session_cookies)
{
if (!session_workload)
{
fprintf (stderr, "%s: --session-cookie requires session-oriented "
"workload (e.g., --wsess)\n", prog_name);
exit (-1);
}
gen[num_gen++] = &sess_cookie;
}
if (param.additional_header || param.method)
gen[num_gen++] = &misc;
/* echo command invocation for logging purposes: */
printf ("%s", prog_name);
if (verbose) printf (" --verbose");
switch (param.print_reply)
{
case 0: break;
case PRINT_HEADER: printf (" --print-reply=header"); break;
case PRINT_BODY: printf (" --print-reply=body"); break;
default: printf (" --print-reply"); break;
}
switch (param.print_request)
{
case 0: break;
case PRINT_HEADER: printf (" --print-request=header"); break;
case PRINT_BODY: printf (" --print-request=body"); break;
default: printf (" --print-request"); break;
}
if (param.hog) printf (" --hog");
if (param.close_with_reset) printf (" --close-with-reset");
if (param.think_timeout > 0) printf (" --think-timeout=%g",
param.think_timeout);
if (param.timeout > 0) printf (" --timeout=%g", param.timeout);
printf (" --client=%u/%u", param.client.id, param.client.num_clients);
if (param.server) printf (" --server=%s", param.server);
if (param.server_name) printf (" --server_name=%s", param.server_name);
if (param.port) printf (" --port=%d", param.port);
if (param.uri) printf (" --uri=%s", param.uri);
if (param.failure_status) printf (" --failure-status=%u",
param.failure_status);
if (param.http_version != 0x10001)
printf (" --http-version=%u.%u", param.http_version >> 16,
param.http_version & 0xffff);
if (param.max_conns)
printf (" --max-connections=%u", param.max_conns);
if (param.max_piped)
printf (" --max-piped-calls=%u", param.max_piped);
if (param.rate.rate_param > 0.0)
{
switch (param.rate.dist)
{
case DETERMINISTIC:
/* for backwards compatibility, continue to use --rate: */
printf (" --rate=%g", param.rate.rate_param);
break;
case UNIFORM:
printf (" --period=u%g,%g",
param.rate.min_iat, param.rate.max_iat);
break;
case EXPONENTIAL:
printf (" --period=e%g", param.rate.mean_iat);
break;
default:
printf("--period=??");
break;
}
}
printf (" --send-buffer=%d", param.send_buffer_size);
if (param.retry_on_failure) printf (" --retry-on-failure");
printf (" --recv-buffer=%d", param.recv_buffer_size);
if (param.session_cookies) printf (" --session-cookies");
#ifdef HAVE_SSL
if (param.use_ssl) printf (" --ssl");
if (param.ssl_cipher_list)
printf(" --ssl-ciphers=%s", param.ssl_cipher_list);
if (!param.ssl_reuse) printf (" --ssl-no-reuse");
#endif
if (param.additional_header)
printf (" --add-header='%s'", param.additional_header);
if (param.method) printf (" --method=%s", param.method);
if (param.wsesslog.num_sessions)
{
/* This overrides any --wsess, --num-conns, --num-calls,
--burst-length and any uri generator */
printf (" --wsesslog=%u,%.3f,%s", param.wsesslog.num_sessions,
param.wsesslog.think_time, param.wsesslog.file);
}
else if (param.wsesspage.num_sessions)
{
printf (" --wsesspage=%u,%u,%.3f", param.wsesspage.num_sessions,
param.wsesspage.num_reqs, param.wsesspage.think_time);
}
else
{
if (param.wsess.num_sessions)
printf (" --wsess=%u,%u,%.3f", param.wsess.num_sessions,
param.wsess.num_calls, param.wsess.think_time);
else
{
if (param.num_conns) printf (" --num-conns=%d", param.num_conns);
if (param.num_calls) printf (" --num-calls=%d",
param.num_calls);
}
if (param.burst_len != 1) printf (" --burst-length=%d", param.burst_len);
if (param.wset.num_files) printf (" --wset=%u,%.3f",
param.wset.num_files,
param.wset.target_miss_rate);
}
printf ("\n");
timer_init ();
core_init ();
signal (SIGINT, (void (*)()) core_exit);
for (i = 0; i < num_stats; ++i)
(*stat[i]->init)();
for (i = 0; i < num_gen; ++i)
(*gen[i]->init) ();
/* Update `now'. This is to keep things accurate even when some of
the initialization routines take a long time to execute. */
timer_tick ();
/* ensure that clients sample rates at different times: */
t = (param.client.id + 1.0)*RATE_INTERVAL/param.client.num_clients;
arg.l = 0;
timer_schedule (perf_sample, arg, t);
perf_sample_start = timer_now ();
for (i = 0; i < num_gen; ++i)
(*gen[i]->start) ();
for (i = 0; i < num_stats; ++i)
(*stat[i]->start)();
getrusage (RUSAGE_SELF, &test_rusage_start);
test_time_start = timer_now ();
core_loop ();
test_time_stop = timer_now ();
getrusage (RUSAGE_SELF, &test_rusage_stop);
for (i = 0; i < num_stats; ++i)
(*stat[i]->stop)();
for (i = 0; i < num_gen; ++i)
(*gen[i]->stop) ();
for (i = 0; i < num_stats; ++i)
(*stat[i]->dump)();
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1