mirror of
https://github.com/wg/wrk
synced 2025-01-08 23:32:54 +08:00
add optional delay() script function
This commit is contained in:
parent
a20969192f
commit
0f8016c907
2
CHANGES
2
CHANGES
@ -1,3 +1,5 @@
|
|||||||
|
* delay() can return milliseconds to delay sending next request.
|
||||||
|
|
||||||
wrk 4.0.0
|
wrk 4.0.0
|
||||||
|
|
||||||
* The wrk global variable is the only global defined by default.
|
* The wrk global variable is the only global defined by default.
|
||||||
|
@ -38,6 +38,7 @@ Overview
|
|||||||
|
|
||||||
global setup -- called during thread setup
|
global setup -- called during thread setup
|
||||||
global init -- called when the thread is starting
|
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 request -- called to generate the HTTP request
|
||||||
global response -- called with HTTP response data
|
global response -- called with HTTP response data
|
||||||
global done -- called with results of run
|
global done -- called with results of run
|
||||||
@ -64,6 +65,7 @@ Setup
|
|||||||
Running
|
Running
|
||||||
|
|
||||||
function init(args)
|
function init(args)
|
||||||
|
function delay()
|
||||||
function request()
|
function request()
|
||||||
function response(status, headers, body)
|
function response(status, headers, body)
|
||||||
|
|
||||||
@ -73,6 +75,9 @@ Running
|
|||||||
The init() function receives any extra command line arguments for the
|
The init() function receives any extra command line arguments for the
|
||||||
script which must be separated from wrk arguments with "--".
|
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() returns a string containing the HTTP request. Building a new
|
||||||
request each time is expensive, when testing a high performance server
|
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
|
one solution is to pre-generate all requests in init() and do a quick
|
||||||
|
6
scripts/delay.lua
Normal file
6
scripts/delay.lua
Normal file
@ -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
src/script.c
12
src/script.c
@ -141,6 +141,14 @@ void script_init(lua_State *L, thread *t, int argc, char **argv) {
|
|||||||
lua_pop(t->L, 1);
|
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) {
|
void script_request(lua_State *L, char **buf, size_t *len) {
|
||||||
int pop = 1;
|
int pop = 1;
|
||||||
lua_getglobal(L, "request");
|
lua_getglobal(L, "request");
|
||||||
@ -189,6 +197,10 @@ bool script_want_response(lua_State *L) {
|
|||||||
return script_is_function(L, "response");
|
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) {
|
bool script_has_done(lua_State *L) {
|
||||||
return script_is_function(L, "done");
|
return script_is_function(L, "done");
|
||||||
}
|
}
|
||||||
|
@ -16,12 +16,14 @@ void script_setup(lua_State *, thread *);
|
|||||||
void script_done(lua_State *, stats *, stats *);
|
void script_done(lua_State *, stats *, stats *);
|
||||||
|
|
||||||
void script_init(lua_State *, thread *, int, char **);
|
void script_init(lua_State *, thread *, int, char **);
|
||||||
|
uint64_t script_delay(lua_State *);
|
||||||
void script_request(lua_State *, char **, size_t *);
|
void script_request(lua_State *, char **, size_t *);
|
||||||
void script_response(lua_State *, int, buffer *, buffer *);
|
void script_response(lua_State *, int, buffer *, buffer *);
|
||||||
size_t script_verify_request(lua_State *L);
|
size_t script_verify_request(lua_State *L);
|
||||||
|
|
||||||
bool script_is_static(lua_State *);
|
bool script_is_static(lua_State *);
|
||||||
bool script_want_response(lua_State *L);
|
bool script_want_response(lua_State *L);
|
||||||
|
bool script_has_delay(lua_State *L);
|
||||||
bool script_has_done(lua_State *L);
|
bool script_has_done(lua_State *L);
|
||||||
void script_summary(lua_State *, uint64_t, uint64_t, uint64_t);
|
void script_summary(lua_State *, uint64_t, uint64_t, uint64_t);
|
||||||
void script_errors(lua_State *, errors *);
|
void script_errors(lua_State *, errors *);
|
||||||
|
22
src/wrk.c
22
src/wrk.c
@ -5,13 +5,14 @@
|
|||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
||||||
static struct config {
|
static struct config {
|
||||||
uint64_t threads;
|
|
||||||
uint64_t connections;
|
uint64_t connections;
|
||||||
uint64_t duration;
|
uint64_t duration;
|
||||||
|
uint64_t threads;
|
||||||
uint64_t timeout;
|
uint64_t timeout;
|
||||||
uint64_t pipeline;
|
uint64_t pipeline;
|
||||||
bool latency;
|
bool delay;
|
||||||
bool dynamic;
|
bool dynamic;
|
||||||
|
bool latency;
|
||||||
char *script;
|
char *script;
|
||||||
SSL_CTX *ctx;
|
SSL_CTX *ctx;
|
||||||
} cfg;
|
} cfg;
|
||||||
@ -108,6 +109,7 @@ int main(int argc, char **argv) {
|
|||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
cfg.pipeline = script_verify_request(t->L);
|
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)) {
|
if (script_want_response(t->L)) {
|
||||||
parser_settings.on_header_field = header_field;
|
parser_settings.on_header_field = header_field;
|
||||||
parser_settings.on_header_value = header_value;
|
parser_settings.on_header_value = header_value;
|
||||||
@ -212,6 +214,7 @@ void *thread_main(void *arg) {
|
|||||||
c->ssl = cfg.ctx ? SSL_new(cfg.ctx) : NULL;
|
c->ssl = cfg.ctx ? SSL_new(cfg.ctx) : NULL;
|
||||||
c->request = request;
|
c->request = request;
|
||||||
c->length = length;
|
c->length = length;
|
||||||
|
c->delayed = cfg.delay;
|
||||||
connect_socket(thread, c);
|
connect_socket(thread, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,6 +285,13 @@ static int record_rate(aeEventLoop *loop, long long id, void *data) {
|
|||||||
return RECORD_INTERVAL_MS;
|
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) {
|
static int header_field(http_parser *parser, const char *at, size_t len) {
|
||||||
connection *c = parser->data;
|
connection *c = parser->data;
|
||||||
if (c->state == VALUE) {
|
if (c->state == VALUE) {
|
||||||
@ -331,6 +341,7 @@ static int response_complete(http_parser *parser) {
|
|||||||
if (!stats_record(statistics.latency, now - c->start)) {
|
if (!stats_record(statistics.latency, now - c->start)) {
|
||||||
thread->errors.timeout++;
|
thread->errors.timeout++;
|
||||||
}
|
}
|
||||||
|
c->delayed = cfg.delay;
|
||||||
aeCreateFileEvent(thread->loop, c->fd, AE_WRITABLE, socket_writeable, c);
|
aeCreateFileEvent(thread->loop, c->fd, AE_WRITABLE, socket_writeable, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,6 +382,13 @@ static void socket_writeable(aeEventLoop *loop, int fd, void *data, int mask) {
|
|||||||
connection *c = data;
|
connection *c = data;
|
||||||
thread *thread = c->thread;
|
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 (!c->written) {
|
||||||
if (cfg.dynamic) {
|
if (cfg.dynamic) {
|
||||||
script_request(thread->L, &c->request, &c->length);
|
script_request(thread->L, &c->request, &c->length);
|
||||||
|
Loading…
Reference in New Issue
Block a user