mirror of
https://github.com/wg/wrk
synced 2026-06-09 16:43:42 +08:00
Compare commits
5 Commits
@@ -1,10 +1,11 @@
|
||||
CFLAGS := -std=c99 -Wall -O2
|
||||
CFLAGS := -std=c99 -Wall -O2 -D_REENTRANT
|
||||
LIBS := -lpthread -lm
|
||||
|
||||
TARGET := $(shell uname -s | tr [A-Z] [a-z] 2>/dev/null || echo unknown)
|
||||
|
||||
ifeq ($(TARGET), sunos)
|
||||
LIBS += -lsocket
|
||||
CFLAGS += -D_PTHREADS -D_POSIX_C_SOURCE=200112L
|
||||
LIBS += -lsocket
|
||||
endif
|
||||
|
||||
SRC := wrk.c aprintf.c stats.c units.c ae.c zmalloc.c http_parser.c tinymt64.c
|
||||
|
||||
@@ -33,6 +33,7 @@ static struct config {
|
||||
uint64_t connections;
|
||||
uint64_t requests;
|
||||
uint64_t timeout;
|
||||
uint64_t errors;
|
||||
} cfg;
|
||||
|
||||
static struct {
|
||||
@@ -50,6 +51,12 @@ static const struct http_parser_settings parser_settings = {
|
||||
.on_message_complete = request_complete
|
||||
};
|
||||
|
||||
static volatile sig_atomic_t stop = 0;
|
||||
|
||||
static void handler(int sig) {
|
||||
stop = 1;
|
||||
}
|
||||
|
||||
static void usage() {
|
||||
printf("Usage: wrk <options> <url> \n"
|
||||
" Options: \n"
|
||||
@@ -59,6 +66,7 @@ static void usage() {
|
||||
" \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");
|
||||
}
|
||||
@@ -104,14 +112,9 @@ int main(int argc, char **argv) {
|
||||
for (addr = addrs; addr != NULL; addr = addr->ai_next) {
|
||||
int fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||
if (fd == -1) continue;
|
||||
if (connect(fd, addr->ai_addr, addr->ai_addrlen) == -1) {
|
||||
if (errno == EHOSTUNREACH || errno == ECONNREFUSED) {
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
rc = connect(fd, addr->ai_addr, addr->ai_addrlen);
|
||||
close(fd);
|
||||
break;
|
||||
if (rc == 0) break;
|
||||
}
|
||||
|
||||
if (addr == NULL) {
|
||||
@@ -121,6 +124,7 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGINT, SIG_IGN);
|
||||
cfg.addr = *addr;
|
||||
request.buf = format_request(host, port, path, headers);
|
||||
request.size = strlen(request.buf);
|
||||
@@ -145,6 +149,13 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
}
|
||||
|
||||
struct sigaction sa = {
|
||||
.sa_handler = handler,
|
||||
.sa_flags = 0,
|
||||
};
|
||||
sigfillset(&sa.sa_mask);
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
|
||||
printf("Making %"PRIu64" requests to %s\n", cfg.requests, url);
|
||||
printf(" %"PRIu64" threads and %"PRIu64" connections\n", cfg.threads, cfg.connections);
|
||||
|
||||
@@ -320,6 +331,16 @@ 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) {
|
||||
aeStop(loop);
|
||||
}
|
||||
|
||||
return TIMEOUT_INTERVAL_MS;
|
||||
}
|
||||
|
||||
@@ -382,18 +403,24 @@ static char *extract_url_part(char *url, struct http_parser_url *parser_url, enu
|
||||
}
|
||||
|
||||
static char *format_request(char *host, char *port, char *path, char **headers) {
|
||||
char *req = NULL;
|
||||
|
||||
aprintf(&req, "GET %s HTTP/1.1\r\n", path);
|
||||
aprintf(&req, "Host: %s", host);
|
||||
if (port) aprintf(&req, ":%s", port);
|
||||
aprintf(&req, "\r\n");
|
||||
char *req = NULL;
|
||||
char *head = NULL;
|
||||
|
||||
for (char **h = headers; *h != NULL; h++) {
|
||||
aprintf(&req, "%s\r\n", *h);
|
||||
aprintf(&head, "%s\r\n", *h);
|
||||
if (!strncasecmp(*h, "Host:", 5)) {
|
||||
host = NULL;
|
||||
port = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
aprintf(&req, "\r\n");
|
||||
aprintf(&req, "GET %s HTTP/1.1\r\n", path);
|
||||
if (host) aprintf(&req, "Host: %s", host);
|
||||
if (port) aprintf(&req, ":%s", port);
|
||||
if (host) aprintf(&req, "\r\n");
|
||||
aprintf(&req, "%s\r\n", head ? head : "");
|
||||
|
||||
free(head);
|
||||
return req;
|
||||
}
|
||||
|
||||
@@ -402,6 +429,7 @@ static struct option longopts[] = {
|
||||
{ "requests", required_argument, NULL, 'r' },
|
||||
{ "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 }
|
||||
@@ -416,7 +444,7 @@ static int parse_args(struct config *cfg, char **url, char **headers, int argc,
|
||||
cfg->requests = 100;
|
||||
cfg->timeout = SOCKET_TIMEOUT_MS;
|
||||
|
||||
while ((c = getopt_long(argc, argv, "t:c:r:H:v?", longopts, NULL)) != -1) {
|
||||
while ((c = getopt_long(argc, argv, "t:c:r:E:H:v?", longopts, NULL)) != -1) {
|
||||
switch (c) {
|
||||
case 't':
|
||||
if (scan_metric(optarg, &cfg->threads)) return -1;
|
||||
@@ -427,6 +455,9 @@ static int parse_args(struct config *cfg, char **url, char **headers, int argc,
|
||||
case 'r':
|
||||
if (scan_metric(optarg, &cfg->requests)) return -1;
|
||||
break;
|
||||
case 'E':
|
||||
if (scan_metric(optarg, &cfg->errors)) return -1;
|
||||
break;
|
||||
case 'H':
|
||||
*header++ = optarg;
|
||||
break;
|
||||
@@ -449,6 +480,10 @@ static int parse_args(struct config *cfg, char **url, char **headers, int argc,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cfg->errors == 0) {
|
||||
cfg->errors = cfg->requests / cfg->threads / 10;
|
||||
}
|
||||
|
||||
*url = argv[optind];
|
||||
*header = NULL;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user