📄 httperf.c
字号:
/* 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 HAVE_SSL# include <openssl/rand.h>#endif#define RATE_INTERVAL 5.0const 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 DEBUGint debug_level;#endifstatic 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 voidusage (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);}voidpanic (const char *msg, ...){ va_list va; va_start (va, msg); vfprintf (stderr, msg, va); va_end (va); exit (1);}voidno_op (void){}static voidperf_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);}intmain (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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -