main
Sean McBride 4 years ago
parent 2bed1bf2e3
commit 7bf48e3aaa

@ -12,7 +12,8 @@ CC_OPTIONS = -O3 -flto -g -pthread -D_GNU_SOURCE
BINARY_NAME=sledgert
# Number of Cores. Options: {2...N or TOTAL_CORES}
NCORES = ${TOTAL_CORES}
# NCORES = ${TOTAL_CORES}
NCORES = 2
# Options: {USE_MEM_GENERIC, USE_MEM_VM}
USE_MEM = USE_MEM_VM
@ -20,19 +21,19 @@ USE_MEM = USE_MEM_VM
# Debugging Flags
# Strips out calls to assert()
CFLAGS += -DNDEBUG
# CFLAGS += -DNDEBUG
# Turns on debuglog and other assorted printfs in third party libs
# CFLAGS += -DDEBUG
CFLAGS += -DDEBUG
# Redirects debuglogs to /runtime/bin/awesome.log
#FIXME This log should be changed to sledge.log (and likely to a user defined path)
# CFLAGS += -DLOG_TO_FILE
# Various Informational Logs for Debugging
# CFLAGS += -DLOG_STATE_CHANGES
CFLAGS += -DLOG_STATE_CHANGES
# CFLAGS += -DLOG_LOCK_OVERHEAD
# CFLAGS += -DLOG_CONTEXT_SWITCHES
CFLAGS += -DLOG_CONTEXT_SWITCHES
# CFLAGS += -DLOG_ADMISSIONS_CONTROL
# CFLAGS += -DLOG_SANDBOX_PERF
# CFLAGS += -DLOG_REQUEST_ALLOCATION
@ -42,16 +43,19 @@ CFLAGS += -DNDEBUG
# This flag dumps totals of incoming requests and outgoing responses, broken out by status code
# family, such as 2XX, 4XX, 5XX. It is useful to debug clients hanging waiting for a response.
# To log, run `call runtime_log_requests_responses()` while in GDB
# CFLAGS += -DLOG_TOTAL_REQS_RESPS
CFLAGS += -DLOG_TOTAL_REQS_RESPS
# This flag logs the total number of sandboxes in the various states
# It is useful to debug if sandboxes are "getting caught" in a particular state
# To log, run `call runtime_log_sandbox_states()` while in GDB
# CFLAGS += -DLOG_SANDBOX_TOTALS
CFLAGS += -DLOG_SANDBOX_TOTALS
# This flag enables an per-worker atomic count of sandbox's local runqueue count in thread local storage
# Useful to debug if sandboxes are "getting caught" or "leaking" while in a local runqueue
# CFLAGS += -DLOG_LOCAL_RUNQUEUE
CFLAGS += -DLOG_LOCAL_RUNQUEUE
# Debug the HTTP Parser
CFLAGS += -DLOG_HTTP_PARSER
# System Configuraiton Flags

@ -25,6 +25,7 @@ libuv_callbacks_on_read_parse_http_request(uv_stream_t *stream, ssize_t number_r
/* Parse the chunks libuv has read on our behalf until we've parse to message end */
if (number_read > 0) {
// FIXME: Broken by refactor to sandbox_parse_http_request changes to return code
if (sandbox_parse_http_request(sandbox, number_read) != 0) return;
sandbox->request_response_data_length += number_read;
struct http_request *rh = &sandbox->http_request;

@ -99,6 +99,7 @@ struct sandbox {
uv_tcp_t client_libuv_stream;
uv_shutdown_t client_libuv_shutdown_request;
bool is_repeat_header;
http_parser http_parser;
struct http_request http_request;
struct http_response http_response;
@ -137,7 +138,7 @@ struct sandbox *sandbox_allocate(struct sandbox_request *sandbox_request);
void sandbox_free(struct sandbox *sandbox);
void sandbox_free_linear_memory(struct sandbox *sandbox);
void sandbox_main(struct sandbox *sandbox);
int sandbox_parse_http_request(struct sandbox *sandbox, size_t length);
size_t sandbox_parse_http_request(struct sandbox *sandbox, size_t length);
static inline char *
sandbox_state_stringify(sandbox_state_t state)

@ -54,7 +54,7 @@ current_sandbox_initialize_io_handle(void)
return sandbox_initialize_io_handle(current_sandbox_get());
}
int sandbox_parse_http_request(struct sandbox *sandbox, size_t l);
size_t sandbox_parse_http_request(struct sandbox *sandbox, size_t l);
/**
* Sets the file descriptor of the sandbox's ith io_handle

@ -24,8 +24,13 @@ int
http_parser_settings_on_url(http_parser *parser, const char *at, size_t length)
{
struct sandbox *sandbox = (struct sandbox *)parser->data;
if (sandbox->http_request.message_end || sandbox->http_request.header_end) return 0;
#ifdef LOG_HTTP_PARSER
debuglog("sandbox: %lu\n", sandbox->request_arrival_timestamp);
assert(strncmp(sandbox->module->name, (at + 1), length - 1) == 0);
#endif
return 0;
}
@ -40,8 +45,14 @@ http_parser_settings_on_message_begin(http_parser *parser)
struct sandbox * sandbox = (struct sandbox *)parser->data;
struct http_request *http_request = &sandbox->http_request;
http_request->message_begin = 1;
http_request->last_was_value = 1; /* should always start with a header */
if (sandbox->http_request.message_end || sandbox->http_request.header_end) return 0;
#ifdef LOG_HTTP_PARSER
debuglog("sandbox: %lu\n", sandbox->request_arrival_timestamp);
#endif
http_request->message_begin = true;
http_request->last_was_value = true; /* should always start with a header */
return 0;
}
@ -60,14 +71,45 @@ http_parser_settings_on_header_field(http_parser *parser, const char *at, size_t
struct sandbox * sandbox = (struct sandbox *)parser->data;
struct http_request *http_request = &sandbox->http_request;
if (http_request->last_was_value) http_request->header_count++;
assert(http_request->header_count <= HTTP_MAX_HEADER_COUNT);
assert(length < HTTP_MAX_HEADER_LENGTH);
if (sandbox->http_request.message_end || sandbox->http_request.header_end) return 0;
http_request->last_was_value = 0;
// idef parser debug
#ifdef LOG_HTTP_PARSER
debuglog("sandbox: %lu\n", sandbox->request_arrival_timestamp);
#endif
/* it is from the sandbox's request_response_data, should persist. */
http_request->headers[http_request->header_count - 1].key = (char *)at;
/* Previous name continues */
if (http_request->last_was_value == false) {
assert(http_request->header_count > 0);
strncat(http_request->headers[http_request->header_count].key, at, length);
return 0;
}
/*
* We receive repeat headers for an unknown reason, so we need to ignore repeat headers
* This probably means that the headers are getting reparsed, so for the sake of performance
* this should be fixed upstream
*/
#ifdef LOG_HTTP_PARSER
for (int i = 0; i < http_request->header_count; i++) {
if (strncmp(http_request->headers[i].key, at, length) == 0) {
debuglog("Repeat header!\n");
assert(0);
sandbox->is_repeat_header = true;
break;
}
}
#endif
if (!sandbox->is_repeat_header) {
if (unlikely(http_request->header_count <= HTTP_MAX_HEADER_COUNT)) { return -1; }
if (unlikely(length < HTTP_MAX_HEADER_LENGTH)) { return -1; }
http_request->headers[http_request->header_count++].key = (char *)at;
http_request->last_was_value = false;
sandbox->is_repeat_header = false;
}
return 0;
}
@ -86,13 +128,21 @@ http_parser_settings_on_header_value(http_parser *parser, const char *at, size_t
struct sandbox * sandbox = (struct sandbox *)parser->data;
struct http_request *http_request = &sandbox->http_request;
http_request->last_was_value = 1;
assert(http_request->header_count <= HTTP_MAX_HEADER_COUNT);
assert(length < HTTP_MAX_HEADER_VALUE_LENGTH);
if (http_request->message_end || http_request->header_end) return 0;
/* it is from the sandbox's request_response_data, should persist. */
http_request->headers[http_request->header_count - 1].value = (char *)at;
#ifdef LOG_HTTP_PARSER
debuglog("sandbox: %lu\n", sandbox->request_arrival_timestamp);
#endif
// TODO: If last_was_value is already true, we might need to append to value
/* it is from the sandbox's request_response_data, should persist. */
if (!sandbox->is_repeat_header) {
if (unlikely(length < HTTP_MAX_HEADER_VALUE_LENGTH)) { return -1; }
http_request->headers[http_request->header_count - 1].value = (char *)at;
http_request->last_was_value = true;
}
return 0;
}
@ -106,17 +156,23 @@ http_parser_settings_on_header_end(http_parser *parser)
{
struct sandbox * sandbox = (struct sandbox *)parser->data;
struct http_request *http_request = &sandbox->http_request;
if (http_request->message_end || http_request->header_end) return 0;
#ifdef LOG_HTTP_PARSER
debuglog("sandbox: %lu\n", sandbox->request_arrival_timestamp);
#endif
http_request->header_end = 1;
http_request->header_end = true;
return 0;
}
/**
* http-parser callback called for HTTP Bodies
* Assigns the parsed data to the http_request body of the sandbox struct
* Presumably, this might only be part of the body
* @param parser
* @param at
* @param length
* @param at - start address of body
* @param length - length of body
* @returns 0
*/
int
@ -125,13 +181,37 @@ http_parser_settings_on_body(http_parser *parser, const char *at, size_t length)
struct sandbox * sandbox = (struct sandbox *)parser->data;
struct http_request *http_request = &sandbox->http_request;
if (http_request->message_end) return 0;
#ifdef LOG_HTTP_PARSER
debuglog("sandbox: %lu\n", sandbox->request_arrival_timestamp);
#endif
/* Assumption: We should never exceed the buffer we're reusing */
assert(http_request->body_length + length <= sandbox->module->max_request_size);
if (!http_request->body)
http_request->body = (char *)at;
else
assert(http_request->body + http_request->body_length == at);
http_request->body_length += length;
if (!http_request->body) {
/* If this is the first invocation of the callback, just set */
http_request->body = (char *)at;
http_request->body_length = length;
} else {
#ifdef LOG_HTTP_PARSER
debuglog("Body: %p, Existing Length: %d\n", http_request->body, http_request->body_length);
debuglog("Expected Offset %d, Actual Offset: %lu\n", http_request->body_length,
at - http_request->body);
/* Attempt to copy and print the entire body */
uint64_t possible_body_len = at - http_request->body;
char test_buffer[possible_body_len + length + 1];
strncpy(test_buffer, http_request->body, possible_body_len);
test_buffer[length] = '\0';
debuglog("http_parser_settings_on_body: len %lu, content: %s\n", possible_body_len, test_buffer);
#endif
http_request->body_length += length;
}
return 0;
}
@ -147,7 +227,12 @@ http_parser_settings_on_msg_end(http_parser *parser)
struct sandbox * sandbox = (struct sandbox *)parser->data;
struct http_request *http_request = &sandbox->http_request;
http_request->message_end = 1;
if (http_request->message_end) return 0;
#ifdef LOG_HTTP_PARSER
debuglog("sandbox: %lu\n", sandbox->request_arrival_timestamp);
#endif
http_request->message_end = true;
return 0;
}

@ -47,34 +47,6 @@ sandbox_setup_arguments(struct sandbox *sandbox)
stub_init(string_off);
}
/**
* Run the http-parser on the next N bytes of the sandbox's request_response_data buffer
* Success means that a "chunk" was fully parsed, not that parsing of a full request is complete
* @param sandbox the sandbox containing that we want to parse
* @param length The size of the data that we want to parse
* @returns 0 on success, -1 on failure
*/
int
sandbox_parse_http_request(struct sandbox *sandbox, size_t length)
{
assert(sandbox != NULL);
if (length == 0) return 0;
/* Assumption: We shouldn't have anything left to parse if message was successfully parsed to completion */
if (unlikely(sandbox->http_request.message_end)) {
debuglog("Unexpectedly received client data after message was parsed to completion");
};
size_t length_parsed = http_parser_execute(&sandbox->http_parser, http_parser_settings_get(),
sandbox->request_response_data
+ sandbox->request_response_data_length,
length);
if (length_parsed != length) return -1;
return 0;
}
/**
* Receive and Parse the Request for the current sandbox
* @return 0 if message parsing complete, -1 on error
@ -92,9 +64,14 @@ sandbox_receive_and_parse_client_request(struct sandbox *sandbox)
while (!sandbox->http_request.message_end) {
/* Read from the Socket */
int length_read = recv(sandbox->client_socket_descriptor,
&sandbox->request_response_data[sandbox->request_response_data_length],
sandbox->module->max_request_size - sandbox->request_response_data_length, 0);
ssize_t length_read = recv(sandbox->client_socket_descriptor,
&sandbox->request_response_data[sandbox->request_response_data_length],
sandbox->module->max_request_size - sandbox->request_response_data_length,
0);
/* Unexpected client shutdown.. or is this just EOF */
if (length_read == 0 && !sandbox->http_request.message_end) goto err;
if (length_read < 0) {
if (errno == EAGAIN) {
worker_thread_block_current_sandbox();
@ -107,13 +84,35 @@ sandbox_receive_and_parse_client_request(struct sandbox *sandbox)
}
}
if (sandbox->http_request.message_end) break;
#ifdef LOG_HTTP_PARSER
debuglog("http_parser_execute(%p, %p, %p, %lu)", &sandbox->http_parser, http_parser_settings_get(),
&sandbox->request_response_data[sandbox->request_response_data_length], length_read);
#endif
http_parser_execute(&sandbox->http_parser, http_parser_settings_get(),
&sandbox->request_response_data[sandbox->request_response_data_length],
length_read);
/* Try to parse what we've read */
if (sandbox_parse_http_request(sandbox, length_read) < 0) {
/* TODO: Consider 0 as EOF? */
size_t length_parsed =
http_parser_execute(&sandbox->http_parser, http_parser_settings_get(),
&sandbox->request_response_data[sandbox->request_response_data_length],
length_read);
// size_t length_parsed = sandbox_parse_http_request(sandbox, length_read);
if (length_parsed != length_read) {
debuglog("Error parsing socket %d\n", sandbox->client_socket_descriptor);
goto err;
}
sandbox->request_response_data_length += length_read;
sandbox->request_response_data_length += length_parsed;
debuglog("After Read: %lu", sandbox->request_response_data_length);
}

@ -0,0 +1,19 @@
#!/bin/bash
# Executes the runtime in GDB
# Substitutes the absolute path from the container with a path relatively derived from the location of this script
# This allows debugging outside of the Docker container
# Also disables pagination and stopping on SIGUSR1
declare project_path="$(
cd "$(dirname "$1")/../.."
pwd
)"
echo $project_path
cd ../../bin
export LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH"
gdb --eval-command="handle SIGUSR1 nostop" \
--eval-command="set pagination off" \
--eval-command="set substitute-path /sledge/runtime $project_path" \
--eval-command="run ../tests/mixed_preemption/test_mixed_preemption.json" \
./sledgert
cd ../../tests

@ -0,0 +1,33 @@
#!/bin/bash
# cd ../../bin
# LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/mixed_preemption/test_mixed_preemption.json &
# cd ../tests/mixed_preemption/
# TODO: Run small samples on each port to let the runtime figure out the execution time
# ab -s 999999999 -v 4 -n 50 -c 1 -r -p ./req/fib10.txt localhost:10010/
# ab -s 999999999 -v 4 -n 50 -c 1 -r -p ./req/fib20.txt localhost:10020/
# ab -s 999999999 -v 4 -n 50 -c 1 -r -p ./req/fib25.txt localhost:10025/
# ab -s 999999999 -v 4 -n 50 -c 1 -r -p ./req/fib30.txt localhost:10030/
# ab -s 999999999 -v 4 -n 50 -c 1 -r -p ./req/fib35.txt localhost:10035/
wrk -d 10s -t1 -s post.lua http://localhost:10010 -- 2 10\n >/dev/null
# wrk -d 10s -t1 -s post.lua http://localhost:10030 -- 2 30\n >/dev/null
# wrk -d 1m -t1 -s post.lua http://localhost:10020 -- 2 20\n
# fib(10)
# sleep 2
# wrk -d 1m -t1 -s post.lua http://localhost:10010 -- 20 10\n >./res/fib10.txt
# wrk -d 1m -t1 -s post.lua http://localhost:10020 -- 2 20\n >./res/fib20.txt &
# wrk -d 1m -t1 -s post.lua http://localhost:10025 -- 2 25\n >./res/fib25.txt &
# wrk -d 1m -t1 -s post.lua http://localhost:10030 -- 2 30\n >./res/fib30.txt
# wrk -d 1m -t1 -s post.lua http://localhost:10035 -- 2 35\n
# ab -n 10000 -c 1 -r -p ./req/fib10.txt localhost:10000/ >./res/fib10.txt &
# ab -n 10000 -c 1 -r -p ./req/fib20.txt localhost:10001/ >./res/fib20.txt &
# ab -n 10000 -c 1 -r -p ./req/fib25.txt localhost:10002/ >./res/fib25.txt &
# ab -n 10000 -c 1 -r -p ./req/fib30.txt localhost:10030/ >./res/fib30.txt &
# ab -n 10000 -c 1 -r -p ./req/fib35.txt localhost:10035/ >./res/fib35.txt
# Kill the Background Sledge processes
# ps -e -o pid,cmd | grep sledgert | grep json | cut -d\ -f 1 | xargs kill
# pkill sledgert
# pkill ab
# pkill wrk

@ -0,0 +1,43 @@
-- Default to 1 request / second
wrk.method = "POST"
wrk.body = "10\n"
wrk.headers["Content-Type"] = "text/plain"
local delay_val = 1000
function init(args)
if #args >= 1 then
-- First argument is "requests per second" per thread
delay_val = (1000 / args[1])
end
if #args >= 2 then
-- Second argument is argument
wrk.body = args[2]
end
end
-- Uncomment to dynamically generate a different request each time
-- function request()
-- return wrk.format(nil, nil, nil,tostring(math.random(10, 23)) .."\n")
-- end
-- Wrk calls a function name delay to get the delay between requests (in ms)
function delay()
return delay_val
end
function response(status, headers, body)
io.write(string.format("%s: %s\n", status, body))
end
-- Done Phase
-- Called when complete, presenting aggregate results
function done(summary, latency, requests)
for i = 1, 99 do
io.write(string.format("%d %d\n", i, latency:percentile(i)))
end
end

@ -0,0 +1,107 @@
Running 1m test @ http://localhost:10010
1 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 0.00us 0.00us 0.00us -nan%
Req/Sec 0.00 0.00 0.00 -nan%
0 requests in 1.00m, 0.00B read
Requests/sec: 0.00
Transfer/sec: 0.00B
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 0
9 0
10 0
11 0
12 0
13 0
14 0
15 0
16 0
17 0
18 0
19 0
20 0
21 0
22 0
23 0
24 0
25 0
26 0
27 0
28 0
29 0
30 0
31 0
32 0
33 0
34 0
35 0
36 0
37 0
38 0
39 0
40 0
41 0
42 0
43 0
44 0
45 0
46 0
47 0
48 0
49 0
50 0
51 0
52 0
53 0
54 0
55 0
56 0
57 0
58 0
59 0
60 0
61 0
62 0
63 0
64 0
65 0
66 0
67 0
68 0
69 0
70 0
71 0
72 0
73 0
74 0
75 0
76 0
77 0
78 0
79 0
80 0
81 0
82 0
83 0
84 0
85 0
86 0
87 0
88 0
89 0
90 0
91 0
92 0
93 0
94 0
95 0
96 0
97 0
98 0
99 0

@ -0,0 +1,70 @@
{
"active": "yes",
"name": "fibonacci_10",
"path": "fibonacci_wasm.so",
"port": 10010,
"relative-deadline-us": 4000,
"argsize": 1,
"http-req-headers": [],
"http-req-content-type": "text/plain",
"http-req-size": 1024,
"http-resp-headers": [],
"http-resp-size": 1024,
"http-resp-content-type": "text/plain"
},
{
"active": "yes",
"name": "fibonacci_20",
"path": "fibonacci_wasm.so",
"port": 10020,
"relative-deadline-us": 5000,
"argsize": 1,
"http-req-headers": [],
"http-req-content-type": "text/plain",
"http-req-size": 1024,
"http-resp-headers": [],
"http-resp-size": 1024,
"http-resp-content-type": "text/plain"
},
{
"active": "yes",
"name": "fibonacci_25",
"path": "fibonacci_wasm.so",
"port": 10025,
"relative-deadline-us": 6000,
"argsize": 1,
"http-req-headers": [],
"http-req-content-type": "text/plain",
"http-req-size": 1024,
"http-resp-headers": [],
"http-resp-size": 1024,
"http-resp-content-type": "text/plain"
},
{
"active": "yes",
"name": "fibonacci_30",
"path": "fibonacci_wasm.so",
"port": 10030,
"relative-deadline-us": 8000,
"argsize": 1,
"http-req-headers": [],
"http-req-content-type": "text/plain",
"http-req-size": 1024,
"http-resp-headers": [],
"http-resp-size": 1024,
"http-resp-content-type": "text/plain"
},
{
"active": "yes",
"name": "fibonacci_35",
"path": "fibonacci_wasm.so",
"port": 10035,
"relative-deadline-us": 53000,
"argsize": 1,
"http-req-headers": [],
"http-req-content-type": "text/plain",
"http-req-size": 1024,
"http-resp-headers": [],
"http-resp-size": 1024,
"http-resp-content-type": "text/plain"
}
Loading…
Cancel
Save