h2load: Code cleanup
This commit is contained in:
parent
50eac7bdf0
commit
2e7cee0faa
193
src/h2load.cc
193
src/h2load.cc
|
@ -85,7 +85,7 @@ Config::~Config() {
|
|||
}
|
||||
}
|
||||
|
||||
bool Config::is_rate_mode() { return (this->rate != 0); }
|
||||
bool Config::is_rate_mode() const { return (this->rate != 0); }
|
||||
|
||||
Config config;
|
||||
|
||||
|
@ -156,13 +156,13 @@ void readcb(struct ev_loop *loop, ev_io *w, int revents) {
|
|||
|
||||
namespace {
|
||||
// Called every second when rate mode is being used
|
||||
void second_timeout_w_cb(EV_P_ ev_timer *w, int revents) {
|
||||
void second_timeout_w_cb(struct ev_loop *loop, ev_timer *w, int revents) {
|
||||
auto worker = static_cast<Worker *>(w->data);
|
||||
auto nclients_per_second = worker->rate;
|
||||
auto conns_remaining = worker->nclients - worker->nconns_made;
|
||||
auto nclients = std::min(nclients_per_second, conns_remaining);
|
||||
|
||||
for (ssize_t i = 0; i < nclients; ++i) {
|
||||
for (size_t i = 0; i < nclients; ++i) {
|
||||
auto req_todo = worker->config->max_concurrent_streams;
|
||||
worker->clients.push_back(make_unique<Client>(worker, req_todo));
|
||||
auto &client = worker->clients.back();
|
||||
|
@ -175,7 +175,6 @@ void second_timeout_w_cb(EV_P_ ev_timer *w, int revents) {
|
|||
if (worker->nconns_made >= worker->nclients) {
|
||||
ev_timer_stop(worker->loop, w);
|
||||
}
|
||||
++worker->current_second;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
@ -729,20 +728,19 @@ void Client::record_ttfb(Stats *stat) {
|
|||
void Client::signal_write() { ev_io_start(worker->loop, &wev); }
|
||||
|
||||
Worker::Worker(uint32_t id, SSL_CTX *ssl_ctx, size_t req_todo, size_t nclients,
|
||||
ssize_t rate, Config *config)
|
||||
size_t rate, Config *config)
|
||||
: stats(req_todo), loop(ev_loop_new(0)), ssl_ctx(ssl_ctx), config(config),
|
||||
id(id), tls_info_report_done(false), current_second(0), nconns_made(0),
|
||||
nclients(nclients), rate(rate) {
|
||||
id(id), tls_info_report_done(false), nconns_made(0), nclients(nclients),
|
||||
rate(rate) {
|
||||
stats.req_todo = req_todo;
|
||||
progress_interval = std::max((size_t)1, req_todo / 10);
|
||||
progress_interval = std::max(static_cast<size_t>(1), req_todo / 10);
|
||||
auto nreqs_per_client = req_todo / nclients;
|
||||
auto nreqs_rem = req_todo % nclients;
|
||||
|
||||
if (config->is_rate_mode()) {
|
||||
// create timer that will go off every second
|
||||
ev_timer_init(&timeout_watcher, second_timeout_w_cb, 0., 1.);
|
||||
timeout_watcher.data = this;
|
||||
ev_init(&timeout_watcher, second_timeout_w_cb);
|
||||
timeout_watcher.repeat = 1.;
|
||||
} else {
|
||||
for (size_t i = 0; i < nclients; ++i) {
|
||||
auto req_todo = nreqs_per_client;
|
||||
|
@ -1233,7 +1231,7 @@ int main(int argc, char **argv) {
|
|||
break;
|
||||
case 'r':
|
||||
config.rate = strtoul(optarg, nullptr, 10);
|
||||
if (config.rate <= 0) {
|
||||
if (config.rate == 0) {
|
||||
std::cerr << "-r: the rate at which connections are made "
|
||||
<< "must be positive." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
|
@ -1241,7 +1239,7 @@ int main(int argc, char **argv) {
|
|||
break;
|
||||
case 'C':
|
||||
config.nconns = strtoul(optarg, nullptr, 10);
|
||||
if (config.nconns <= 0) {
|
||||
if (config.nconns == 0) {
|
||||
std::cerr << "-C: the total number of connections made "
|
||||
<< "must be positive." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
|
@ -1298,47 +1296,37 @@ int main(int argc, char **argv) {
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!config.is_rate_mode() && config.nreqs < config.nclients) {
|
||||
std::cerr << "-n, -c: the number of requests must be greater than or "
|
||||
<< "equal to the concurrent clients." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!config.is_rate_mode() && config.nclients < config.nthreads) {
|
||||
std::cerr << "-c, -t: the number of client must be greater than or equal "
|
||||
"to the number of threads." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (config.nthreads > std::thread::hardware_concurrency()) {
|
||||
std::cerr << "-t: warning: the number of threads is greater than hardware "
|
||||
<< "cores." << std::endl;
|
||||
}
|
||||
|
||||
if (config.nconns < 0) {
|
||||
std::cerr << "-C: the total number of connections made "
|
||||
<< "cannot be negative." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!config.is_rate_mode()) {
|
||||
if (config.nreqs < config.nclients) {
|
||||
std::cerr << "-n, -c: the number of requests must be greater than or "
|
||||
<< "equal to the concurrent clients." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (config.rate < 0) {
|
||||
std::cerr << "-r: the rate at which connections are made "
|
||||
<< "cannot be negative." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (config.nclients < config.nthreads) {
|
||||
std::cerr << "-c, -t: the number of client must be greater than or equal "
|
||||
"to the number of threads." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
if (config.rate < config.nthreads) {
|
||||
std::cerr << "-r, -t: the connection rate must be greater than or equal "
|
||||
<< "to the number of threads." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (config.is_rate_mode() && config.rate < (ssize_t)config.nthreads) {
|
||||
std::cerr << "-r, -t: the connection rate must be greater than or equal "
|
||||
<< "to the number of threads." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (config.is_rate_mode() && config.nconns != 0 &&
|
||||
config.nconns < (ssize_t)config.nthreads) {
|
||||
std::cerr << "-C, -t: the total number of connections must be greater than "
|
||||
"or equal "
|
||||
<< "to the number of threads." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
if (config.nconns != 0 && config.nconns < config.nthreads) {
|
||||
std::cerr
|
||||
<< "-C, -t: the total number of connections must be greater than "
|
||||
"or equal "
|
||||
<< "to the number of threads." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (!datafile.empty()) {
|
||||
|
@ -1424,51 +1412,58 @@ int main(int argc, char **argv) {
|
|||
reqlines = parse_uris(std::begin(uris), std::end(uris));
|
||||
}
|
||||
|
||||
if (reqlines.empty()) {
|
||||
std::cerr << "No URI given" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (config.max_concurrent_streams == -1) {
|
||||
config.max_concurrent_streams = reqlines.size();
|
||||
}
|
||||
|
||||
assert(config.max_concurrent_streams > 0);
|
||||
|
||||
// if not in rate mode and -C is set, warn that we are ignoring it
|
||||
if (!config.is_rate_mode() && config.nconns != 0) {
|
||||
std::cerr << "-C: warning: This option can only be used with -r, and"
|
||||
<< " will be ignored otherwise." << std::endl;
|
||||
}
|
||||
|
||||
ssize_t n_time = 0;
|
||||
ssize_t c_time = 0;
|
||||
size_t n_time = 0;
|
||||
size_t c_time = 0;
|
||||
size_t actual_nreqs = config.nreqs;
|
||||
// only care about n_time and c_time in rate mode
|
||||
if (config.is_rate_mode() && config.max_concurrent_streams != 0) {
|
||||
n_time = (int)config.nreqs /
|
||||
((int)config.rate * (int)config.max_concurrent_streams);
|
||||
c_time = (int)config.nconns / (int)config.rate;
|
||||
}
|
||||
// check to see if the two ways of determining test time conflict
|
||||
if (config.is_rate_mode() && (int)config.max_concurrent_streams != 0 &&
|
||||
(n_time != c_time) && config.nreqs != 1 && config.nconns != 0) {
|
||||
if ((int)config.nreqs < config.nconns) {
|
||||
std::cerr << "-C, -n: warning: number of requests conflict. "
|
||||
<< std::endl;
|
||||
std::cerr << "The test will create "
|
||||
<< (config.max_concurrent_streams * config.nconns)
|
||||
<< " total requests." << std::endl;
|
||||
actual_nreqs = config.max_concurrent_streams * config.nconns;
|
||||
} else {
|
||||
std::cout << "-C, -n: warning: number of requests conflict. "
|
||||
<< std::endl;
|
||||
std::cout << "The smaller of the two will be chosen and the test will "
|
||||
<< "create "
|
||||
<< std::min(
|
||||
config.nreqs,
|
||||
(size_t)(config.max_concurrent_streams * config.nconns))
|
||||
<< " total requests." << std::endl;
|
||||
actual_nreqs = std::min(
|
||||
config.nreqs, (size_t)(config.max_concurrent_streams * config.nreqs));
|
||||
}
|
||||
} else {
|
||||
if (config.is_rate_mode() && config.max_concurrent_streams != 0 &&
|
||||
(n_time != c_time) && config.nreqs == 1 && config.nconns != 0) {
|
||||
actual_nreqs = config.max_concurrent_streams * config.nconns;
|
||||
if (config.is_rate_mode()) {
|
||||
n_time = config.nreqs / (config.rate * config.max_concurrent_streams);
|
||||
c_time = config.nconns / config.rate;
|
||||
|
||||
// check to see if the two ways of determining test time conflict
|
||||
if (n_time != c_time && config.nconns != 0) {
|
||||
if (config.nreqs != 1) {
|
||||
if (config.nreqs < config.nconns) {
|
||||
std::cerr << "-C, -n: warning: number of requests conflict. "
|
||||
<< std::endl;
|
||||
std::cerr << "The test will create "
|
||||
<< (config.max_concurrent_streams * config.nconns)
|
||||
<< " total requests." << std::endl;
|
||||
actual_nreqs = config.max_concurrent_streams * config.nconns;
|
||||
} else {
|
||||
std::cout << "-C, -n: warning: number of requests conflict. "
|
||||
<< std::endl;
|
||||
std::cout
|
||||
<< "The smaller of the two will be chosen and the test will "
|
||||
<< "create "
|
||||
<< std::min(config.nreqs,
|
||||
static_cast<size_t>(config.max_concurrent_streams *
|
||||
config.nconns))
|
||||
<< " total requests." << std::endl;
|
||||
actual_nreqs = std::min(
|
||||
config.nreqs, static_cast<size_t>(config.max_concurrent_streams *
|
||||
config.nreqs));
|
||||
}
|
||||
} else {
|
||||
actual_nreqs = config.max_concurrent_streams * config.nconns;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1545,7 +1540,7 @@ int main(int argc, char **argv) {
|
|||
if (config.is_rate_mode()) {
|
||||
|
||||
// set various config values
|
||||
if ((int)config.nreqs < config.nconns) {
|
||||
if (config.nreqs < config.nconns) {
|
||||
seconds = c_time;
|
||||
} else if (config.nconns == 0) {
|
||||
seconds = n_time;
|
||||
|
@ -1561,19 +1556,17 @@ int main(int argc, char **argv) {
|
|||
size_t nclients_per_thread = config.nclients / config.nthreads;
|
||||
ssize_t nclients_rem = config.nclients % config.nthreads;
|
||||
|
||||
size_t rate_per_thread = config.rate / (ssize_t)config.nthreads;
|
||||
ssize_t rate_per_thread_rem = config.rate % (ssize_t)config.nthreads;
|
||||
size_t rate_per_thread = config.rate / config.nthreads;
|
||||
ssize_t rate_per_thread_rem = config.rate % config.nthreads;
|
||||
|
||||
auto nclients_extra = 0;
|
||||
auto nclients_extra_per_thread = 0;
|
||||
auto nclients_extra_rem_per_thread = 0;
|
||||
size_t nclients_extra_per_thread = 0;
|
||||
ssize_t nclients_extra_per_thread_rem = 0;
|
||||
// In rate mode, we want each Worker to create a total of
|
||||
// C/t connections.
|
||||
if (config.is_rate_mode() && config.nconns > seconds * config.rate) {
|
||||
nclients_extra = config.nconns - (seconds * config.rate);
|
||||
nclients_extra_per_thread = nclients_extra / (ssize_t)config.nthreads;
|
||||
nclients_extra_rem_per_thread =
|
||||
(ssize_t)nclients_extra % (ssize_t)config.nthreads;
|
||||
auto nclients_extra = config.nconns - (seconds * config.rate);
|
||||
nclients_extra_per_thread = nclients_extra / config.nthreads;
|
||||
nclients_extra_per_thread_rem = nclients_extra % config.nthreads;
|
||||
}
|
||||
|
||||
std::cout << "starting benchmark..." << std::endl;
|
||||
|
@ -1586,12 +1579,15 @@ int main(int argc, char **argv) {
|
|||
#ifndef NOTHREADS
|
||||
std::vector<std::future<void>> futures;
|
||||
for (size_t i = 0; i < config.nthreads - 1; ++i) {
|
||||
auto nreqs = nreqs_per_thread + (nreqs_rem-- > 0);
|
||||
auto rate = rate_per_thread + (rate_per_thread_rem-- > 0);
|
||||
auto nclients = nclients_per_thread + (nclients_rem-- > 0);
|
||||
if (config.is_rate_mode()) {
|
||||
size_t nreqs;
|
||||
size_t nclients;
|
||||
if (!config.is_rate_mode()) {
|
||||
nclients = nclients_per_thread + (nclients_rem-- > 0);
|
||||
nreqs = nreqs_per_thread + (nreqs_rem-- > 0);
|
||||
} else {
|
||||
nclients = rate * seconds + nclients_extra_per_thread +
|
||||
(nclients_extra_rem_per_thread-- > 0);
|
||||
(nclients_extra_per_thread_rem-- > 0);
|
||||
nreqs = nclients * config.max_concurrent_streams;
|
||||
}
|
||||
std::cout << "spawning thread #" << i << ": " << nclients
|
||||
|
@ -1605,12 +1601,15 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
#endif // NOTHREADS
|
||||
|
||||
auto nreqs_last = nreqs_per_thread + (nreqs_rem-- > 0);
|
||||
auto nclients_last = nclients_per_thread + (nclients_rem-- > 0);
|
||||
auto rate_last = rate_per_thread + (rate_per_thread_rem-- > 0);
|
||||
if (config.is_rate_mode()) {
|
||||
size_t nclients_last;
|
||||
size_t nreqs_last;
|
||||
if (!config.is_rate_mode()) {
|
||||
nclients_last = nclients_per_thread + (nclients_rem-- > 0);
|
||||
nreqs_last = nreqs_per_thread + (nreqs_rem-- > 0);
|
||||
} else {
|
||||
nclients_last = rate_last * seconds + nclients_extra_per_thread +
|
||||
(nclients_extra_rem_per_thread-- > 0);
|
||||
(nclients_extra_per_thread_rem-- > 0);
|
||||
nreqs_last = nclients_last * config.max_concurrent_streams;
|
||||
}
|
||||
std::cout << "spawning thread #" << (config.nthreads - 1) << ": "
|
||||
|
|
15
src/h2load.h
15
src/h2load.h
|
@ -78,9 +78,9 @@ struct Config {
|
|||
size_t window_bits;
|
||||
size_t connection_window_bits;
|
||||
// rate at which connections should be made
|
||||
ssize_t rate;
|
||||
size_t rate;
|
||||
// number of connections made
|
||||
ssize_t nconns;
|
||||
size_t nconns;
|
||||
enum { PROTO_HTTP2, PROTO_SPDY2, PROTO_SPDY3, PROTO_SPDY3_1 } no_tls_proto;
|
||||
// file descriptor for upload data
|
||||
int data_fd;
|
||||
|
@ -91,7 +91,7 @@ struct Config {
|
|||
Config();
|
||||
~Config();
|
||||
|
||||
bool is_rate_mode();
|
||||
bool is_rate_mode() const;
|
||||
};
|
||||
|
||||
struct RequestStat {
|
||||
|
@ -177,14 +177,13 @@ struct Worker {
|
|||
size_t progress_interval;
|
||||
uint32_t id;
|
||||
bool tls_info_report_done;
|
||||
ssize_t current_second;
|
||||
ssize_t nconns_made;
|
||||
ssize_t nclients;
|
||||
size_t nconns_made;
|
||||
size_t nclients;
|
||||
size_t rate;
|
||||
ev_timer timeout_watcher;
|
||||
ssize_t rate;
|
||||
|
||||
Worker(uint32_t id, SSL_CTX *ssl_ctx, size_t nreq_todo, size_t nclients,
|
||||
ssize_t rate, Config *config);
|
||||
size_t rate, Config *config);
|
||||
~Worker();
|
||||
Worker(Worker &&o) = default;
|
||||
void run();
|
||||
|
|
Loading…
Reference in New Issue