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:
parent
86a23c6beb
commit
8225945f32
8
README
8
README
@ -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%
|
||||
|
12
src/units.c
12
src/units.c
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
64
src/wrk.c
64
src/wrk.c
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user