Skip to content

Commit

Permalink
add optional delay() script function
Browse files Browse the repository at this point in the history
  • Loading branch information
wg committed May 8, 2015
1 parent a209691 commit 0f8016c
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 3 deletions.
2 changes: 2 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
* delay() can return milliseconds to delay sending next request.

wrk 4.0.0

* The wrk global variable is the only global defined by default.
Expand Down
5 changes: 5 additions & 0 deletions SCRIPTING
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Overview

global setup -- called during thread setup
global init -- called when the thread is starting
global delay -- called to get the request delay
global request -- called to generate the HTTP request
global response -- called with HTTP response data
global done -- called with results of run
Expand All @@ -64,6 +65,7 @@ Setup
Running

function init(args)
function delay()
function request()
function response(status, headers, body)

Expand All @@ -73,6 +75,9 @@ Running
The init() function receives any extra command line arguments for the
script which must be separated from wrk arguments with "--".

delay() returns the number of milliseconds to delay sending the next
request.

request() returns a string containing the HTTP request. Building a new
request each time is expensive, when testing a high performance server
one solution is to pre-generate all requests in init() and do a quick
Expand Down
6 changes: 6 additions & 0 deletions scripts/delay.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- example script that demonstrates adding a random
-- 10-50ms delay before each request

function delay()
return math.random(10, 50)
end
12 changes: 12 additions & 0 deletions src/script.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,14 @@ void script_init(lua_State *L, thread *t, int argc, char **argv) {
lua_pop(t->L, 1);
}

uint64_t script_delay(lua_State *L) {
lua_getglobal(L, "delay");
lua_call(L, 0, 1);
uint64_t delay = lua_tonumber(L, -1);
lua_pop(L, 1);
return delay;
}

void script_request(lua_State *L, char **buf, size_t *len) {
int pop = 1;
lua_getglobal(L, "request");
Expand Down Expand Up @@ -189,6 +197,10 @@ bool script_want_response(lua_State *L) {
return script_is_function(L, "response");
}

bool script_has_delay(lua_State *L) {
return script_is_function(L, "delay");
}

bool script_has_done(lua_State *L) {
return script_is_function(L, "done");
}
Expand Down
2 changes: 2 additions & 0 deletions src/script.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ void script_setup(lua_State *, thread *);
void script_done(lua_State *, stats *, stats *);

void script_init(lua_State *, thread *, int, char **);
uint64_t script_delay(lua_State *);
void script_request(lua_State *, char **, size_t *);
void script_response(lua_State *, int, buffer *, buffer *);
size_t script_verify_request(lua_State *L);

bool script_is_static(lua_State *);
bool script_want_response(lua_State *L);
bool script_has_delay(lua_State *L);
bool script_has_done(lua_State *L);
void script_summary(lua_State *, uint64_t, uint64_t, uint64_t);
void script_errors(lua_State *, errors *);
Expand Down
24 changes: 21 additions & 3 deletions src/wrk.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
#include "main.h"

static struct config {
uint64_t threads;
uint64_t connections;
uint64_t duration;
uint64_t threads;
uint64_t timeout;
uint64_t pipeline;
bool latency;
bool delay;
bool dynamic;
bool latency;
char *script;
SSL_CTX *ctx;
} cfg;
Expand Down Expand Up @@ -107,7 +108,8 @@ int main(int argc, char **argv) {

if (i == 0) {
cfg.pipeline = script_verify_request(t->L);
cfg.dynamic = !script_is_static(t->L);
cfg.dynamic = !script_is_static(t->L);
cfg.delay = script_has_delay(t->L);
if (script_want_response(t->L)) {
parser_settings.on_header_field = header_field;
parser_settings.on_header_value = header_value;
Expand Down Expand Up @@ -212,6 +214,7 @@ void *thread_main(void *arg) {
c->ssl = cfg.ctx ? SSL_new(cfg.ctx) : NULL;
c->request = request;
c->length = length;
c->delayed = cfg.delay;
connect_socket(thread, c);
}

Expand Down Expand Up @@ -282,6 +285,13 @@ static int record_rate(aeEventLoop *loop, long long id, void *data) {
return RECORD_INTERVAL_MS;
}

static int delay_request(aeEventLoop *loop, long long id, void *data) {
connection *c = data;
c->delayed = false;
aeCreateFileEvent(loop, c->fd, AE_WRITABLE, socket_writeable, c);
return AE_NOMORE;
}

static int header_field(http_parser *parser, const char *at, size_t len) {
connection *c = parser->data;
if (c->state == VALUE) {
Expand Down Expand Up @@ -331,6 +341,7 @@ static int response_complete(http_parser *parser) {
if (!stats_record(statistics.latency, now - c->start)) {
thread->errors.timeout++;
}
c->delayed = cfg.delay;
aeCreateFileEvent(thread->loop, c->fd, AE_WRITABLE, socket_writeable, c);
}

Expand Down Expand Up @@ -371,6 +382,13 @@ static void socket_writeable(aeEventLoop *loop, int fd, void *data, int mask) {
connection *c = data;
thread *thread = c->thread;

if (c->delayed) {
uint64_t delay = script_delay(thread->L);
aeDeleteFileEvent(loop, fd, AE_WRITABLE);
aeCreateTimeEvent(loop, delay, delay_request, c, NULL);
return;
}

if (!c->written) {
if (cfg.dynamic) {
script_request(thread->L, &c->request, &c->length);
Expand Down
1 change: 1 addition & 0 deletions src/wrk.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ typedef struct connection {
} state;
int fd;
SSL *ssl;
bool delayed;
uint64_t start;
char *request;
size_t length;
Expand Down

0 comments on commit 0f8016c

Please sign in to comment.