mirror of
https://github.com/wg/wrk
synced 2026-06-09 16:43:42 +08:00
Compare commits
4 Commits
@@ -4,7 +4,7 @@ LIBS := -lpthread -lm
|
|||||||
TARGET := $(shell uname -s | tr [A-Z] [a-z] 2>/dev/null || echo unknown)
|
TARGET := $(shell uname -s | tr [A-Z] [a-z] 2>/dev/null || echo unknown)
|
||||||
|
|
||||||
ifeq ($(TARGET), sunos)
|
ifeq ($(TARGET), sunos)
|
||||||
CFLAGS += -D_PTHREADS
|
CFLAGS += -D_PTHREADS -D_POSIX_C_SOURCE=200112L
|
||||||
LIBS += -lsocket
|
LIBS += -lsocket
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ static struct config {
|
|||||||
uint64_t connections;
|
uint64_t connections;
|
||||||
uint64_t requests;
|
uint64_t requests;
|
||||||
uint64_t timeout;
|
uint64_t timeout;
|
||||||
|
uint64_t errors;
|
||||||
} cfg;
|
} cfg;
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
@@ -50,6 +51,12 @@ static const struct http_parser_settings parser_settings = {
|
|||||||
.on_message_complete = request_complete
|
.on_message_complete = request_complete
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static volatile sig_atomic_t stop = 0;
|
||||||
|
|
||||||
|
static void handler(int sig) {
|
||||||
|
stop = 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void usage() {
|
static void usage() {
|
||||||
printf("Usage: wrk <options> <url> \n"
|
printf("Usage: wrk <options> <url> \n"
|
||||||
" Options: \n"
|
" Options: \n"
|
||||||
@@ -59,6 +66,7 @@ static void usage() {
|
|||||||
" \n"
|
" \n"
|
||||||
" -H, --header <h> Add header to request \n"
|
" -H, --header <h> Add header to request \n"
|
||||||
" -v, --version Print version details \n"
|
" -v, --version Print version details \n"
|
||||||
|
" --errors <n> Abort after N errors \n"
|
||||||
" \n"
|
" \n"
|
||||||
" Numeric arguments may include a SI unit (2k, 2M, 2G)\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) {
|
for (addr = addrs; addr != NULL; addr = addr->ai_next) {
|
||||||
int fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
int fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||||
if (fd == -1) continue;
|
if (fd == -1) continue;
|
||||||
if (connect(fd, addr->ai_addr, addr->ai_addrlen) == -1) {
|
rc = connect(fd, addr->ai_addr, addr->ai_addrlen);
|
||||||
if (errno == EHOSTUNREACH || errno == ECONNREFUSED) {
|
|
||||||
close(fd);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(fd);
|
close(fd);
|
||||||
break;
|
if (rc == 0) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addr == NULL) {
|
if (addr == NULL) {
|
||||||
@@ -121,6 +124,7 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
signal(SIGINT, SIG_IGN);
|
||||||
cfg.addr = *addr;
|
cfg.addr = *addr;
|
||||||
request.buf = format_request(host, port, path, headers);
|
request.buf = format_request(host, port, path, headers);
|
||||||
request.size = strlen(request.buf);
|
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("Making %"PRIu64" requests to %s\n", cfg.requests, url);
|
||||||
printf(" %"PRIu64" threads and %"PRIu64" connections\n", cfg.threads, cfg.connections);
|
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;
|
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) {
|
static char *format_request(char *host, char *port, char *path, char **headers) {
|
||||||
char *req = NULL;
|
char *req = NULL;
|
||||||
|
char *head = 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");
|
|
||||||
|
|
||||||
for (char **h = headers; *h != NULL; h++) {
|
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;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -402,6 +429,7 @@ static struct option longopts[] = {
|
|||||||
{ "requests", required_argument, NULL, 'r' },
|
{ "requests", required_argument, NULL, 'r' },
|
||||||
{ "threads", required_argument, NULL, 't' },
|
{ "threads", required_argument, NULL, 't' },
|
||||||
{ "header", required_argument, NULL, 'H' },
|
{ "header", required_argument, NULL, 'H' },
|
||||||
|
{ "errors", required_argument, NULL, 'E' },
|
||||||
{ "help", no_argument, NULL, 'h' },
|
{ "help", no_argument, NULL, 'h' },
|
||||||
{ "version", no_argument, NULL, 'v' },
|
{ "version", no_argument, NULL, 'v' },
|
||||||
{ NULL, 0, NULL, 0 }
|
{ 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->requests = 100;
|
||||||
cfg->timeout = SOCKET_TIMEOUT_MS;
|
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) {
|
switch (c) {
|
||||||
case 't':
|
case 't':
|
||||||
if (scan_metric(optarg, &cfg->threads)) return -1;
|
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':
|
case 'r':
|
||||||
if (scan_metric(optarg, &cfg->requests)) return -1;
|
if (scan_metric(optarg, &cfg->requests)) return -1;
|
||||||
break;
|
break;
|
||||||
|
case 'E':
|
||||||
|
if (scan_metric(optarg, &cfg->errors)) return -1;
|
||||||
|
break;
|
||||||
case 'H':
|
case 'H':
|
||||||
*header++ = optarg;
|
*header++ = optarg;
|
||||||
break;
|
break;
|
||||||
@@ -449,6 +480,10 @@ static int parse_args(struct config *cfg, char **url, char **headers, int argc,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cfg->errors == 0) {
|
||||||
|
cfg->errors = cfg->requests / cfg->threads / 10;
|
||||||
|
}
|
||||||
|
|
||||||
*url = argv[optind];
|
*url = argv[optind];
|
||||||
*header = NULL;
|
*header = NULL;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user