1
0
mirror of https://github.com/wg/wrk synced 2025-02-10 20:33:07 +08:00

switch to time as basis of benchmark duration

This commit is contained in:
Will 2013-04-10 20:53:30 +09:00
parent 86a23c6beb
commit 8225945f32
5 changed files with 46 additions and 44 deletions

8
README
View File

@ -6,14 +6,14 @@ wrk - a HTTP benchmarking tool
Basic Usage
wrk -t8 -c400 -r10m http://localhost:8080/index.html
wrk -t8 -c400 -d30 http://localhost:8080/index.html
This runs wrk with 8 threads, keeping 400 connections open, and making a
total of 10 million HTTP GET requests to http://localhost:8080/index.html
This runs a benchmark for 30 seconds, using 8 threads, and keeping
400 HTTP connections open.
Output:
Making 10000000 requests to http://localhost:8080/index.html
Running 30s test @ http://localhost:8080/index.html
8 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 439.75us 350.49us 7.60ms 92.88%

View File

@ -62,10 +62,10 @@ static int scan_units(char *s, uint64_t *n, units *m) {
if ((c = sscanf(s, "%"SCNu64"%2s", &base, unit)) < 1) return -1;
if (c == 2) {
if (c == 2 && strncasecmp(unit, m->base, 3)) {
for (i = 0; m->units[i] != NULL; i++) {
scale *= m->scale;
if (!strncasecmp(unit, m->units[i], sizeof(unit))) break;
if (!strncasecmp(unit, m->units[i], 3)) break;
}
if (m->units[i] == NULL) return -1;
}
@ -91,6 +91,14 @@ char *format_time_us(long double n) {
return format_units(n, units, 2);
}
char *format_time_s(long double n) {
return format_units(n, &time_units_s, 0);
}
int scan_metric(char *s, uint64_t *n) {
return scan_units(s, n, &metric_units);
}
int scan_time(char *s, uint64_t *n) {
return scan_units(s, n, &time_units_s);
}

View File

@ -4,7 +4,9 @@
char *format_binary(long double);
char *format_metric(long double);
char *format_time_us(long double);
char *format_time_s(long double);
int scan_metric(char *, uint64_t *);
int scan_time(char *, uint64_t *);
#endif /* UNITS_H */

View File

@ -31,9 +31,8 @@ static struct config {
struct addrinfo addr;
uint64_t threads;
uint64_t connections;
uint64_t requests;
uint64_t duration;
uint64_t timeout;
uint64_t errors;
} cfg;
static struct {
@ -60,15 +59,15 @@ static void handler(int sig) {
static void usage() {
printf("Usage: wrk <options> <url> \n"
" Options: \n"
" -c, --connections <n> Connections to keep open \n"
" -r, --requests <n> Total requests to make \n"
" -t, --threads <n> Number of threads to use \n"
" -c, --connections <N> Connections to keep open \n"
" -d, --duration <T> Duration of test \n"
" -t, --threads <N> Number of threads to use \n"
" \n"
" -H, --header <h> Add header to request \n"
" -H, --header <H> Add header to request \n"
" -v, --version Print version details \n"
" --errors <n> Abort after N errors \n"
" \n"
" Numeric arguments may include a SI unit (2k, 2M, 2G)\n");
" Numeric arguments may include a SI unit (1k, 1M, 1G)\n"
" Time arguments may include a time unit (2s, 2m, 2h)\n");
}
int main(int argc, char **argv) {
@ -135,12 +134,12 @@ int main(int argc, char **argv) {
thread *threads = zcalloc(cfg.threads * sizeof(thread));
uint64_t connections = cfg.connections / cfg.threads;
uint64_t requests = cfg.requests / cfg.threads;
uint64_t stop_at = time_us() + (cfg.duration * 1000000);
for (uint64_t i = 0; i < cfg.threads; i++) {
thread *t = &threads[i];
t->connections = connections;
t->requests = requests;
t->stop_at = stop_at;
if (pthread_create(&t->thread, NULL, &thread_main, t)) {
char *msg = strerror(errno);
@ -156,7 +155,8 @@ int main(int argc, char **argv) {
sigfillset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
printf("Making %"PRIu64" requests to %s\n", cfg.requests, url);
char *time = format_time_s(cfg.duration);
printf("Running %s test @ %s\n", time, url);
printf(" %"PRIu64" threads and %"PRIu64" connections\n", cfg.threads, cfg.connections);
uint64_t start = time_us();
@ -293,17 +293,20 @@ static int sample_rate(aeEventLoop *loop, long long id, void *data) {
static int request_complete(http_parser *parser) {
connection *c = parser->data;
thread *thread = c->thread;
uint64_t now = time_us();
thread->complete++;
c->latency = now - c->start;
if (parser->status_code > 399) {
thread->errors.status++;
}
if (++thread->complete >= thread->requests) {
if (now >= thread->stop_at) {
aeStop(thread->loop);
goto done;
}
c->latency = time_us() - c->start;
if (!http_should_keep_alive(parser)) goto reconnect;
http_parser_init(parser, HTTP_RESPONSE);
@ -321,9 +324,10 @@ static int request_complete(http_parser *parser) {
static int check_timeouts(aeEventLoop *loop, long long id, void *data) {
thread *thread = data;
connection *c = thread->cs;
connection *c = thread->cs;
uint64_t now = time_us();
uint64_t maxAge = time_us() - (cfg.timeout * 1000);
uint64_t maxAge = now - (cfg.timeout * 1000);
for (uint64_t i = 0; i < thread->connections; i++, c++) {
if (maxAge > c->start) {
@ -331,13 +335,7 @@ static int check_timeouts(aeEventLoop *loop, long long id, void *data) {
}
}
uint64_t errors = 0;
errors += thread->errors.connect;
errors += thread->errors.read;
errors += thread->errors.write;
errors += thread->errors.timeout;
if (stop || errors >= cfg.errors) {
if (stop || now >= thread->stop_at) {
aeStop(loop);
}
@ -426,10 +424,9 @@ static char *format_request(char *host, char *port, char *path, char **headers)
static struct option longopts[] = {
{ "connections", required_argument, NULL, 'c' },
{ "requests", required_argument, NULL, 'r' },
{ "duration", required_argument, NULL, 'd' },
{ "threads", required_argument, NULL, 't' },
{ "header", required_argument, NULL, 'H' },
{ "errors", required_argument, NULL, 'E' },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{ NULL, 0, NULL, 0 }
@ -441,10 +438,10 @@ static int parse_args(struct config *cfg, char **url, char **headers, int argc,
memset(cfg, 0, sizeof(struct config));
cfg->threads = 2;
cfg->connections = 10;
cfg->requests = 100;
cfg->duration = 10;
cfg->timeout = SOCKET_TIMEOUT_MS;
while ((c = getopt_long(argc, argv, "t:c:r:E:H:v?", longopts, NULL)) != -1) {
while ((c = getopt_long(argc, argv, "t:c:d:H:rv?", longopts, NULL)) != -1) {
switch (c) {
case 't':
if (scan_metric(optarg, &cfg->threads)) return -1;
@ -452,11 +449,8 @@ static int parse_args(struct config *cfg, char **url, char **headers, int argc,
case 'c':
if (scan_metric(optarg, &cfg->connections)) return -1;
break;
case 'r':
if (scan_metric(optarg, &cfg->requests)) return -1;
break;
case 'E':
if (scan_metric(optarg, &cfg->errors)) return -1;
case 'd':
if (scan_time(optarg, &cfg->duration)) return -1;
break;
case 'H':
*header++ = optarg;
@ -465,6 +459,8 @@ static int parse_args(struct config *cfg, char **url, char **headers, int argc,
printf("wrk %s [%s] ", VERSION, aeGetApiName());
printf("Copyright (C) 2012 Will Glozer\n");
break;
case 'r':
fprintf(stderr, "wrk 2.0.0+ uses -d instead of -r\n");
case 'h':
case '?':
case ':':
@ -473,17 +469,13 @@ static int parse_args(struct config *cfg, char **url, char **headers, int argc,
}
}
if (optind == argc || !cfg->threads || !cfg->requests) return -1;
if (optind == argc || !cfg->threads || !cfg->duration) return -1;
if (!cfg->connections || cfg->connections < cfg->threads) {
fprintf(stderr, "number of connections must be >= threads\n");
return -1;
}
if (cfg->errors == 0) {
cfg->errors = cfg->requests / cfg->threads / 10;
}
*url = argv[optind];
*header = NULL;

View File

@ -11,7 +11,7 @@
#include "http_parser.h"
#include "tinymt64.h"
#define VERSION "1.2.0"
#define VERSION "2.0.0"
#define RECVBUF 8192
#define SAMPLES 100000
@ -31,7 +31,7 @@ typedef struct {
pthread_t thread;
aeEventLoop *loop;
uint64_t connections;
uint64_t requests;
uint64_t stop_at;
uint64_t complete;
uint64_t bytes;
uint64_t start;