h2load: Add option for user-definable rate period

This commit is contained in:
Lucas Pardue 2015-10-05 15:27:00 +00:00
parent e262c013bd
commit afa14d36a8
2 changed files with 74 additions and 24 deletions

View File

@ -74,9 +74,9 @@ namespace h2load {
Config::Config() Config::Config()
: data_length(-1), addrs(nullptr), nreqs(1), nclients(1), nthreads(1), : data_length(-1), addrs(nullptr), nreqs(1), nclients(1), nthreads(1),
max_concurrent_streams(-1), window_bits(30), connection_window_bits(30), max_concurrent_streams(-1), window_bits(30), connection_window_bits(30),
rate(0), nconns(0), conn_active_timeout(0), conn_inactivity_timeout(0), rate(0), rate_period(1.0), nconns(0), conn_active_timeout(0),
no_tls_proto(PROTO_HTTP2), data_fd(-1), port(0), default_port(0), conn_inactivity_timeout(0), no_tls_proto(PROTO_HTTP2), data_fd(-1),
verbose(false), timing_script(false) {} port(0), default_port(0), verbose(false), timing_script(false) {}
Config::~Config() { Config::~Config() {
freeaddrinfo(addrs); freeaddrinfo(addrs);
@ -136,8 +136,8 @@ void readcb(struct ev_loop *loop, ev_io *w, int revents) {
} // namespace } // namespace
namespace { namespace {
// Called every second when rate mode is being used // Called every rate_period when rate mode is being used
void second_timeout_w_cb(struct ev_loop *loop, ev_timer *w, int revents) { void rate_period_timeout_w_cb(struct ev_loop *loop, ev_timer *w, int revents) {
auto worker = static_cast<Worker *>(w->data); auto worker = static_cast<Worker *>(w->data);
auto nclients_per_second = worker->rate; auto nclients_per_second = worker->rate;
auto conns_remaining = worker->nclients - worker->nconns_made; auto conns_remaining = worker->nclients - worker->nconns_made;
@ -938,8 +938,9 @@ Worker::Worker(uint32_t id, SSL_CTX *ssl_ctx, size_t req_todo, size_t nclients,
auto nreqs_per_client = req_todo / nclients; auto nreqs_per_client = req_todo / nclients;
auto nreqs_rem = req_todo % nclients; auto nreqs_rem = req_todo % nclients;
// create timer that will go off every second // create timer that will go off every rate_period
ev_timer_init(&timeout_watcher, second_timeout_w_cb, 0., 1.); ev_timer_init(&timeout_watcher, rate_period_timeout_w_cb, 0.,
config->rate_period);
timeout_watcher.data = this; timeout_watcher.data = this;
if (!config->is_rate_mode()) { if (!config->is_rate_mode()) {
@ -974,8 +975,8 @@ void Worker::run() {
} else { } else {
ev_timer_again(loop, &timeout_watcher); ev_timer_again(loop, &timeout_watcher);
// call callback so that we don't waste the first second // call callback so that we don't waste the first rate_period
second_timeout_w_cb(loop, &timeout_watcher, 0); rate_period_timeout_w_cb(loop, &timeout_watcher, 0);
} }
ev_run(loop, 0); ev_run(loop, 0);
} }
@ -1345,9 +1346,16 @@ Options:
Specifies the fixed rate at which connections are Specifies the fixed rate at which connections are
created. The rate must be a positive integer, created. The rate must be a positive integer,
representing the number of connections to be made per representing the number of connections to be made per
second. When the rate is 0, the program will run as it rate period. When the rate is 0, the program will run as
normally does, creating connections at whatever variable it normally does, creating connections at whatever
rate it wants. The default value for this option is 0. variable rate it wants. The default value for this
option is 0.
--rate-period=<N>
Specifies the time period between creating connections.
The period must be a positive number greater than or
equal to 1.0, representing the length of the period in
seconds. This option is ignored if the rate option is
not used. The default value for this option is 1.0.
-C, --num-conns=<N> -C, --num-conns=<N>
Specifies the total number of connections to create. Specifies the total number of connections to create.
The total number of connections must be a positive The total number of connections must be a positive
@ -1444,6 +1452,7 @@ int main(int argc, char **argv) {
{"timing-script-file", required_argument, &flag, 3}, {"timing-script-file", required_argument, &flag, 3},
{"base-uri", required_argument, nullptr, 'B'}, {"base-uri", required_argument, nullptr, 'B'},
{"npn-list", required_argument, &flag, 4}, {"npn-list", required_argument, &flag, 4},
{"rate-period", required_argument, &flag, 5},
{nullptr, 0, nullptr, 0}}; {nullptr, 0, nullptr, 0}};
int option_index = 0; int option_index = 0;
auto c = getopt_long(argc, argv, "hvW:c:d:m:n:p:t:w:H:i:r:C:T:N:B:", auto c = getopt_long(argc, argv, "hvW:c:d:m:n:p:t:w:H:i:r:C:T:N:B:",
@ -1610,6 +1619,25 @@ int main(int argc, char **argv) {
// npn-list option // npn-list option
config.npn_list = util::parse_config_str_list(optarg); config.npn_list = util::parse_config_str_list(optarg);
break; break;
case 5: {
// rate-period
const char *start = optarg;
char *end;
errno = 0;
auto v = std::strtod(start, &end);
if (v < 1.0 || !std::isfinite(v) || end == start || errno != 0) {
auto error = errno;
std::cerr << "Rate period value error " << optarg << std::endl;
if (error != 0) {
std::cerr << "\n\t" << strerror(error) << std::endl;
}
exit(EXIT_FAILURE);
}
config.rate_period = v;
break;
}
} }
break; break;
default: default:
@ -1630,12 +1658,6 @@ int main(int argc, char **argv) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (config.timing_script && config.is_rate_mode()) {
std::cerr << "--timing-script, -r: these options cannot be used together."
<< std::endl;
exit(EXIT_FAILURE);
}
if (config.npn_list.empty()) { if (config.npn_list.empty()) {
config.npn_list = util::parse_config_str_list(DEFAULT_NPN_LIST); config.npn_list = util::parse_config_str_list(DEFAULT_NPN_LIST);
} }
@ -1996,14 +2018,28 @@ int main(int argc, char **argv) {
if (!config.is_rate_mode()) { if (!config.is_rate_mode()) {
nclients = nclients_per_thread + (nclients_rem-- > 0); nclients = nclients_per_thread + (nclients_rem-- > 0);
nreqs = nreqs_per_thread + (nreqs_rem-- > 0); nreqs = nreqs_per_thread + (nreqs_rem-- > 0);
std::cout << "spawning thread #" << i << ": " << nclients
<< " concurrent clients, " << nreqs << " total requests"
<< std::endl;
} else { } else {
nclients = rate * seconds + nclients_extra_per_thread + nclients = rate * seconds + nclients_extra_per_thread +
(nclients_extra_per_thread_rem-- > 0); (nclients_extra_per_thread_rem-- > 0);
nreqs = nclients * config.max_concurrent_streams; nreqs = nclients * config.max_concurrent_streams;
std::stringstream rate_report;
if (nclients >= config.rate) {
rate_report << "Up to " << config.rate
<< " client(s) will be created every "
<< std::setprecision(3) << config.rate_period
<< " seconds. ";
}
std::cout << "spawning thread #" << i << ": " << nclients
<< " total client(s). " << rate_report.str() << nreqs
<< " total requests" << std::endl;
} }
std::cout << "spawning thread #" << i << ": " << nclients
<< " concurrent clients, " << nreqs << " total requests"
<< std::endl;
workers.push_back( workers.push_back(
make_unique<Worker>(i, ssl_ctx, nreqs, nclients, rate, &config)); make_unique<Worker>(i, ssl_ctx, nreqs, nclients, rate, &config));
auto &worker = workers.back(); auto &worker = workers.back();
@ -2018,14 +2054,27 @@ int main(int argc, char **argv) {
if (!config.is_rate_mode()) { if (!config.is_rate_mode()) {
nclients_last = nclients_per_thread + (nclients_rem-- > 0); nclients_last = nclients_per_thread + (nclients_rem-- > 0);
nreqs_last = nreqs_per_thread + (nreqs_rem-- > 0); nreqs_last = nreqs_per_thread + (nreqs_rem-- > 0);
std::cout << "spawning thread #" << (config.nthreads - 1) << ": "
<< nclients_last << " concurrent clients, " << nreqs_last
<< " total requests" << std::endl;
} else { } else {
nclients_last = rate_last * seconds + nclients_extra_per_thread + nclients_last = rate_last * seconds + nclients_extra_per_thread +
(nclients_extra_per_thread_rem-- > 0); (nclients_extra_per_thread_rem-- > 0);
nreqs_last = nclients_last * config.max_concurrent_streams; nreqs_last = nclients_last * config.max_concurrent_streams;
std::stringstream rate_report;
if (nclients_last >= config.rate) {
rate_report << "Up to " << config.rate
<< " client(s) will be created every " << std::setprecision(3)
<< config.rate_period << " seconds. ";
}
std::cout << "spawning thread #" << (config.nthreads - 1) << ": "
<< nclients_last << " total client(s). " << rate_report.str()
<< nreqs_last << " total requests" << std::endl;
} }
std::cout << "spawning thread #" << (config.nthreads - 1) << ": "
<< nclients_last << " concurrent clients, " << nreqs_last
<< " total requests" << std::endl;
workers.push_back(make_unique<Worker>(config.nthreads - 1, ssl_ctx, workers.push_back(make_unique<Worker>(config.nthreads - 1, ssl_ctx,
nreqs_last, nclients_last, rate_last, nreqs_last, nclients_last, rate_last,
&config)); &config));

View File

@ -81,6 +81,7 @@ struct Config {
size_t connection_window_bits; size_t connection_window_bits;
// rate at which connections should be made // rate at which connections should be made
size_t rate; size_t rate;
ev_tstamp rate_period;
// number of connections made // number of connections made
size_t nconns; size_t nconns;
// amount of time to wait for activity on a given connection // amount of time to wait for activity on a given connection