From e2e95d7942a79a1aac2bf291bfd59582a943c075 Mon Sep 17 00:00:00 2001 From: xiaosuGW Date: Mon, 13 Feb 2023 11:28:56 -0700 Subject: [PATCH 001/198] replace http by eRPC --- runtime/Makefile | 12 +++-- runtime/include/http_router.h | 12 +++++ runtime/include/route.h | 1 + runtime/include/route_config.h | 10 ++++ runtime/include/route_config_parse.h | 10 ++++ runtime/src/listener_thread.c | 72 ++++++++++++++++++++++++++++ 6 files changed, 114 insertions(+), 3 deletions(-) diff --git a/runtime/Makefile b/runtime/Makefile index a90f1b351..3ee3b313e 100644 --- a/runtime/Makefile +++ b/runtime/Makefile @@ -13,6 +13,8 @@ CFLAGS=-std=c18 -pthread # sched_getcpu, MAP_ANONYMOUS, acceess to 'gregs' in 'mcontext_t', REG_RIP, REG_RSP CFLAGS+=-D_GNU_SOURCE +# Enable SLEDGE macro for erpc c interface build +CFLAGS+=-DSLEDGE # Release Flags CFLAGS+=-O3 -flto @@ -112,11 +114,15 @@ CFLAGS += -D${ARCH} # the runtime to execute. The export-dynamic Linker flag adds all globals to the dynamic symbol table, # allowing the libraries acess to such symbols. The libm math library is used several places, including # in backing functions that implement the WebAssembly instruction set. -LDFLAGS += -Wl,--export-dynamic -ldl -lm +LDFLAGS += -Wl,--whole-archive -ldpdk -Wl,--no-whole-archive -Wl,--export-dynamic -ldl -lm -lstdc++ -lnuma -ldl -libverbs -lmlx4 -lmlx5 +LDFLAGS += -L ../../eRPC/c_interface/build # Our third-party dependencies build into a single dist directory to simplify configuration here. LDFLAGS += -Lthirdparty/dist/lib/ INCLUDES += -Iinclude/ -Ithirdparty/dist/include/ -I../libsledge/include/ +INCLUDES += -I../../eRPC/c_interface +INCLUDES += -I /usr/include/dpdk + # CFILES CFILES += src/*.c @@ -130,7 +136,7 @@ JSMNCFLAGS += -DJSMN_STRICT # Force sledgert to rebuild when header files change # This is a bit fragile, as it does not recurse subdirectories when detecting last changed times -HEADER_DEPS = thirdparty/dist/include/*.h include/*.h include/arch/x86_64/*.h include/arch/aarch64/*.h +HEADER_DEPS = thirdparty/dist/include/*.h include/*.h include/arch/x86_64/*.h include/arch/aarch64/*.h ../../eRPC/c_interface/*.h .PHONY: all all: thirdparty runtime @@ -142,7 +148,7 @@ clean: thirdparty.clean runtime.clean bin/${BINARY_NAME}: ${HEADER_DEPS} ${CFILES} @echo "Compiling runtime" @mkdir -p bin/ - @${CC} ${INCLUDES} ${CFLAGS} ${LDFLAGS} ${JSMNCFLAGS} -L/usr/lib/ ${CFILES} -o bin/${BINARY_NAME} + @${CC} ${INCLUDES} ${CFLAGS} ${LDFLAGS} ${JSMNCFLAGS} -L/usr/lib/ ${CFILES} -L../../eRPC/c_interface/build -lerpc_c_interface -o bin/${BINARY_NAME} .PHONY: runtime runtime: bin/${BINARY_NAME} diff --git a/runtime/include/http_router.h b/runtime/include/http_router.h index 3b8320610..a7059626e 100644 --- a/runtime/include/http_router.h +++ b/runtime/include/http_router.h @@ -63,6 +63,18 @@ http_router_match_route(http_router_t *router, char *route) return NULL; } +static inline struct route * +http_router_match_request_type(http_router_t *router, uint8_t request_type) +{ + for (int i = 0; i < router->length; i++) { + if (request_type == router->buffer[i].request_type) { + return &router->buffer[i]; + } + } + + return NULL; +} + static inline void http_router_foreach(http_router_t *router, void (*cb)(route_t *, void *, void *), void *arg_one, void *arg_two) { diff --git a/runtime/include/route.h b/runtime/include/route.h index a57493279..c549de089 100644 --- a/runtime/include/route.h +++ b/runtime/include/route.h @@ -11,6 +11,7 @@ /* Assumption: entrypoint is always _start. This should be enhanced later */ struct route { char *route; + uint8_t request_type; struct http_route_total metrics; struct module *module; /* HTTP State */ diff --git a/runtime/include/route_config.h b/runtime/include/route_config.h index 78b743b93..cc7053bd4 100644 --- a/runtime/include/route_config.h +++ b/runtime/include/route_config.h @@ -11,6 +11,7 @@ enum route_config_member { route_config_member_route, + route_config_member_request_type, route_config_member_path, route_config_member_admissions_percentile, route_config_member_expected_execution_us, @@ -21,6 +22,7 @@ enum route_config_member struct route_config { char *route; + uint8_t request_type; char *path; uint8_t admissions_percentile; uint32_t expected_execution_us; @@ -43,6 +45,8 @@ static inline void route_config_print(struct route_config *config) { printf("[Route] Route: %s\n", config->route); + printf("[Route] Request type: %hhu\n", config->request_type); + printf("[Route] Request type: %hhu\n", config->request_type); printf("[Route] Path: %s\n", config->path); printf("[Route] Admissions Percentile: %hhu\n", config->admissions_percentile); printf("[Route] Expected Execution (us): %u\n", config->expected_execution_us); @@ -63,6 +67,12 @@ route_config_validate(struct route_config *config, bool *did_set) return -1; } + if (did_set[route_config_member_request_type] == false) { + + fprintf(stderr, "request type field is required\n"); + return -1; + } + if (did_set[route_config_member_path] == false) { fprintf(stderr, "path field is required\n"); return -1; diff --git a/runtime/include/route_config_parse.h b/runtime/include/route_config_parse.h index f3a1be088..c7403df4a 100644 --- a/runtime/include/route_config_parse.h +++ b/runtime/include/route_config_parse.h @@ -7,6 +7,7 @@ #include "route_config.h" static const char *route_config_json_keys[route_config_member_len] = { "route", + "request-type", "path", "admissions-percentile", "expected-execution-us", @@ -56,6 +57,15 @@ route_config_parse(struct route_config *config, const char *json_buf, jsmntok_t if (route_config_set_key_once(did_set, route_config_member_route) == -1) return -1; config->route = strndup(json_buf + tokens[i].start, tokens[i].end - tokens[i].start); + } else if (strcmp(key, route_config_json_keys[route_config_member_request_type]) == 0) { + if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1; + if (route_config_set_key_once(did_set, route_config_member_request_type) == -1) + return -1; + + int rc = parse_uint8_t(tokens[i], json_buf, + route_config_json_keys[route_config_member_request_type], + &config->request_type); + if (rc < 0) return -1; } else if (strcmp(key, route_config_json_keys[route_config_member_path]) == 0) { if (!is_nonempty_string(tokens[i], key)) return -1; if (route_config_set_key_once(did_set, route_config_member_path) == -1) return -1; diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 7856016f9..4cc8ea0b4 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -1,6 +1,7 @@ #include #include +#include "erpc_c_interface.h" #include "arch/getcycles.h" #include "global_request_scheduler.h" #include "listener_thread.h" @@ -49,6 +50,10 @@ listener_thread_initialize(void) listener_thread_epoll_file_descriptor = epoll_create1(0); assert(listener_thread_epoll_file_descriptor >= 0); + /* erpc init */ + char *server_uri = "128.110.219.3:31850"; + erpc_init(server_uri, 0, 0); + int ret = pthread_create(&listener_thread_id, NULL, listener_thread_main, NULL); assert(ret == 0); ret = pthread_setaffinity_np(listener_thread_id, sizeof(cpu_set_t), &cs); @@ -388,6 +393,67 @@ on_client_socket_epoll_event(struct epoll_event *evt) } } +/** + * @brief Request routing function + * @param req_handle used by eRPC internal, it is used to send out the response packet + * @param req_type the type of the request. Each function has a unique reqest type id + * @param msg the payload of the rpc request. It is the input parameter fot the function + * @param size the size of the msg + */ +void (req_func) (void *req_handle, uint8_t req_type, uint8_t *msg, size_t size) { + printf("req_type is %d, msg %s size %zu\n", req_type, msg, size); + uint8_t kMsgSize = 16; + //TODO: rpc_id is hardcode now + assert(session->state == HTTP_SESSION_RECEIVED_REQUEST); + session->request_downloaded_timestamp = __getcycles(); + + struct route *route = http_router_match_route(&session->tenant->router, session->http_request.full_url); + if (route == NULL) { + debuglog("Did not match any routes\n"); + session->state = HTTP_SESSION_EXECUTION_COMPLETE; + http_session_set_response_header(session, 404); + on_client_response_header_sending(session); + return; + } + + session->route = route; + + /* + * Perform admissions control. + * If 0, workload was rejected, so close with 429 "Too Many Requests" and continue + * TODO: Consider providing a Retry-After header + */ + uint64_t work_admitted = admissions_control_decide(route->admissions_info.estimate); + if (work_admitted == 0) { + session->state = HTTP_SESSION_EXECUTION_COMPLETE; + http_session_set_response_header(session, 429); + on_client_response_header_sending(session); + return; + } + + /* Allocate a Sandbox */ + session->state = HTTP_SESSION_EXECUTING; + struct sandbox *sandbox = sandbox_alloc(route->module, session, route, session->tenant, work_admitted); + if (unlikely(sandbox == NULL)) { + debuglog("Failed to allocate sandbox\n"); + session->state = HTTP_SESSION_EXECUTION_COMPLETE; + http_session_set_response_header(session, 500); + on_client_response_header_sending(session); + return; + } + + /* If the global request scheduler is full, return a 429 to the client */ + if (unlikely(global_request_scheduler_add(sandbox) == NULL)) { + debuglog("Failed to add sandbox to global queue\n"); + sandbox_free(sandbox); + session->state = HTTP_SESSION_EXECUTION_COMPLETE; + http_session_set_response_header(session, 429); + on_client_response_header_sending(session); + } + + erpc_req_response_enqueue(0, req_handle, "hello world", kMsgSize); +} + /** * @brief Execution Loop of the listener core, io_handles HTTP requests, allocates sandbox request objects, and * pushes the sandbox object to the global dequeue @@ -410,6 +476,12 @@ listener_thread_main(void *dummy) // runtime_set_pthread_prio(pthread_self(), 2); pthread_setschedprio(pthread_self(), -20); + uint8_t rpc_id = 0; + uint8_t kReqType = 2; + erpc_register_req_func(kReqType, req_func, 0); + erpc_start(NULL, rpc_id, NULL, 0); + erpc_run_event_loop(rpc_id, 100000); + while (true) { /* Block indefinitely on the epoll file descriptor, waiting on up to a max number of events */ int descriptor_count = epoll_wait(listener_thread_epoll_file_descriptor, epoll_events, From e2e0842c59221d985f56c4666f342a020e659ea3 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Mon, 13 Feb 2023 13:55:29 -0700 Subject: [PATCH 002/198] make it work: Sledge receives a rpc request and parse the header and payload successfully --- runtime/Makefile | 8 +++--- runtime/src/listener_thread.c | 47 ----------------------------------- runtime/tests/fib.json | 20 +++++++++++++++ runtime/tests/start.sh | 42 +++++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 51 deletions(-) create mode 100644 runtime/tests/fib.json create mode 100755 runtime/tests/start.sh diff --git a/runtime/Makefile b/runtime/Makefile index 3ee3b313e..38df2f1f5 100644 --- a/runtime/Makefile +++ b/runtime/Makefile @@ -115,12 +115,12 @@ CFLAGS += -D${ARCH} # allowing the libraries acess to such symbols. The libm math library is used several places, including # in backing functions that implement the WebAssembly instruction set. LDFLAGS += -Wl,--whole-archive -ldpdk -Wl,--no-whole-archive -Wl,--export-dynamic -ldl -lm -lstdc++ -lnuma -ldl -libverbs -lmlx4 -lmlx5 -LDFLAGS += -L ../../eRPC/c_interface/build +LDFLAGS += -L /users/xiaosuGW/eRPC/c_interface/build # Our third-party dependencies build into a single dist directory to simplify configuration here. LDFLAGS += -Lthirdparty/dist/lib/ INCLUDES += -Iinclude/ -Ithirdparty/dist/include/ -I../libsledge/include/ -INCLUDES += -I../../eRPC/c_interface +INCLUDES += -I/users/xiaosuGW/eRPC/c_interface INCLUDES += -I /usr/include/dpdk @@ -136,7 +136,7 @@ JSMNCFLAGS += -DJSMN_STRICT # Force sledgert to rebuild when header files change # This is a bit fragile, as it does not recurse subdirectories when detecting last changed times -HEADER_DEPS = thirdparty/dist/include/*.h include/*.h include/arch/x86_64/*.h include/arch/aarch64/*.h ../../eRPC/c_interface/*.h +HEADER_DEPS = thirdparty/dist/include/*.h include/*.h include/arch/x86_64/*.h include/arch/aarch64/*.h /users/xiaosuGW/eRPC/c_interface/*.h .PHONY: all all: thirdparty runtime @@ -148,7 +148,7 @@ clean: thirdparty.clean runtime.clean bin/${BINARY_NAME}: ${HEADER_DEPS} ${CFILES} @echo "Compiling runtime" @mkdir -p bin/ - @${CC} ${INCLUDES} ${CFLAGS} ${LDFLAGS} ${JSMNCFLAGS} -L/usr/lib/ ${CFILES} -L../../eRPC/c_interface/build -lerpc_c_interface -o bin/${BINARY_NAME} + @${CC} ${INCLUDES} ${CFLAGS} ${LDFLAGS} ${JSMNCFLAGS} -L/usr/lib/ ${CFILES} -L/users/xiaosuGW/eRPC/c_interface/build -lerpc_c_interface -o bin/${BINARY_NAME} .PHONY: runtime runtime: bin/${BINARY_NAME} diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 4cc8ea0b4..1cbeec220 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -404,53 +404,6 @@ void (req_func) (void *req_handle, uint8_t req_type, uint8_t *msg, size_t size) printf("req_type is %d, msg %s size %zu\n", req_type, msg, size); uint8_t kMsgSize = 16; //TODO: rpc_id is hardcode now - assert(session->state == HTTP_SESSION_RECEIVED_REQUEST); - session->request_downloaded_timestamp = __getcycles(); - - struct route *route = http_router_match_route(&session->tenant->router, session->http_request.full_url); - if (route == NULL) { - debuglog("Did not match any routes\n"); - session->state = HTTP_SESSION_EXECUTION_COMPLETE; - http_session_set_response_header(session, 404); - on_client_response_header_sending(session); - return; - } - - session->route = route; - - /* - * Perform admissions control. - * If 0, workload was rejected, so close with 429 "Too Many Requests" and continue - * TODO: Consider providing a Retry-After header - */ - uint64_t work_admitted = admissions_control_decide(route->admissions_info.estimate); - if (work_admitted == 0) { - session->state = HTTP_SESSION_EXECUTION_COMPLETE; - http_session_set_response_header(session, 429); - on_client_response_header_sending(session); - return; - } - - /* Allocate a Sandbox */ - session->state = HTTP_SESSION_EXECUTING; - struct sandbox *sandbox = sandbox_alloc(route->module, session, route, session->tenant, work_admitted); - if (unlikely(sandbox == NULL)) { - debuglog("Failed to allocate sandbox\n"); - session->state = HTTP_SESSION_EXECUTION_COMPLETE; - http_session_set_response_header(session, 500); - on_client_response_header_sending(session); - return; - } - - /* If the global request scheduler is full, return a 429 to the client */ - if (unlikely(global_request_scheduler_add(sandbox) == NULL)) { - debuglog("Failed to add sandbox to global queue\n"); - sandbox_free(sandbox); - session->state = HTTP_SESSION_EXECUTION_COMPLETE; - http_session_set_response_header(session, 429); - on_client_response_header_sending(session); - } - erpc_req_response_enqueue(0, req_handle, "hello world", kMsgSize); } diff --git a/runtime/tests/fib.json b/runtime/tests/fib.json new file mode 100644 index 000000000..e743f03bd --- /dev/null +++ b/runtime/tests/fib.json @@ -0,0 +1,20 @@ +[ + { + "name": "gwu", + "port": 10030, + "replenishment-period-us": 0, + "max-budget-us": 0, + "routes": [ + { + "route": "/fib", + "request-type": 1, + "path": "fibonacci.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 4000, + "relative-deadline-us": 16000, + "http-resp-content-type": "text/plain" + } + ] + } +] + diff --git a/runtime/tests/start.sh b/runtime/tests/start.sh new file mode 100755 index 000000000..0bfc6ce61 --- /dev/null +++ b/runtime/tests/start.sh @@ -0,0 +1,42 @@ +#!/bin/bash +ulimit -n 655350 + +function usage { + echo "$0 [cpu cores]" + exit 1 +} + +if [ $# != 1 ] ; then + usage + exit 1; +fi + +core_num=$1 + +declare project_path="$( + cd "$(dirname "$0")/../.." + pwd +)" +echo $project_path +path=`pwd` +export SLEDGE_DISABLE_PREEMPTION=true +#export SLEDGE_SIGALRM_HANDLER=TRIAGED +export SLEDGE_NWORKERS=$core_num +#export SLEDGE_SCHEDULER=EDF +#export SLEDGE_SANDBOX_PERF_LOG=$path/$output +#echo $SLEDGE_SANDBOX_PERF_LOG +cd $project_path/runtime/bin +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_fibonacci.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_big_fibonacci.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_armcifar10.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_png2bmp.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_image_processing.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/mulitple_linear_chain.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing3.json +LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/fib.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/empty.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/my_fibonacci.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_sodresize.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/my_sodresize.json + From 5718adab5e207ffd5ef2b7ef9c8b00f9e44cfa07 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 15 Feb 2023 15:45:23 -0700 Subject: [PATCH 003/198] first working version to integrate eRPC, but some part are hardcode --- runtime/include/http_router.h | 10 ++++ runtime/include/runtime.h | 2 +- runtime/include/sandbox_functions.h | 3 +- runtime/include/sandbox_set_as_returned.h | 5 +- runtime/include/sandbox_types.h | 8 +++ runtime/include/tenant.h | 1 + runtime/include/tenant_functions.h | 6 +- runtime/src/current_sandbox.c | 4 +- runtime/src/libc/wasi_impl_serverless.c | 16 +++-- runtime/src/listener_thread.c | 73 +++++++++++++++++++---- runtime/src/main.c | 13 ++-- runtime/src/sandbox.c | 39 ++++++++++-- runtime/src/tenant_database.c | 9 +-- runtime/tests/fib.json | 2 +- 14 files changed, 142 insertions(+), 49 deletions(-) diff --git a/runtime/include/http_router.h b/runtime/include/http_router.h index a7059626e..d5863ebfe 100644 --- a/runtime/include/http_router.h +++ b/runtime/include/http_router.h @@ -3,6 +3,8 @@ #include #include +#include "erpc_handler.h" +#include "erpc_c_interface.h" #include "http.h" #include "module.h" #include "route_latency.h" @@ -10,6 +12,7 @@ #include "route_config.h" #include "vec.h" +//extern void (req_func) (void *req_handle, uint8_t req_type, uint8_t *msg, size_t size); typedef struct route route_t; VEC(route_t) @@ -31,6 +34,7 @@ http_router_add_route(http_router_t *router, struct route_config *config, struct assert(config->http_resp_content_type != NULL); struct route route = { .route = config->route, + .request_type = config->request_type, .module = module, .relative_deadline_us = config->relative_deadline_us, .relative_deadline = (uint64_t)config->relative_deadline_us @@ -40,6 +44,12 @@ http_router_add_route(http_router_t *router, struct route_config *config, struct route_latency_init(&route.latency); http_route_total_init(&route.metrics); + + /* Register RPC request handler */ + if (erpc_register_req_func(config->request_type, req_func, 0) != 0) { + panic("register erpc function failed\n"); + } + /* Admissions Control */ uint64_t expected_execution = (uint64_t)config->expected_execution_us * runtime_processor_speed_MHz; admissions_info_initialize(&route.admissions_info, config->admissions_percentile, expected_execution, diff --git a/runtime/include/runtime.h b/runtime/include/runtime.h index 4fe0ec27b..11eec7dbb 100644 --- a/runtime/include/runtime.h +++ b/runtime/include/runtime.h @@ -24,7 +24,7 @@ #define RUNTIME_LOG_FILE "sledge.log" #define RUNTIME_MAX_EPOLL_EVENTS 128 -#define RUNTIME_MAX_TENANT_COUNT 32 +#define RUNTIME_MAX_TENANT_COUNT 65535 /* Use UDP port to index tenent */ #define RUNTIME_RELATIVE_DEADLINE_US_MAX 3600000000 /* One Hour. Fits in uint32_t */ #define RUNTIME_RUNQUEUE_SIZE 256 /* Minimum guaranteed size. Might grow! */ #define RUNTIME_TENANT_QUEUE_SIZE 4096 diff --git a/runtime/include/sandbox_functions.h b/runtime/include/sandbox_functions.h index 754d40c9c..59f3915bd 100644 --- a/runtime/include/sandbox_functions.h +++ b/runtime/include/sandbox_functions.h @@ -13,11 +13,12 @@ **************************/ struct sandbox *sandbox_alloc(struct module *module, struct http_session *session, struct route *route, - struct tenant *tenant, uint64_t admissions_estimate); + struct tenant *tenant, uint64_t admissions_estimate, void *req_handle); int sandbox_prepare_execution_environment(struct sandbox *sandbox); void sandbox_free(struct sandbox *sandbox); void sandbox_main(struct sandbox *sandbox); void sandbox_switch_to(struct sandbox *next_sandbox); +void sandbox_send_response(struct sandbox *sandbox, uint8_t response_code); /** * Free Linear Memory, leaving stack in place diff --git a/runtime/include/sandbox_set_as_returned.h b/runtime/include/sandbox_set_as_returned.h index 2eec1bf2d..589b052bb 100644 --- a/runtime/include/sandbox_set_as_returned.h +++ b/runtime/include/sandbox_set_as_returned.h @@ -51,10 +51,7 @@ sandbox_set_as_returned(struct sandbox *sandbox, sandbox_state_t last_state) sandbox_state_totals_increment(SANDBOX_RETURNED); sandbox_state_totals_decrement(last_state); - http_session_set_response_header(sandbox->http, 200); - sandbox->http->state = HTTP_SESSION_EXECUTION_COMPLETE; - http_session_send_response(sandbox->http, (void_star_cb)listener_thread_register_http_session); - sandbox->http = NULL; + sandbox_send_response(sandbox, 0); /* State Change Hooks */ sandbox_state_transition_from_hook(sandbox, last_state); diff --git a/runtime/include/sandbox_types.h b/runtime/include/sandbox_types.h index 796c4b3ae..d5f8225a0 100644 --- a/runtime/include/sandbox_types.h +++ b/runtime/include/sandbox_types.h @@ -66,6 +66,14 @@ struct sandbox { deadline (cycles) */ uint64_t total_time; /* Total time from Request to Response */ + void *rpc_handler; + uint8_t *rpc_request_body; + size_t rpc_request_body_size; + /* Runtime state used by WASI */ + int cursor; /* Sandbox cursor (offset from body pointer) */ + struct auto_buf response_body; + //size_t response_body_written; + /* System Interface State */ int32_t return_value; wasi_context_t *wasi_context; diff --git a/runtime/include/tenant.h b/runtime/include/tenant.h index 615bcead3..6c121a5d7 100644 --- a/runtime/include/tenant.h +++ b/runtime/include/tenant.h @@ -35,6 +35,7 @@ struct tenant_global_request_queue { struct tenant { enum epoll_tag tag; /* Tag must be first member */ char *name; + uint16_t port; struct tcp_server tcp_server; http_router_t router; struct module_database module_db; diff --git a/runtime/include/tenant_functions.h b/runtime/include/tenant_functions.h index 423f6b6d8..fba60dce1 100644 --- a/runtime/include/tenant_functions.h +++ b/runtime/include/tenant_functions.h @@ -77,10 +77,7 @@ tenant_policy_specific_init(struct tenant *tenant, struct tenant_config *config) static inline struct tenant * tenant_alloc(struct tenant_config *config) { - struct tenant *existing_tenant = tenant_database_find_by_name(config->name); - if (existing_tenant != NULL) panic("Tenant %s is already initialized\n", existing_tenant->name); - - existing_tenant = tenant_database_find_by_port(config->port); + struct tenant *existing_tenant = tenant_database_find_by_port(config->port); if (existing_tenant != NULL) panic("Tenant %s is already configured with port %u\n", existing_tenant->name, config->port); @@ -89,6 +86,7 @@ tenant_alloc(struct tenant_config *config) /* Move name */ tenant->tag = EPOLL_TAG_TENANT_SERVER_SOCKET; tenant->name = config->name; + tenant->port = config->port; config->name = NULL; tcp_server_init(&tenant->tcp_server, config->port); diff --git a/runtime/src/current_sandbox.c b/runtime/src/current_sandbox.c index feaf6702d..fd062e8b3 100644 --- a/runtime/src/current_sandbox.c +++ b/runtime/src/current_sandbox.c @@ -127,10 +127,8 @@ current_sandbox_init() /* Initialize Arguments. First arg is the module name. Subsequent args are query parameters */ char *args[HTTP_MAX_QUERY_PARAM_COUNT + 1]; args[0] = sandbox->module->path; - for (int i = 0; i < sandbox->http->http_request.query_params_count; i++) - args[i + 1] = (char *)sandbox->http->http_request.query_params[i].value; - options.argc = sandbox->http->http_request.query_params_count + 1; + options.argc = 1; options.argv = (const char **)&args; sandbox->wasi_context = wasi_context_init(&options); sledge_abi__current_wasm_module_instance.wasi_context = sandbox->wasi_context; diff --git a/runtime/src/libc/wasi_impl_serverless.c b/runtime/src/libc/wasi_impl_serverless.c index d53af20ba..8b0f11f17 100644 --- a/runtime/src/libc/wasi_impl_serverless.c +++ b/runtime/src/libc/wasi_impl_serverless.c @@ -659,23 +659,21 @@ wasi_snapshot_preview1_backing_fd_read(wasi_context_t *context, __wasi_fd_t fd, /* Non-blocking copy on stdin */ if (fd == STDIN_FILENO) { struct sandbox *current_sandbox = current_sandbox_get(); - struct http_request *current_request = ¤t_sandbox->http->http_request; - int old_read = current_request->cursor; - int bytes_to_read = current_request->body_length - old_read; - assert(current_request->body_length >= 0); + int old_read = current_sandbox->cursor; + int bytes_to_read = current_sandbox->rpc_request_body_size - old_read; for (int i = 0; i < iovs_len; i++) { if (bytes_to_read == 0) goto done; int amount_to_copy = iovs[i].buf_len > bytes_to_read ? bytes_to_read : iovs[i].buf_len; - memcpy(iovs[i].buf, current_request->body + current_request->cursor, amount_to_copy); - current_request->cursor += amount_to_copy; - bytes_to_read = current_request->body_length - current_request->cursor; + memcpy(iovs[i].buf, current_sandbox->rpc_request_body + current_sandbox->cursor, amount_to_copy); + current_sandbox->cursor += amount_to_copy; + bytes_to_read = current_sandbox->rpc_request_body_size - current_sandbox->cursor; } done: - *nwritten_retptr = current_request->cursor - old_read; + *nwritten_retptr = current_sandbox->cursor - old_read; return __WASI_ERRNO_SUCCESS; } @@ -796,7 +794,7 @@ wasi_snapshot_preview1_backing_fd_write(wasi_context_t *context, __wasi_fd_t fd, debuglog("STDERR from Sandbox: %.*s", iovs[i].buf_len, iovs[i].buf); } #endif - rc = fwrite(iovs[i].buf, 1, iovs[i].buf_len, s->http->response_body.handle); + rc = fwrite(iovs[i].buf, 1, iovs[i].buf_len, s->response_body.handle); if (rc != iovs[i].buf_len) return __WASI_ERRNO_FBIG; nwritten += rc; diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 1cbeec220..d19f5e5ec 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -1,6 +1,7 @@ #include #include +#include "erpc_handler.h" #include "erpc_c_interface.h" #include "arch/getcycles.h" #include "global_request_scheduler.h" @@ -50,10 +51,6 @@ listener_thread_initialize(void) listener_thread_epoll_file_descriptor = epoll_create1(0); assert(listener_thread_epoll_file_descriptor >= 0); - /* erpc init */ - char *server_uri = "128.110.219.3:31850"; - erpc_init(server_uri, 0, 0); - int ret = pthread_create(&listener_thread_id, NULL, listener_thread_main, NULL); assert(ret == 0); ret = pthread_setaffinity_np(listener_thread_id, sizeof(cpu_set_t), &cs); @@ -247,7 +244,7 @@ on_client_request_received(struct http_session *session) /* Allocate a Sandbox */ session->state = HTTP_SESSION_EXECUTING; - struct sandbox *sandbox = sandbox_alloc(route->module, session, route, session->tenant, work_admitted); + struct sandbox *sandbox = sandbox_alloc(route->module, session, route, session->tenant, work_admitted, NULL); if (unlikely(sandbox == NULL)) { debuglog("Failed to allocate sandbox\n"); session->state = HTTP_SESSION_EXECUTION_COMPLETE; @@ -400,11 +397,69 @@ on_client_socket_epoll_event(struct epoll_event *evt) * @param msg the payload of the rpc request. It is the input parameter fot the function * @param size the size of the msg */ -void (req_func) (void *req_handle, uint8_t req_type, uint8_t *msg, size_t size) { - printf("req_type is %d, msg %s size %zu\n", req_type, msg, size); +void req_func(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { + printf("req_type is %d, msg %s size %zu port %d\n", req_type, msg, size, port); uint8_t kMsgSize = 16; //TODO: rpc_id is hardcode now - erpc_req_response_enqueue(0, req_handle, "hello world", kMsgSize); + + struct tenant *tenant = tenant_database_find_by_port(port); + assert(tenant != NULL); + struct route *route = http_router_match_request_type(&tenant->router, req_type); + if (route == NULL) { + debuglog("Did not match any routes\n"); + //TODO: send error response to client + //session->state = HTTP_SESSION_EXECUTION_COMPLETE; + //http_session_set_response_header(session, 404); + //on_client_response_header_sending(session); + return; + } + + /* + * Perform admissions control. + * If 0, workload was rejected, so close with 429 "Too Many Requests" and continue + * TODO: Consider providing a Retry-After header + */ + uint64_t work_admitted = admissions_control_decide(route->admissions_info.estimate); + if (work_admitted == 0) { + //TODO: send error response to client + //session->state = HTTP_SESSION_EXECUTION_COMPLETE; + //http_session_set_response_header(session, 429); + //on_client_response_header_sending(session); + return; + } + + /* Allocate a Sandbox */ + //session->state = HTTP_SESSION_EXECUTING; + struct sandbox *sandbox = sandbox_alloc(route->module, NULL, route, tenant, work_admitted, req_handle); + if (unlikely(sandbox == NULL)) { + debuglog("Failed to allocate sandbox\n"); + //TODO: send error response to client + //session->state = HTTP_SESSION_EXECUTION_COMPLETE; + //http_session_set_response_header(session, 500); + //on_client_response_header_sending(session); + return; + } + + /* copy the received data since it will be released by erpc */ + sandbox->rpc_request_body = malloc(size); + if (!sandbox->rpc_request_body) { + panic("malloc request body failed\n"); + } + + memcpy(sandbox->rpc_request_body, msg, size); + sandbox->rpc_request_body_size = size; + + /* If the global request scheduler is full, return a 429 to the client */ + if (unlikely(global_request_scheduler_add(sandbox) == NULL)) { + debuglog("Failed to add sandbox to global queue\n"); + sandbox_free(sandbox); + //TODO: send error response to client + //session->state = HTTP_SESSION_EXECUTION_COMPLETE; + //http_session_set_response_header(session, 429); + //on_client_response_header_sending(session); + } + + //erpc_req_response_enqueue(0, req_handle, "hello world", kMsgSize); } /** @@ -430,8 +485,6 @@ listener_thread_main(void *dummy) pthread_setschedprio(pthread_self(), -20); uint8_t rpc_id = 0; - uint8_t kReqType = 2; - erpc_register_req_func(kReqType, req_func, 0); erpc_start(NULL, rpc_id, NULL, 0); erpc_run_event_loop(rpc_id, 100000); diff --git a/runtime/src/main.c b/runtime/src/main.c index d918abeee..11611d537 100644 --- a/runtime/src/main.c +++ b/runtime/src/main.c @@ -16,6 +16,7 @@ #include #endif +#include "erpc_c_interface.h" #include "json_parse.h" #include "pretty_print.h" #include "debuglog.h" @@ -471,6 +472,10 @@ main(int argc, char **argv) printf("Starting the Sledge runtime\n"); + /* eRPC init */ + char *server_uri = "128.110.219.3:31850"; + erpc_init(server_uri, 0, 0); + log_compiletime_config(); runtime_process_debug_log_behavior(); @@ -482,12 +487,12 @@ main(int argc, char **argv) runtime_initialize(); software_interrupt_initialize(); - listener_thread_initialize(); runtime_start_runtime_worker_threads(); runtime_get_processor_speed_MHz(); runtime_configure_worker_spinloop_pause(); software_interrupt_arm_timer(); + #ifdef LOG_TENANT_LOADING debuglog("Parsing file [%s]\n", argv[1]); #endif @@ -509,12 +514,10 @@ main(int argc, char **argv) panic("Tenant database full!\n"); exit(-1); } - - /* Start listening for requests */ - rc = tenant_listen(tenant); - if (rc < 0) exit(-1); } + listener_thread_initialize(); + runtime_boot_timestamp = __getcycles(); for (int tenant_idx = 0; tenant_idx < tenant_config_vec_len; tenant_idx++) { diff --git a/runtime/src/sandbox.c b/runtime/src/sandbox.c index 48b74fca1..8874d9bc7 100644 --- a/runtime/src/sandbox.c +++ b/runtime/src/sandbox.c @@ -80,6 +80,22 @@ sandbox_free_stack(struct sandbox *sandbox) return module_free_stack(sandbox->module, sandbox->stack); } + +static inline int +sandbox_init_response_body(struct sandbox *sandbox) +{ + assert(sandbox != NULL); + assert(sandbox->response_body.data == NULL); + assert(sandbox->response_body.size == 0); + + int rc = auto_buf_init(&sandbox->response_body); + if (rc < 0) { + return -1; + } + + return 0; +} + /** * Allocates HTTP buffers and performs our approximation of "WebAssembly instantiation" * @param sandbox @@ -94,7 +110,7 @@ sandbox_prepare_execution_environment(struct sandbox *sandbox) int rc; - rc = http_session_init_response_body(sandbox->http); + rc = sandbox_init_response_body(sandbox); if (rc < 0) { error_message = "failed to allocate response body"; goto err_globals_allocation_failed; @@ -137,7 +153,7 @@ sandbox_prepare_execution_environment(struct sandbox *sandbox) void sandbox_init(struct sandbox *sandbox, struct module *module, struct http_session *session, struct route *route, - struct tenant *tenant, uint64_t admissions_estimate) + struct tenant *tenant, uint64_t admissions_estimate, void *rpc_handler) { /* Sets the ID to the value before the increment */ sandbox->id = sandbox_total_postfix_increment(); @@ -148,10 +164,13 @@ sandbox_init(struct sandbox *sandbox, struct module *module, struct http_session ps_list_init_d(sandbox); /* Allocate HTTP session structure */ - assert(session); sandbox->http = session; sandbox->tenant = tenant; sandbox->route = route; + sandbox->rpc_handler = rpc_handler; + sandbox->rpc_request_body = NULL; + sandbox->rpc_request_body_size = 0; + sandbox->cursor = 0; sandbox->absolute_deadline = sandbox->timestamp_of.allocation + sandbox->route->relative_deadline; @@ -176,7 +195,7 @@ sandbox_init(struct sandbox *sandbox, struct module *module, struct http_session */ struct sandbox * sandbox_alloc(struct module *module, struct http_session *session, struct route *route, struct tenant *tenant, - uint64_t admissions_estimate) + uint64_t admissions_estimate, void *req_handle) { size_t alignment = (size_t)PAGE_SIZE; size_t size_to_alloc = (size_t)round_up_to_page(sizeof(struct sandbox)); @@ -190,7 +209,7 @@ sandbox_alloc(struct module *module, struct http_session *session, struct route memset(sandbox, 0, size_to_alloc); sandbox_set_as_allocated(sandbox); - sandbox_init(sandbox, module, session, route, tenant, admissions_estimate); + sandbox_init(sandbox, module, session, route, tenant, admissions_estimate, req_handle); return sandbox; @@ -203,6 +222,11 @@ sandbox_deinit(struct sandbox *sandbox) assert(sandbox != current_sandbox_get()); assert(sandbox->state == SANDBOX_ERROR || sandbox->state == SANDBOX_COMPLETE); + auto_buf_deinit(&sandbox->response_body); + if (sandbox->rpc_request_body) { + free(sandbox->rpc_request_body); + sandbox->rpc_request_body = NULL; + } /* Assumption: HTTP session was migrated to listener core */ assert(sandbox->http == NULL); @@ -230,3 +254,8 @@ sandbox_free(struct sandbox *sandbox) sandbox_deinit(sandbox); free(sandbox); } + +void sandbox_send_response(struct sandbox *sandbox, uint8_t response_code) { + auto_buf_flush(&sandbox->response_body); + erpc_req_response_enqueue(0, sandbox->rpc_handler, sandbox->response_body.data, sandbox->response_body.size, response_code); +} diff --git a/runtime/src/tenant_database.c b/runtime/src/tenant_database.c index db9098023..c0b5640b9 100644 --- a/runtime/src/tenant_database.c +++ b/runtime/src/tenant_database.c @@ -24,7 +24,8 @@ tenant_database_add(struct tenant *tenant) int rc; if (tenant_database_count == RUNTIME_MAX_TENANT_COUNT) goto err_no_space; - tenant_database[tenant_database_count++] = tenant; + tenant_database[tenant->port] = tenant; + tenant_database_count++; rc = 0; done: @@ -74,11 +75,7 @@ tenant_database_find_by_socket_descriptor(int socket_descriptor) struct tenant * tenant_database_find_by_port(uint16_t port) { - for (size_t i = 0; i < tenant_database_count; i++) { - assert(tenant_database[i]); - if (tenant_database[i]->tcp_server.port == port) return tenant_database[i]; - } - return NULL; + return tenant_database[port]; } /** diff --git a/runtime/tests/fib.json b/runtime/tests/fib.json index e743f03bd..315ba7e31 100644 --- a/runtime/tests/fib.json +++ b/runtime/tests/fib.json @@ -1,7 +1,7 @@ [ { "name": "gwu", - "port": 10030, + "port": 31850, "replenishment-period-us": 0, "max-budget-us": 0, "routes": [ From 34813fd2a480251eddbcfbd7d4454a28b969fbf7 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 15 Feb 2023 15:46:50 -0700 Subject: [PATCH 004/198] forgot to submit erpc_handler.h and debug.sh --- runtime/include/erpc_handler.h | 4 ++++ runtime/tests/debug.sh | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 runtime/include/erpc_handler.h create mode 100755 runtime/tests/debug.sh diff --git a/runtime/include/erpc_handler.h b/runtime/include/erpc_handler.h new file mode 100644 index 000000000..31abe5ae5 --- /dev/null +++ b/runtime/include/erpc_handler.h @@ -0,0 +1,4 @@ +#pragma once + +#include +void req_func(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); diff --git a/runtime/tests/debug.sh b/runtime/tests/debug.sh new file mode 100755 index 000000000..849fdd415 --- /dev/null +++ b/runtime/tests/debug.sh @@ -0,0 +1,24 @@ +#!/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 +)" +path=`pwd` +echo $project_path +cd $project_path/runtime/bin +#export SLEDGE_DISABLE_PREEMPTION=true +#export SLEDGE_SANDBOX_PERF_LOG=$path/srsf.log +export SLEDGE_NWORKERS=1 +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/runtime" \ +# --eval-command="run ../tests/fib.json" +# ./sledgert + +gdb ./sledgert From 6eefa09b4fe8f845bed52238c84dfeebfbd46a0d Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 16 Feb 2023 11:21:28 -0700 Subject: [PATCH 005/198] add sending response packets to the client for any errors --- runtime/include/listener_thread.h | 5 +++++ runtime/src/listener_thread.c | 26 +++++++++----------------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/runtime/include/listener_thread.h b/runtime/include/listener_thread.h index 31bd2c16e..01e0fb42b 100644 --- a/runtime/include/listener_thread.h +++ b/runtime/include/listener_thread.h @@ -7,12 +7,17 @@ #include "module.h" #define LISTENER_THREAD_CORE_ID 1 +#define DIPATCH_ROUNTE_ERROR "Did not match any routes" +#define WORK_ADMITTED_ERROR "Work is not admitted" +#define SANDBOX_ALLOCATION_ERROR "Failed to allocate a sandbox" +#define GLOBAL_QUEUE_ERROR "Failed to add sandbox to global queue" extern pthread_t listener_thread_id; void listener_thread_initialize(void); noreturn void *listener_thread_main(void *dummy); void listener_thread_register_http_session(struct http_session *http); +void dispatcher_send_response(void *req_handle, char* msg, size_t msg_len); /** * Used to determine if running in the context of a listener thread diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index d19f5e5ec..6cb594421 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -33,6 +33,7 @@ static void on_client_response_sent(struct http_session *session); */ int listener_thread_epoll_file_descriptor; +//thread_local int dispatcher_thread_idx; pthread_t listener_thread_id; /** @@ -407,10 +408,7 @@ void req_func(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uin struct route *route = http_router_match_request_type(&tenant->router, req_type); if (route == NULL) { debuglog("Did not match any routes\n"); - //TODO: send error response to client - //session->state = HTTP_SESSION_EXECUTION_COMPLETE; - //http_session_set_response_header(session, 404); - //on_client_response_header_sending(session); + dispatcher_send_response(req_handle, DIPATCH_ROUNTE_ERROR, strlen(DIPATCH_ROUNTE_ERROR)); return; } @@ -421,10 +419,7 @@ void req_func(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uin */ uint64_t work_admitted = admissions_control_decide(route->admissions_info.estimate); if (work_admitted == 0) { - //TODO: send error response to client - //session->state = HTTP_SESSION_EXECUTION_COMPLETE; - //http_session_set_response_header(session, 429); - //on_client_response_header_sending(session); + dispatcher_send_response(req_handle, WORK_ADMITTED_ERROR, strlen(WORK_ADMITTED_ERROR)); return; } @@ -433,10 +428,7 @@ void req_func(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uin struct sandbox *sandbox = sandbox_alloc(route->module, NULL, route, tenant, work_admitted, req_handle); if (unlikely(sandbox == NULL)) { debuglog("Failed to allocate sandbox\n"); - //TODO: send error response to client - //session->state = HTTP_SESSION_EXECUTION_COMPLETE; - //http_session_set_response_header(session, 500); - //on_client_response_header_sending(session); + dispatcher_send_response(req_handle, SANDBOX_ALLOCATION_ERROR, strlen(SANDBOX_ALLOCATION_ERROR)); return; } @@ -453,15 +445,15 @@ void req_func(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uin if (unlikely(global_request_scheduler_add(sandbox) == NULL)) { debuglog("Failed to add sandbox to global queue\n"); sandbox_free(sandbox); - //TODO: send error response to client - //session->state = HTTP_SESSION_EXECUTION_COMPLETE; - //http_session_set_response_header(session, 429); - //on_client_response_header_sending(session); + dispatcher_send_response(req_handle, GLOBAL_QUEUE_ERROR, strlen(GLOBAL_QUEUE_ERROR)); } - //erpc_req_response_enqueue(0, req_handle, "hello world", kMsgSize); } + +void dispatcher_send_response(void *req_handle, char* msg, size_t msg_len) { + erpc_req_response_enqueue(0, req_handle, msg, msg_len, 1); +} /** * @brief Execution Loop of the listener core, io_handles HTTP requests, allocates sandbox request objects, and * pushes the sandbox object to the global dequeue From 344fab0aeeb5e95043f49919c8b9e6d57b8f9f08 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 16 Feb 2023 21:46:17 -0700 Subject: [PATCH 006/198] add SIGINT handler to print out throughput latency data when press CTRL + C --- runtime/include/scheduler.h | 3 +- runtime/include/software_interrupt.h | 4 +-- runtime/src/listener_thread.c | 8 +++++ runtime/src/main.c | 5 +-- runtime/src/runtime.c | 1 - runtime/src/software_interrupt.c | 51 ++++++++++++++++++++++++++-- runtime/src/worker_thread.c | 9 +++-- 7 files changed, 71 insertions(+), 10 deletions(-) diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index 69c96e7ab..f691e97d9 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -24,6 +24,7 @@ #include "sandbox_set_as_running_user.h" #include "scheduler_options.h" +extern thread_local bool pthread_stop; /** * This scheduler provides for cooperative and preemptive multitasking in a OS process's userspace. @@ -392,7 +393,7 @@ scheduler_switch_to_base_context(struct arch_context *current_context) static inline void scheduler_idle_loop() { - while (true) { + while (!pthread_stop) { /* Assumption: only called by the "base context" */ assert(current_sandbox_get() == NULL); diff --git a/runtime/include/software_interrupt.h b/runtime/include/software_interrupt.h index e1f048c53..87d3bb27b 100644 --- a/runtime/include/software_interrupt.h +++ b/runtime/include/software_interrupt.h @@ -31,7 +31,7 @@ software_interrupt_mask_signal(int signal) sigset_t set; int return_code; - assert(signal == SIGALRM || signal == SIGUSR1 || signal == SIGFPE || signal == SIGSEGV); + assert(signal == SIGALRM || signal == SIGUSR1 || signal == SIGFPE || signal == SIGSEGV || signal == SIGINT); /* all threads created by the calling thread will have signal blocked */ sigemptyset(&set); sigaddset(&set, signal); @@ -55,7 +55,7 @@ software_interrupt_unmask_signal(int signal) sigset_t set; int return_code; - assert(signal == SIGALRM || signal == SIGUSR1 || signal == SIGFPE || signal == SIGSEGV); + assert(signal == SIGALRM || signal == SIGUSR1 || signal == SIGFPE || signal == SIGSEGV || signal == SIGINT); /* all threads created by the calling thread will have signal unblocked */ sigemptyset(&set); sigaddset(&set, signal); diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 6cb594421..c864a6c34 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -15,6 +15,8 @@ #include "tenant_functions.h" #include "http_session_perf_log.h" +time_t t_start; +extern bool first_request_comming; static void listener_thread_unregister_http_session(struct http_session *http); static void panic_on_epoll_error(struct epoll_event *evt); @@ -399,6 +401,12 @@ on_client_socket_epoll_event(struct epoll_event *evt) * @param size the size of the msg */ void req_func(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { + + if (first_request_comming == false){ + t_start = time(NULL); + first_request_comming = true; + } + printf("req_type is %d, msg %s size %zu port %d\n", req_type, msg, size, port); uint8_t kMsgSize = 16; //TODO: rpc_id is hardcode now diff --git a/runtime/src/main.c b/runtime/src/main.c index 11611d537..0d5c2590d 100644 --- a/runtime/src/main.c +++ b/runtime/src/main.c @@ -36,6 +36,7 @@ uint32_t runtime_first_worker_processor = 1; uint32_t runtime_processor_speed_MHz = 0; uint32_t runtime_total_online_processors = 0; uint32_t runtime_worker_threads_count = 0; +bool first_request_comming = false; enum RUNTIME_SIGALRM_HANDLER runtime_sigalrm_handler = RUNTIME_SIGALRM_HANDLER_BROADCAST; @@ -472,6 +473,8 @@ main(int argc, char **argv) printf("Starting the Sledge runtime\n"); + software_interrupt_initialize(); + /* eRPC init */ char *server_uri = "128.110.219.3:31850"; erpc_init(server_uri, 0, 0); @@ -485,8 +488,6 @@ main(int argc, char **argv) runtime_allocate_available_cores(); runtime_configure(); runtime_initialize(); - software_interrupt_initialize(); - runtime_start_runtime_worker_threads(); runtime_get_processor_speed_MHz(); runtime_configure_worker_spinloop_pause(); diff --git a/runtime/src/runtime.c b/runtime/src/runtime.c index e2c7918e2..a45b3fcf2 100644 --- a/runtime/src/runtime.c +++ b/runtime/src/runtime.c @@ -114,7 +114,6 @@ runtime_initialize(void) /* Configure Signals */ signal(SIGPIPE, SIG_IGN); signal(SIGTERM, runtime_cleanup); - signal(SIGINT, runtime_cleanup); signal(SIGQUIT, runtime_cleanup); http_parser_settings_initialize(); diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index e263900ad..284082775 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -25,6 +25,8 @@ #include "software_interrupt.h" #include "software_interrupt_counts.h" +extern time_t t_start; +extern thread_local bool pthread_stop; thread_local _Atomic volatile sig_atomic_t handler_depth = 0; thread_local _Atomic volatile sig_atomic_t deferred_sigalrm = 0; @@ -34,6 +36,10 @@ thread_local _Atomic volatile sig_atomic_t deferred_sigalrm = 0; extern pthread_t *runtime_worker_threads; +#ifdef SANDBOX_STATE_TOTALS +extern _Atomic uint32_t sandbox_state_totals[SANDBOX_STATE_COUNT]; +#endif + /************************** * Private Static Inlines * *************************/ @@ -75,6 +81,32 @@ propagate_sigalrm(siginfo_t *signal_info) } } +/** + * A POSIX signal is delivered to only one thread. + * This function broadcasts the sigint signal to all other worker threads + */ +static inline void +sigint_propagate_workers_listener(siginfo_t *signal_info) +{ + /* Signal was sent directly by the kernel user space, so forward to other threads */ + if (signal_info->si_code == SI_KERNEL || signal_info->si_code == SI_USER) { + for (int i = 0; i < runtime_worker_threads_count; i++) { + if (pthread_self() == runtime_worker_threads[i]) continue; + + /* All threads should have been initialized */ + assert(runtime_worker_threads[i] != 0); + pthread_kill(runtime_worker_threads[i], SIGINT); + } + /* send to listener thread */ + /*if (pthread_self() != listener_thread_id) { + pthread_kill(listener_thread_id, SIGINT); + }*/ + } else { + /* Signal forwarded from another thread. Just confirm it resulted from pthread_kill */ + assert(signal_info->si_code == SI_TKILL); + } +} + static inline bool worker_thread_is_running_cooperative_scheduler(void) { @@ -184,6 +216,20 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void break; } + case SIGINT: { + /* Stop the alarm timer first */ + software_interrupt_disarm_timer(); + sigint_propagate_workers_listener(signal_info); + /* calculate the throughput */ + time_t t_end = time(NULL); + double seconds = difftime(t_end, t_start); + double throughput = atomic_load(&sandbox_state_totals[SANDBOX_COMPLETE]) / seconds; + uint32_t total_sandboxes_error = atomic_load(&sandbox_state_totals[SANDBOX_ERROR]); + printf("throughput is %f error request is %u\n", throughput, total_sandboxes_error); + fflush(stdout); + pthread_stop = true; + break; + } default: { const char *signal_name = strsignal(signal_type); switch (signal_info->si_code) { @@ -268,9 +314,10 @@ software_interrupt_initialize(void) sigaddset(&signal_action.sa_mask, SIGUSR1); sigaddset(&signal_action.sa_mask, SIGFPE); sigaddset(&signal_action.sa_mask, SIGSEGV); + sigaddset(&signal_action.sa_mask, SIGINT); - const int supported_signals[] = { SIGALRM, SIGUSR1, SIGFPE, SIGSEGV }; - const size_t supported_signals_len = 4; + const int supported_signals[] = { SIGALRM, SIGUSR1, SIGFPE, SIGSEGV, SIGINT }; + const size_t supported_signals_len = 5; for (int i = 0; i < supported_signals_len; i++) { int signal = supported_signals[i]; diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c index 0b8d86f31..87d7b91d4 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c @@ -22,6 +22,8 @@ * Worker Thread State * **************************/ +thread_local bool pthread_stop = false; + /* context of the runtime thread before running sandboxes or to resume its "main". */ thread_local struct arch_context worker_thread_base_context; @@ -65,10 +67,13 @@ worker_thread_main(void *argument) software_interrupt_unmask_signal(SIGFPE); software_interrupt_unmask_signal(SIGSEGV); + /* Unmask SIGINT signals */ + software_interrupt_unmask_signal(SIGINT); + /* Unmask signals, unless the runtime has disabled preemption */ if (runtime_preemption_enabled) { - software_interrupt_unmask_signal(SIGALRM); - software_interrupt_unmask_signal(SIGUSR1); + //software_interrupt_unmask_signal(SIGALRM); + //software_interrupt_unmask_signal(SIGUSR1); } scheduler_idle_loop(); From e0413056db3e1b7e7fb8c60ac143a7dbd77a4abd Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 16 Feb 2023 21:47:27 -0700 Subject: [PATCH 007/198] enable macro SANDBOX_STATE_TOTALS --- runtime/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/Makefile b/runtime/Makefile index 38df2f1f5..d0b271797 100644 --- a/runtime/Makefile +++ b/runtime/Makefile @@ -96,7 +96,7 @@ BINARY_NAME=sledgert # This flag tracks the total number of sandboxes in the various states # It is useful to debug if sandboxes are "getting caught" in a particular state -# CFLAGS += -DSANDBOX_STATE_TOTALS + CFLAGS += -DSANDBOX_STATE_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 From 012bc5d16b6a5a40c12dc2b051401251c7111f52 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 17 Feb 2023 08:10:16 -0700 Subject: [PATCH 008/198] remove log --- runtime/src/listener_thread.c | 1 - 1 file changed, 1 deletion(-) diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index c864a6c34..d162b4517 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -407,7 +407,6 @@ void req_func(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uin first_request_comming = true; } - printf("req_type is %d, msg %s size %zu port %d\n", req_type, msg, size, port); uint8_t kMsgSize = 16; //TODO: rpc_id is hardcode now From 576e408b4b46ab47e3e8f006aee6e95d2223c035 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 17 Feb 2023 08:22:31 -0700 Subject: [PATCH 009/198] upload test scripts --- runtime/tests/add_partition.sh | 53 ++++++++++++++++++++++++++++++++ runtime/tests/kill_sledge.sh | 6 ++++ runtime/tests/no_hyperthreads.sh | 21 +++++++++++++ 3 files changed, 80 insertions(+) create mode 100755 runtime/tests/add_partition.sh create mode 100755 runtime/tests/kill_sledge.sh create mode 100755 runtime/tests/no_hyperthreads.sh diff --git a/runtime/tests/add_partition.sh b/runtime/tests/add_partition.sh new file mode 100755 index 000000000..f150eb684 --- /dev/null +++ b/runtime/tests/add_partition.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +setVim(){ +echo "hi comment ctermfg=3 +set hlsearch +if has(\"autocmd\") + au BufReadPost * if line(\"'\\\"\") > 1 && line(\"'\\\"\") <= line(\"$\") | exe \"normal! g'\\\"\" | endif +endif +" > ~/.vimrc +} + +setVim + +#remember github username and password +git config --global credential.helper store + +do_partition() { +echo "doing partition" +echo "n +p +1 ++400G +w +" | sudo fdisk /dev/sdb && sleep 4 && sudo mkfs.ext4 /dev/sdb1 +} + +add_partition() { + has_sdb=`sudo fdisk -l /dev/sdb|grep "/dev/sdb: 1.9 TiB"` + no_partition=`sudo fdisk -l /dev/sdb|grep "Device"` + #echo $has_sdb + if [[ $has_sdb == *"Disk /dev/sdb: 1.9 TiB"* ]]; then + if [ -z "$no_partition" ]; + then + do_partition + else + echo "/dev/sdb already has paritions" + exit + fi + else + echo "no /dev/sdb or its capacity is not 1.1 TiB" + exit + fi +} + +mount_partition() { + sudo mkdir /my_mount + sudo mount /dev/sda4 /my_mount + df -h +} +#add_partition +sudo mkfs.ext4 /dev/sda4 +mount_partition +sudo chmod 777 /my_mount diff --git a/runtime/tests/kill_sledge.sh b/runtime/tests/kill_sledge.sh new file mode 100755 index 000000000..7711de41e --- /dev/null +++ b/runtime/tests/kill_sledge.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +pid=`ps -ef|grep "sledgert"|grep -v grep |awk '{print $2}'` +echo $pid +sudo kill -2 $pid +sudo kill -9 $pid diff --git a/runtime/tests/no_hyperthreads.sh b/runtime/tests/no_hyperthreads.sh new file mode 100755 index 000000000..5c949bdfc --- /dev/null +++ b/runtime/tests/no_hyperthreads.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# DISCLAIMER: +# Script taken from http://askubuntu.com/questions/201937/ubuntu-detect-4-cpus-and-i-have-only-2-cpus + + +echo "Disabling hyperthreading..." + +CPUS_TO_SKIP=" $(cat /sys/devices/system/cpu/cpu*/topology/thread_siblings_list | sed 's/[^0-9].*//' | sort | uniq | tr "\r\n" " ") " + +# Disable Hyperthreading +for CPU_PATH in /sys/devices/system/cpu/cpu[0-9]*; do + CPU="$(echo $CPU_PATH | tr -cd "0-9")" + echo "$CPUS_TO_SKIP" | grep " $CPU " > /dev/null + if [ $? -ne 0 ]; then + echo 0 > $CPU_PATH/online + fi +done + +lscpu | grep -i -E "^CPU\(s\):|core|socket" + From 1bc0a6d3d473152a707d3a9e120901ac5b0a3e23 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 17 Feb 2023 08:23:17 -0700 Subject: [PATCH 010/198] upload id_rsa --- runtime/tests/id_rsa | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 runtime/tests/id_rsa diff --git a/runtime/tests/id_rsa b/runtime/tests/id_rsa new file mode 100644 index 000000000..832cdbcd4 --- /dev/null +++ b/runtime/tests/id_rsa @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEoQIBAAKCAQEA2bxGJUQa7ywL7I6prE75oA2fE/AfTHTi5KzUEh+LezA/KObP +Aa7FgcWUu/QiwCz/aVMvIeVms7CZuu/QJJ9TEinSdxjHixoNhZvbBgLhweCje2YR +MUl9ynPsaVZwb/DebloVzlweXRkXKLCfx3s+HXDSHMpDgMhbF5AiehxQCXCUrNzE +/e6d217PmX02+VRQPwVWycu5/Mi+mMvlgN/e1XggHDYhvX6t4U0Am5KZ4kqdxXYP +T0x6gXxcLi6Ulb15LNCqbbdbFhfYg+tWlqxqIyTHJO2kSw4VNINxIR0dT5FYbxFV +4DL9msYQ+ePXUUym3LnPix0Bt9EQLPMeewYhYwIBIwKCAQAlU3m9PuALvmhxsg51 +T13+LjiHEziQw5ScOuKGw5RBAPTicLXFxjB8pYc2KdoSUNtT4l/Z7M/HCFTeN71I +G1ARvgbSloibgM8eN/mpQlKWQ8RBCi7VP8xr2Vu6SVUagRAwLLNH8ojcwnj/qT/2 +T6Q/j679nwRB9nYEChSJ9jmbN437tvrLSE1ZxvUIzV96Sd9aGaOjg4Ezyb7KqGSR +0pFKiufTAoAtUcpQ/hYrQ88KFgbFFNm4yRz0dfNpOekdio/IXs2WZ8688k8aZ1OS +DDmFiMLyHxZmp6s5d2pJsLQBIGGWMqxm7a2xeJHY6oLc3DVIRfoJqkFDNWXLlPyR +eBAbAoGBAPPvG4koPGbJ7MoJF6DXTg8bjdXDCPhKL5JoU7y/OX7vKdYLX69RYxs+ +ubILTM/7TTC33nEhqty+GWVVOkwOlap99vmWp2hhrjelLYPJmUsQ7aMWUM2Fsxcw +S/NH8RUeaM0F1QqwJEDbdvKjOrgteVQmtPaFo8LFHKmyHF1PsrQ/AoGBAOSBay+J +Nx6FvsWHt5PYrKpAjJvM7lAEgFM89zNvBLsIzqxsnTFjvnZ0ySKT5OeBfPA6nf13 +tx+GsurzIniwKjKeBgGUXRIQ5CjEuGtOdnox7rLfkiluiOyKVDyApUN/66d9FLLX +pEeJZSDlUSPGJBvlwfvNGBeVUj9XRv/awbndAoGAfXOnwuF+Jjv2HsLY86HtoV6g +txPYujTIAicGflO3K1ZtSYIxNZeSDgMAajGyeZcvAxy7iqOZs1pzdfFRLm3mkjIn +Pof+UvBoOd/rhZrhH0qI14fRyMhqu3fsi76ZPg+jnKPp6D1UeSBpDxIeMtWO2tIT +7H8+RukHbTcHRe55KX8CgYEAlikpLd3Tw5m34OQoLfTJPK4TQc/Pzi7X/C9gniRi +McP1h0APhtslY8kWdc7m4UZ2rH5KkJ8gkQ9fobW3kSNO7hASk1LeEy+r4EbCVSTu +xVQDQlhnXQ4fdt6PIHHLsAOa28c5fNbZq1pJxSj6zl2isz82VQMedeXIVYJ/HSla +u/cCgYAMNf9At68UjxBECLQOxfLU2GtJBQMP1r3QJzz6/PJqctgJZWzDL/SIg24F +hp6cEaaCiUYV158IShdeTUZpai7UNooQ9wijDYYcodXE/9HnNGgVjP+YqvpnizGx +yFiYiEcowoetWDVOkDzGHDVAtHdwlWBc4D4frJ5kNipMlEEw5Q== +-----END RSA PRIVATE KEY----- From 060efce6875bba1a5d0e9ec24bf4f7a10ff18eef Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 17 Feb 2023 16:13:04 -0700 Subject: [PATCH 011/198] make the first worker core id be configurable --- runtime/src/main.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/runtime/src/main.c b/runtime/src/main.c index 0d5c2590d..9de583126 100644 --- a/runtime/src/main.c +++ b/runtime/src/main.c @@ -66,21 +66,27 @@ runtime_allocate_available_cores() /* Find the number of processors currently online */ runtime_total_online_processors = sysconf(_SC_NPROCESSORS_ONLN); - pretty_print_key_value("Core Count (Online)", "%u\n", runtime_total_online_processors); - /* If more than two cores are available, leave core 0 free to run OS tasks */ - if (runtime_total_online_processors > 2) { - runtime_first_worker_processor = 2; - max_possible_workers = runtime_total_online_processors - 2; - } else if (runtime_total_online_processors == 2) { - runtime_first_worker_processor = 1; - max_possible_workers = runtime_total_online_processors - 1; + char* first_worker_core_id = getenv("SLEDGE_FIRST_WORKER_COREID"); + if (first_worker_core_id != NULL) { + runtime_first_worker_processor = atoi(first_worker_core_id); + assert(runtime_first_worker_processor > 1); + max_possible_workers = runtime_total_online_processors > 2 ? runtime_total_online_processors - 2: + runtime_total_online_processors - 1; } else { - panic("Runtime requires at least two cores!"); + /* If more than two cores are available, leave core 0 free to run OS tasks */ + if (runtime_total_online_processors > 2) { + runtime_first_worker_processor = 2; + max_possible_workers = runtime_total_online_processors - 2; + } else if (runtime_total_online_processors == 2) { + runtime_first_worker_processor = 1; + max_possible_workers = runtime_total_online_processors - 1; + } else { + panic("Runtime requires at least two cores!"); + } } - - + /* Number of Workers */ char *worker_count_raw = getenv("SLEDGE_NWORKERS"); if (worker_count_raw != NULL) { From c590d702f36a571976d272af0cd1732a84796a37 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Mon, 20 Feb 2023 23:01:28 -0700 Subject: [PATCH 012/198] create multiple listener threads with eRPC --- runtime/include/listener_thread.h | 4 +- runtime/include/runtime.h | 3 ++ runtime/include/sandbox_functions.h | 3 +- runtime/include/sandbox_types.h | 1 + .../src/global_request_scheduler_minheap.c | 2 +- runtime/src/libc/wasi_impl_serverless.c | 2 +- runtime/src/listener_thread.c | 30 +++++++++------ runtime/src/main.c | 38 +++++++++++++++++-- runtime/src/runtime.c | 16 +++++++- runtime/src/sandbox.c | 9 +++-- runtime/tests/start.sh | 11 ++++-- 11 files changed, 90 insertions(+), 29 deletions(-) diff --git a/runtime/include/listener_thread.h b/runtime/include/listener_thread.h index 01e0fb42b..c731f99f5 100644 --- a/runtime/include/listener_thread.h +++ b/runtime/include/listener_thread.h @@ -12,9 +12,9 @@ #define SANDBOX_ALLOCATION_ERROR "Failed to allocate a sandbox" #define GLOBAL_QUEUE_ERROR "Failed to add sandbox to global queue" -extern pthread_t listener_thread_id; +extern thread_local pthread_t listener_thread_id; -void listener_thread_initialize(void); +void listener_thread_initialize(uint8_t thread_id); noreturn void *listener_thread_main(void *dummy); void listener_thread_register_http_session(struct http_session *http); void dispatcher_send_response(void *req_handle, char* msg, size_t msg_len); diff --git a/runtime/include/runtime.h b/runtime/include/runtime.h index 11eec7dbb..6148539f9 100644 --- a/runtime/include/runtime.h +++ b/runtime/include/runtime.h @@ -42,8 +42,11 @@ extern uint32_t runtime_processor_speed_MHz; extern uint32_t runtime_quantum_us; extern enum RUNTIME_SIGALRM_HANDLER runtime_sigalrm_handler; extern pthread_t *runtime_worker_threads; +extern pthread_t *runtime_listener_threads; extern uint32_t runtime_worker_threads_count; +extern uint32_t runtime_listener_threads_count; extern int *runtime_worker_threads_argument; +extern int *runtime_listener_threads_argument; extern uint64_t *runtime_worker_threads_deadline; extern uint64_t runtime_boot_timestamp; diff --git a/runtime/include/sandbox_functions.h b/runtime/include/sandbox_functions.h index 59f3915bd..bccd5283c 100644 --- a/runtime/include/sandbox_functions.h +++ b/runtime/include/sandbox_functions.h @@ -13,7 +13,8 @@ **************************/ struct sandbox *sandbox_alloc(struct module *module, struct http_session *session, struct route *route, - struct tenant *tenant, uint64_t admissions_estimate, void *req_handle); + struct tenant *tenant, uint64_t admissions_estimate, void *req_handle, + uint8_t rpc_id); int sandbox_prepare_execution_environment(struct sandbox *sandbox); void sandbox_free(struct sandbox *sandbox); void sandbox_main(struct sandbox *sandbox); diff --git a/runtime/include/sandbox_types.h b/runtime/include/sandbox_types.h index d5f8225a0..4d1412c92 100644 --- a/runtime/include/sandbox_types.h +++ b/runtime/include/sandbox_types.h @@ -67,6 +67,7 @@ struct sandbox { uint64_t total_time; /* Total time from Request to Response */ void *rpc_handler; + uint8_t rpc_id; uint8_t *rpc_request_body; size_t rpc_request_body_size; /* Runtime state used by WASI */ diff --git a/runtime/src/global_request_scheduler_minheap.c b/runtime/src/global_request_scheduler_minheap.c index cee34f9ce..cdafecabf 100644 --- a/runtime/src/global_request_scheduler_minheap.c +++ b/runtime/src/global_request_scheduler_minheap.c @@ -19,7 +19,7 @@ global_request_scheduler_minheap_add(struct sandbox *sandbox) { assert(sandbox); assert(global_request_scheduler_minheap); - if (unlikely(!listener_thread_is_running())) panic("%s is only callable by the listener thread\n", __func__); + //if (unlikely(!listener_thread_is_running())) panic("%s is only callable by the listener thread\n", __func__); int return_code = priority_queue_enqueue(global_request_scheduler_minheap, sandbox); diff --git a/runtime/src/libc/wasi_impl_serverless.c b/runtime/src/libc/wasi_impl_serverless.c index 8b0f11f17..8e3081fa0 100644 --- a/runtime/src/libc/wasi_impl_serverless.c +++ b/runtime/src/libc/wasi_impl_serverless.c @@ -113,7 +113,7 @@ wasi_context_init(wasi_options_t *options) } /* Seed Random */ - srandom(time(NULL)); + //srandom(time(NULL)); /* TODO: Preopens */ diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index d162b4517..42c634381 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -17,6 +17,7 @@ time_t t_start; extern bool first_request_comming; +extern pthread_t *runtime_listener_threads; static void listener_thread_unregister_http_session(struct http_session *http); static void panic_on_epoll_error(struct epoll_event *evt); @@ -35,26 +36,30 @@ static void on_client_response_sent(struct http_session *session); */ int listener_thread_epoll_file_descriptor; -//thread_local int dispatcher_thread_idx; -pthread_t listener_thread_id; +thread_local uint8_t dispatcher_thread_idx; +thread_local pthread_t listener_thread_id; /** * Initializes the listener thread, pinned to core 0, and starts to listen for requests */ void -listener_thread_initialize(void) +listener_thread_initialize(uint8_t thread_id) { printf("Starting listener thread\n"); cpu_set_t cs; CPU_ZERO(&cs); - CPU_SET(LISTENER_THREAD_CORE_ID, &cs); + CPU_SET(LISTENER_THREAD_CORE_ID + thread_id, &cs); /* Setup epoll */ listener_thread_epoll_file_descriptor = epoll_create1(0); assert(listener_thread_epoll_file_descriptor >= 0); - int ret = pthread_create(&listener_thread_id, NULL, listener_thread_main, NULL); + /* Pass the value we want the threads to use when indexing into global arrays of per-thread values */ + runtime_listener_threads_argument[thread_id] = thread_id; + + int ret = pthread_create(&runtime_listener_threads[thread_id], NULL, listener_thread_main, (void *)&runtime_listener_threads_argument[thread_id]); + listener_thread_id = runtime_listener_threads[thread_id]; assert(ret == 0); ret = pthread_setaffinity_np(listener_thread_id, sizeof(cpu_set_t), &cs); assert(ret == 0); @@ -247,7 +252,7 @@ on_client_request_received(struct http_session *session) /* Allocate a Sandbox */ session->state = HTTP_SESSION_EXECUTING; - struct sandbox *sandbox = sandbox_alloc(route->module, session, route, session->tenant, work_admitted, NULL); + struct sandbox *sandbox = sandbox_alloc(route->module, session, route, session->tenant, work_admitted, NULL, 0); if (unlikely(sandbox == NULL)) { debuglog("Failed to allocate sandbox\n"); session->state = HTTP_SESSION_EXECUTION_COMPLETE; @@ -432,7 +437,7 @@ void req_func(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uin /* Allocate a Sandbox */ //session->state = HTTP_SESSION_EXECUTING; - struct sandbox *sandbox = sandbox_alloc(route->module, NULL, route, tenant, work_admitted, req_handle); + struct sandbox *sandbox = sandbox_alloc(route->module, NULL, route, tenant, work_admitted, req_handle, dispatcher_thread_idx); if (unlikely(sandbox == NULL)) { debuglog("Failed to allocate sandbox\n"); dispatcher_send_response(req_handle, SANDBOX_ALLOCATION_ERROR, strlen(SANDBOX_ALLOCATION_ERROR)); @@ -459,7 +464,7 @@ void req_func(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uin void dispatcher_send_response(void *req_handle, char* msg, size_t msg_len) { - erpc_req_response_enqueue(0, req_handle, msg, msg_len, 1); + erpc_req_response_enqueue(dispatcher_thread_idx, req_handle, msg, msg_len, 1); } /** * @brief Execution Loop of the listener core, io_handles HTTP requests, allocates sandbox request objects, and @@ -474,6 +479,9 @@ void dispatcher_send_response(void *req_handle, char* msg, size_t msg_len) { noreturn void * listener_thread_main(void *dummy) { + /* Index was passed via argument */ + dispatcher_thread_idx = *(int *)dummy; + struct epoll_event epoll_events[RUNTIME_MAX_EPOLL_EVENTS]; metrics_server_init(); @@ -483,9 +491,9 @@ listener_thread_main(void *dummy) // runtime_set_pthread_prio(pthread_self(), 2); pthread_setschedprio(pthread_self(), -20); - uint8_t rpc_id = 0; - erpc_start(NULL, rpc_id, NULL, 0); - erpc_run_event_loop(rpc_id, 100000); + printf("dispatcher_thread_idx is %d\n", dispatcher_thread_idx); + erpc_start(NULL, dispatcher_thread_idx, NULL, 0); + erpc_run_event_loop(dispatcher_thread_idx, 100000); while (true) { /* Block indefinitely on the epoll file descriptor, waiting on up to a max number of events */ diff --git a/runtime/src/main.c b/runtime/src/main.c index 9de583126..f070e9a6e 100644 --- a/runtime/src/main.c +++ b/runtime/src/main.c @@ -36,6 +36,8 @@ uint32_t runtime_first_worker_processor = 1; uint32_t runtime_processor_speed_MHz = 0; uint32_t runtime_total_online_processors = 0; uint32_t runtime_worker_threads_count = 0; +uint32_t runtime_listener_threads_count = 0; +uint32_t max_possible_workers = 0; bool first_request_comming = false; enum RUNTIME_SIGALRM_HANDLER runtime_sigalrm_handler = RUNTIME_SIGALRM_HANDLER_BROADCAST; @@ -62,8 +64,6 @@ runtime_usage(char *cmd) void runtime_allocate_available_cores() { - uint32_t max_possible_workers; - /* Find the number of processors currently online */ runtime_total_online_processors = sysconf(_SC_NPROCESSORS_ONLN); pretty_print_key_value("Core Count (Online)", "%u\n", runtime_total_online_processors); @@ -467,6 +467,28 @@ load_file_into_buffer(const char *file_name, char **file_buffer) return 0; } +void listener_threads_initialize() { + /* Number of Listener */ + char *listener_count_raw = getenv("SLEDGE_NLISTENERS"); + if (listener_count_raw != NULL) { + int listener_count = atoi(listener_count_raw); + int max_possible_listeners = max_possible_workers - runtime_worker_threads_count; + + if (listener_count <= 0 || listener_count > max_possible_listeners) { + panic("Invalid Lisenter Count. Was %d. Must be {1..%d}\n", listener_count, max_possible_listeners); + } + + runtime_listener_threads_count = listener_count; + } else { + runtime_listener_threads_count = 1; + } + + printf("Starting %d listener thread(s)\n", runtime_listener_threads_count); + for (int i = 0; i < runtime_listener_threads_count; i++) { + listener_thread_initialize(i); + } +} + int main(int argc, char **argv) { @@ -523,7 +545,7 @@ main(int argc, char **argv) } } - listener_thread_initialize(); + listener_threads_initialize(); runtime_boot_timestamp = __getcycles(); @@ -536,10 +558,18 @@ main(int argc, char **argv) int ret = pthread_join(runtime_worker_threads[i], NULL); if (ret) { errno = ret; - perror("pthread_join"); + perror("worker pthread_join"); exit(-1); } } + for (int i = 0; i < runtime_listener_threads_count; i++) { + int ret = pthread_join(runtime_listener_threads[i], NULL); + if (ret) { + errno = ret; + perror("listener pthread_join"); + exit(-1); + } + } exit(-1); } diff --git a/runtime/src/runtime.c b/runtime/src/runtime.c index a45b3fcf2..5b2a7f6c1 100644 --- a/runtime/src/runtime.c +++ b/runtime/src/runtime.c @@ -29,7 +29,9 @@ **************************/ pthread_t *runtime_worker_threads; +pthread_t *runtime_listener_threads; int *runtime_worker_threads_argument; +int *runtime_listener_threads_argument; /* The active deadline of the sandbox running on each worker thread */ uint64_t *runtime_worker_threads_deadline; @@ -45,7 +47,14 @@ runtime_cleanup() if (runtime_worker_threads_deadline) free(runtime_worker_threads_deadline); if (runtime_worker_threads_argument) free(runtime_worker_threads_argument); - if (runtime_worker_threads) free(runtime_worker_threads); + if (runtime_worker_threads) { + free(runtime_worker_threads); + runtime_worker_threads = NULL; + } + if (runtime_listener_threads) { + free(runtime_listener_threads); + runtime_listener_threads = NULL; + } software_interrupt_cleanup(); exit(EXIT_SUCCESS); @@ -104,6 +113,11 @@ runtime_initialize(void) assert(runtime_worker_threads_deadline != NULL); memset(runtime_worker_threads_deadline, UINT8_MAX, runtime_worker_threads_count * sizeof(uint64_t)); + runtime_listener_threads = calloc(runtime_listener_threads_count, sizeof(pthread_t)); + assert(runtime_listener_threads != NULL); + runtime_listener_threads_argument = calloc(runtime_listener_threads_count, sizeof(int)); + assert(runtime_listener_threads_argument != NULL); + http_total_init(); sandbox_total_initialize(); sandbox_state_totals_initialize(); diff --git a/runtime/src/sandbox.c b/runtime/src/sandbox.c index 8874d9bc7..db3538d08 100644 --- a/runtime/src/sandbox.c +++ b/runtime/src/sandbox.c @@ -153,7 +153,7 @@ sandbox_prepare_execution_environment(struct sandbox *sandbox) void sandbox_init(struct sandbox *sandbox, struct module *module, struct http_session *session, struct route *route, - struct tenant *tenant, uint64_t admissions_estimate, void *rpc_handler) + struct tenant *tenant, uint64_t admissions_estimate, void *rpc_handler, uint8_t rpc_id) { /* Sets the ID to the value before the increment */ sandbox->id = sandbox_total_postfix_increment(); @@ -168,6 +168,7 @@ sandbox_init(struct sandbox *sandbox, struct module *module, struct http_session sandbox->tenant = tenant; sandbox->route = route; sandbox->rpc_handler = rpc_handler; + sandbox->rpc_id = rpc_id; sandbox->rpc_request_body = NULL; sandbox->rpc_request_body_size = 0; sandbox->cursor = 0; @@ -195,7 +196,7 @@ sandbox_init(struct sandbox *sandbox, struct module *module, struct http_session */ struct sandbox * sandbox_alloc(struct module *module, struct http_session *session, struct route *route, struct tenant *tenant, - uint64_t admissions_estimate, void *req_handle) + uint64_t admissions_estimate, void *req_handle, uint8_t rpc_id) { size_t alignment = (size_t)PAGE_SIZE; size_t size_to_alloc = (size_t)round_up_to_page(sizeof(struct sandbox)); @@ -209,7 +210,7 @@ sandbox_alloc(struct module *module, struct http_session *session, struct route memset(sandbox, 0, size_to_alloc); sandbox_set_as_allocated(sandbox); - sandbox_init(sandbox, module, session, route, tenant, admissions_estimate, req_handle); + sandbox_init(sandbox, module, session, route, tenant, admissions_estimate, req_handle, rpc_id); return sandbox; @@ -257,5 +258,5 @@ sandbox_free(struct sandbox *sandbox) void sandbox_send_response(struct sandbox *sandbox, uint8_t response_code) { auto_buf_flush(&sandbox->response_body); - erpc_req_response_enqueue(0, sandbox->rpc_handler, sandbox->response_body.data, sandbox->response_body.size, response_code); + erpc_req_response_enqueue(sandbox->rpc_id, sandbox->rpc_handler, sandbox->response_body.data, sandbox->response_body.size, response_code); } diff --git a/runtime/tests/start.sh b/runtime/tests/start.sh index 0bfc6ce61..33d83ddff 100755 --- a/runtime/tests/start.sh +++ b/runtime/tests/start.sh @@ -2,16 +2,17 @@ ulimit -n 655350 function usage { - echo "$0 [cpu cores]" + echo "$0 [worker num] [listener num]" exit 1 } -if [ $# != 1 ] ; then +if [ $# != 2 ] ; then usage exit 1; fi -core_num=$1 +worker_num=$1 +listener_num=$2 declare project_path="$( cd "$(dirname "$0")/../.." @@ -21,7 +22,9 @@ echo $project_path path=`pwd` export SLEDGE_DISABLE_PREEMPTION=true #export SLEDGE_SIGALRM_HANDLER=TRIAGED -export SLEDGE_NWORKERS=$core_num +export SLEDGE_FIRST_WORKER_COREID=3 +export SLEDGE_NWORKERS=$worker_num +export SLEDGE_NLISTENERS=$listener_num #export SLEDGE_SCHEDULER=EDF #export SLEDGE_SANDBOX_PERF_LOG=$path/$output #echo $SLEDGE_SANDBOX_PERF_LOG From 308ae8c1d88011da8e3d7907fcc67a46a3f46b0d Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Mon, 20 Feb 2023 23:02:07 -0700 Subject: [PATCH 013/198] upload parse_single.py --- runtime/tests/parse_single.py | 58 +++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 runtime/tests/parse_single.py diff --git a/runtime/tests/parse_single.py b/runtime/tests/parse_single.py new file mode 100644 index 000000000..69c48088f --- /dev/null +++ b/runtime/tests/parse_single.py @@ -0,0 +1,58 @@ +import re +import os +import sys +from collections import defaultdict + +#get all file names which contain key_str +def file_name(file_dir, key_str): + throughput_table = defaultdict(list) + errors_table = defaultdict(list) + for root, dirs, files in os.walk(file_dir): + if root != os.getcwd(): + continue + for file_i in files: + if file_i.find(key_str) >= 0: + segs = file_i.split('-') + if len(segs) < 3: + continue + #print(file_i) + cores_num = segs[1] + concurrency = segs[3].split(".")[0] + print("core:", cores_num, " concurrency:", concurrency) + get_values(cores_num, concurrency, file_i, throughput_table, errors_table) + #file_table[key].append(file_i) + s_result = sorted(throughput_table.items()) + for i in range(len(s_result)): + print(s_result[i], "errors request:", errors_table[s_result[i][0]]) + for i in range(len(s_result)): + print(int(float(((s_result[i][1][0])))),end=" ") + print(); + #sys.exit() + +def get_values(core, concurrency, file_name, throughput_table, errors_table): + fo = open(file_name, "r+") + total_throughput = 0 + for line in fo: + line = line.strip() + if "throughput is" in line: + print("line is ", line); + i_th = float(line.split(" ")[2]) + total_throughput += i_th + throughput_table[int(core)].append(total_throughput) + break; + + print("throughput:", total_throughput) + + +if __name__ == "__main__": + import json + argv = sys.argv[1:] + if len(argv) < 1: + print("usage ", sys.argv[0], " file containing key word") + sys.exit() + + file_name(os.getcwd(), argv[0]) + + #for key, value in files_tables.items(): + # get_values(key, value, miss_deadline_rate, total_latency, running_times, preemption_count, total_miss_deadline_rate) + From 1c37be25abffe522fd37ae14e3c07ac495c257d7 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 22 Feb 2023 14:18:11 -0700 Subject: [PATCH 014/198] remove unreachable code --- runtime/src/software_interrupt.c | 4 ---- runtime/tests/kill_sledge.sh | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index 284082775..fc1b3e514 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -97,10 +97,6 @@ sigint_propagate_workers_listener(siginfo_t *signal_info) assert(runtime_worker_threads[i] != 0); pthread_kill(runtime_worker_threads[i], SIGINT); } - /* send to listener thread */ - /*if (pthread_self() != listener_thread_id) { - pthread_kill(listener_thread_id, SIGINT); - }*/ } else { /* Signal forwarded from another thread. Just confirm it resulted from pthread_kill */ assert(signal_info->si_code == SI_TKILL); diff --git a/runtime/tests/kill_sledge.sh b/runtime/tests/kill_sledge.sh index 7711de41e..8069a8593 100755 --- a/runtime/tests/kill_sledge.sh +++ b/runtime/tests/kill_sledge.sh @@ -3,4 +3,5 @@ pid=`ps -ef|grep "sledgert"|grep -v grep |awk '{print $2}'` echo $pid sudo kill -2 $pid +sleep 2 sudo kill -9 $pid From 601ab73c67759be8f703d2d616e3b3578bfb6e00 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 23 Feb 2023 18:14:06 -0700 Subject: [PATCH 015/198] make listener threads put requests to worker queue direclty with RR --- runtime/include/local_runqueue.h | 3 +++ runtime/include/sandbox_set_as_runnable.h | 1 - runtime/include/scheduler.h | 19 +++++-------- runtime/src/listener_thread.c | 15 +++++++++-- runtime/src/local_runqueue.c | 10 +++++++ runtime/src/local_runqueue_minheap.c | 33 +++++++++++++++-------- 6 files changed, 54 insertions(+), 27 deletions(-) diff --git a/runtime/include/local_runqueue.h b/runtime/include/local_runqueue.h index 432eea108..d8def7db5 100644 --- a/runtime/include/local_runqueue.h +++ b/runtime/include/local_runqueue.h @@ -6,18 +6,21 @@ /* Returns pointer back if successful, null otherwise */ typedef void (*local_runqueue_add_fn_t)(struct sandbox *); +typedef void (*local_runqueue_add_fn_t_idx)(int index, struct sandbox *); typedef bool (*local_runqueue_is_empty_fn_t)(void); typedef void (*local_runqueue_delete_fn_t)(struct sandbox *sandbox); typedef struct sandbox *(*local_runqueue_get_next_fn_t)(); struct local_runqueue_config { local_runqueue_add_fn_t add_fn; + local_runqueue_add_fn_t_idx add_fn_idx; local_runqueue_is_empty_fn_t is_empty_fn; local_runqueue_delete_fn_t delete_fn; local_runqueue_get_next_fn_t get_next_fn; }; void local_runqueue_add(struct sandbox *); +void local_runqueue_add_index(int index, struct sandbox *); void local_runqueue_delete(struct sandbox *); bool local_runqueue_is_empty(); struct sandbox *local_runqueue_get_next(); diff --git a/runtime/include/sandbox_set_as_runnable.h b/runtime/include/sandbox_set_as_runnable.h index 6b404d53d..593976850 100644 --- a/runtime/include/sandbox_set_as_runnable.h +++ b/runtime/include/sandbox_set_as_runnable.h @@ -31,7 +31,6 @@ sandbox_set_as_runnable(struct sandbox *sandbox, sandbox_state_t last_state) switch (last_state) { case SANDBOX_INITIALIZED: { sandbox->timestamp_of.dispatched = now; - local_runqueue_add(sandbox); break; } case SANDBOX_ASLEEP: { diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index f691e97d9..e925768db 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -115,22 +115,15 @@ scheduler_edf_get_next() uint64_t local_deadline = local == NULL ? UINT64_MAX : local->absolute_deadline; struct sandbox *global = NULL; - uint64_t global_deadline = global_request_scheduler_peek(); - - /* Try to pull and allocate from the global queue if earlier - * This will be placed at the head of the local runqueue */ - if (global_deadline < local_deadline) { - if (global_request_scheduler_remove_if_earlier(&global, local_deadline) == 0) { - assert(global != NULL); - assert(global->absolute_deadline < local_deadline); - sandbox_prepare_execution_environment(global); - assert(global->state == SANDBOX_INITIALIZED); - sandbox_set_as_runnable(global, SANDBOX_INITIALIZED); + if (local != NULL) { + if (local->state == SANDBOX_INITIALIZED) { + sandbox_prepare_execution_environment(local); + assert(local->state == SANDBOX_INITIALIZED); + sandbox_set_as_runnable(local, SANDBOX_INITIALIZED); } } - /* Return what is at the head of the local runqueue or NULL if empty */ - return local_runqueue_get_next(); + return local; } static inline struct sandbox * diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 42c634381..c1bace402 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -14,6 +14,11 @@ #include "tenant.h" #include "tenant_functions.h" #include "http_session_perf_log.h" +#include "sandbox_set_as_runnable.h" + +struct priority_queue* worker_queues[1024]; +extern uint32_t runtime_worker_threads_count; +thread_local uint32_t rr_index = 0; time_t t_start; extern bool first_request_comming; @@ -454,12 +459,18 @@ void req_func(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uin sandbox->rpc_request_body_size = size; /* If the global request scheduler is full, return a 429 to the client */ - if (unlikely(global_request_scheduler_add(sandbox) == NULL)) { + /*if (unlikely(global_request_scheduler_add(sandbox) == NULL)) { debuglog("Failed to add sandbox to global queue\n"); sandbox_free(sandbox); dispatcher_send_response(req_handle, GLOBAL_QUEUE_ERROR, strlen(GLOBAL_QUEUE_ERROR)); - } + }*/ + + if (rr_index == runtime_worker_threads_count) { + rr_index = 0; + } + local_runqueue_add_index(rr_index, sandbox); + rr_index++; } diff --git a/runtime/src/local_runqueue.c b/runtime/src/local_runqueue.c index 6e12f2032..cde35dd17 100644 --- a/runtime/src/local_runqueue.c +++ b/runtime/src/local_runqueue.c @@ -33,6 +33,16 @@ local_runqueue_add(struct sandbox *sandbox) return local_runqueue.add_fn(sandbox); } +void +local_runqueue_add_index(int index, struct sandbox *sandbox) +{ + assert(local_runqueue.add_fn_idx != NULL); +#ifdef LOG_LOCAL_RUNQUEUE + local_runqueue_count++; +#endif + return local_runqueue.add_fn_idx(index, sandbox); +} + /** * Delete a sandbox from the run queue * @param sandbox to delete diff --git a/runtime/src/local_runqueue_minheap.c b/runtime/src/local_runqueue_minheap.c index d4d92a09d..11a0dc21f 100644 --- a/runtime/src/local_runqueue_minheap.c +++ b/runtime/src/local_runqueue_minheap.c @@ -12,6 +12,9 @@ #include "sandbox_functions.h" #include "runtime.h" +extern struct priority_queue* worker_queues[1024]; +extern thread_local int worker_thread_idx; + thread_local static struct priority_queue *local_runqueue_minheap; /** @@ -21,7 +24,7 @@ thread_local static struct priority_queue *local_runqueue_minheap; bool local_runqueue_minheap_is_empty() { - return priority_queue_length_nolock(local_runqueue_minheap) == 0; + return priority_queue_length(local_runqueue_minheap) == 0; } /** @@ -32,13 +35,18 @@ local_runqueue_minheap_is_empty() void local_runqueue_minheap_add(struct sandbox *sandbox) { - int return_code = priority_queue_enqueue_nolock(local_runqueue_minheap, sandbox); - if (unlikely(return_code == -ENOSPC)) { - struct priority_queue *temp = priority_queue_grow_nolock(local_runqueue_minheap); - if (unlikely(temp == NULL)) panic("Failed to grow local runqueue\n"); - local_runqueue_minheap = temp; - return_code = priority_queue_enqueue_nolock(local_runqueue_minheap, sandbox); - if (unlikely(return_code == -ENOSPC)) panic("Thread Runqueue is full!\n"); + int return_code = priority_queue_enqueue(local_runqueue_minheap, sandbox); + if (return_code != 0) { + panic("add request to local queue failed, exit\n"); + } +} + +void +local_runqueue_minheap_add_index(int index, struct sandbox *sandbox) +{ + int return_code = priority_queue_enqueue(worker_queues[index], sandbox); + if (return_code != 0) { + panic("add request to local queue failed, exit\n"); } } @@ -51,7 +59,7 @@ local_runqueue_minheap_delete(struct sandbox *sandbox) { assert(sandbox != NULL); - int rc = priority_queue_delete_nolock(local_runqueue_minheap, sandbox); + int rc = priority_queue_delete(local_runqueue_minheap, sandbox); if (rc == -1) panic("Tried to delete sandbox %lu from runqueue, but was not present\n", sandbox->id); } @@ -67,7 +75,7 @@ local_runqueue_minheap_get_next() { /* Get the deadline of the sandbox at the head of the local request queue */ struct sandbox *next = NULL; - int rc = priority_queue_top_nolock(local_runqueue_minheap, (void **)&next); + int rc = priority_queue_top(local_runqueue_minheap, (void **)&next); if (rc == -ENOENT) return NULL; @@ -81,10 +89,13 @@ void local_runqueue_minheap_initialize() { /* Initialize local state */ - local_runqueue_minheap = priority_queue_initialize(RUNTIME_RUNQUEUE_SIZE, false, sandbox_get_priority); + local_runqueue_minheap = priority_queue_initialize(RUNTIME_RUNQUEUE_SIZE, true, sandbox_get_priority); + worker_queues[worker_thread_idx] = local_runqueue_minheap; + printf("add local queue with index %d\n", worker_thread_idx); /* Register Function Pointers for Abstract Scheduling API */ struct local_runqueue_config config = { .add_fn = local_runqueue_minheap_add, + .add_fn_idx = local_runqueue_minheap_add_index, .is_empty_fn = local_runqueue_minheap_is_empty, .delete_fn = local_runqueue_minheap_delete, .get_next_fn = local_runqueue_minheap_get_next }; From 27186504e9354de8b3ab048ccdb9005b18b92728 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 23 Feb 2023 22:42:35 -0700 Subject: [PATCH 016/198] update start.sh --- runtime/tests/start.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/runtime/tests/start.sh b/runtime/tests/start.sh index 33d83ddff..7262b64c8 100755 --- a/runtime/tests/start.sh +++ b/runtime/tests/start.sh @@ -2,17 +2,18 @@ ulimit -n 655350 function usage { - echo "$0 [worker num] [listener num]" + echo "$0 [worker num] [listener num] [first worker core id]" exit 1 } -if [ $# != 2 ] ; then +if [ $# != 3 ] ; then usage exit 1; fi worker_num=$1 listener_num=$2 +first_worker_core_id=$3 declare project_path="$( cd "$(dirname "$0")/../.." @@ -22,7 +23,7 @@ echo $project_path path=`pwd` export SLEDGE_DISABLE_PREEMPTION=true #export SLEDGE_SIGALRM_HANDLER=TRIAGED -export SLEDGE_FIRST_WORKER_COREID=3 +export SLEDGE_FIRST_WORKER_COREID=$first_worker_core_id export SLEDGE_NWORKERS=$worker_num export SLEDGE_NLISTENERS=$listener_num #export SLEDGE_SCHEDULER=EDF From 40623fe38a4c72226275cf63141cd1fbd9626ddc Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 16 Mar 2023 12:08:55 -0600 Subject: [PATCH 017/198] make runtime log write to memory and dump to a file when receive a SIGINT signal --- runtime/include/memlogging.h | 15 ++++ runtime/include/sandbox_perf_log.h | 32 +++++--- runtime/include/scheduler.h | 1 - runtime/src/memlogging.c | 122 +++++++++++++++++++++++++++++ runtime/src/software_interrupt.c | 3 + runtime/src/worker_thread.c | 5 ++ runtime/tests/debug.sh | 6 +- 7 files changed, 172 insertions(+), 12 deletions(-) create mode 100644 runtime/include/memlogging.h create mode 100644 runtime/src/memlogging.c diff --git a/runtime/include/memlogging.h b/runtime/include/memlogging.h new file mode 100644 index 000000000..8584620fc --- /dev/null +++ b/runtime/include/memlogging.h @@ -0,0 +1,15 @@ +#pragma once +#include +#include + +struct mem_logging_obj { + uint32_t log_size; + char *logger; + uint32_t offset; + FILE* fout; +}; + +void mem_log_init(uint32_t log_size, char const* file); +void mem_log_init2(uint32_t log_size, FILE* file); +void mem_log(char const * fmt, ...); +void dump_log_to_file(); diff --git a/runtime/include/sandbox_perf_log.h b/runtime/include/sandbox_perf_log.h index a7a96de56..dac656410 100644 --- a/runtime/include/sandbox_perf_log.h +++ b/runtime/include/sandbox_perf_log.h @@ -3,6 +3,7 @@ #include "pretty_print.h" #include "runtime.h" #include "sandbox_types.h" +#include "memlogging.h" extern FILE *sandbox_perf_log; @@ -29,23 +30,36 @@ sandbox_perf_log_print_entry(struct sandbox *sandbox) /* If the log was not defined by an environment variable, early out */ if (sandbox_perf_log == NULL) return; - uint64_t queued_duration = sandbox->timestamp_of.dispatched - sandbox->timestamp_of.allocation; + uint64_t queued_duration = (sandbox->timestamp_of.dispatched - sandbox->timestamp_of.allocation) / runtime_processor_speed_MHz; + bool miss_deadline = sandbox->timestamp_of.completion > sandbox->absolute_deadline ? true : false; + uint64_t total_time = (sandbox->timestamp_of.completion - sandbox->timestamp_of.allocation) / runtime_processor_speed_MHz; + uint64_t execution_time = (sandbox->duration_of_state[SANDBOX_RUNNING_SYS] + sandbox->duration_of_state[SANDBOX_RUNNING_USER]) + / runtime_processor_speed_MHz; + + if (miss_deadline) { + mem_log("%u miss deadline total time %lu execution time %lu queue %lu module name %s\n", sandbox->id, total_time, execution_time, + queued_duration, sandbox->module->path); + } else { + mem_log("%u meet deadline total time %lu execution time %lu queue %lu module name %s\n", sandbox->id, total_time, execution_time, + queued_duration, sandbox->module->path); + } /* * Assumption: A sandbox is never able to free pages. If linear memory management * becomes more intelligent, then peak linear memory size needs to be tracked * seperately from current linear memory size. */ - fprintf(sandbox_perf_log, "%lu,%s,%s,%s,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%u\n", + /*mem_log("%lu,%s,%s,%s,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%u\n", sandbox->id, sandbox->tenant->name, sandbox->route->route, sandbox_state_stringify(sandbox->state), - sandbox->route->relative_deadline, sandbox->total_time, queued_duration, - sandbox->duration_of_state[SANDBOX_UNINITIALIZED], sandbox->duration_of_state[SANDBOX_ALLOCATED], - sandbox->duration_of_state[SANDBOX_INITIALIZED], sandbox->duration_of_state[SANDBOX_RUNNABLE], - sandbox->duration_of_state[SANDBOX_INTERRUPTED], sandbox->duration_of_state[SANDBOX_PREEMPTED], - sandbox->duration_of_state[SANDBOX_RUNNING_SYS], sandbox->duration_of_state[SANDBOX_RUNNING_USER], - sandbox->duration_of_state[SANDBOX_ASLEEP], sandbox->duration_of_state[SANDBOX_RETURNED], - sandbox->duration_of_state[SANDBOX_COMPLETE], sandbox->duration_of_state[SANDBOX_ERROR], + sandbox->route->relative_deadline/runtime_processor_speed_MHz, sandbox->total_time/runtime_processor_speed_MHz, queued_duration, + sandbox->duration_of_state[SANDBOX_UNINITIALIZED]/runtime_processor_speed_MHz, sandbox->duration_of_state[SANDBOX_ALLOCATED]/runtime_processor_speed_MHz, + sandbox->duration_of_state[SANDBOX_INITIALIZED]/runtime_processor_speed_MHz, sandbox->duration_of_state[SANDBOX_RUNNABLE]/runtime_processor_speed_MHz, + sandbox->duration_of_state[SANDBOX_INTERRUPTED]/runtime_processor_speed_MHz, sandbox->duration_of_state[SANDBOX_PREEMPTED]/runtime_processor_speed_MHz, + sandbox->duration_of_state[SANDBOX_RUNNING_SYS]/runtime_processor_speed_MHz, sandbox->duration_of_state[SANDBOX_RUNNING_USER]/runtime_processor_speed_MHz, + sandbox->duration_of_state[SANDBOX_ASLEEP]/runtime_processor_speed_MHz, sandbox->duration_of_state[SANDBOX_RETURNED]/runtime_processor_speed_MHz, + sandbox->duration_of_state[SANDBOX_COMPLETE]/runtime_processor_speed_MHz, sandbox->duration_of_state[SANDBOX_ERROR]/runtime_processor_speed_MHz, runtime_processor_speed_MHz); + */ } static inline void diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index e925768db..530843b8b 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -113,7 +113,6 @@ scheduler_edf_get_next() /* Get the deadline of the sandbox at the head of the local queue */ struct sandbox *local = local_runqueue_get_next(); uint64_t local_deadline = local == NULL ? UINT64_MAX : local->absolute_deadline; - struct sandbox *global = NULL; if (local != NULL) { if (local->state == SANDBOX_INITIALIZED) { diff --git a/runtime/src/memlogging.c b/runtime/src/memlogging.c new file mode 100644 index 000000000..2c3e7b703 --- /dev/null +++ b/runtime/src/memlogging.c @@ -0,0 +1,122 @@ +#include +#include "memlogging.h" +#include "panic.h" + +__thread struct mem_logging_obj log_obj; + +/** + * Initialize memory log. This should be called in each worker thread. + * Every worker thread writes log to its own memory. + * @param log_size the number of bytes of memory to allocate for logging + * @param file the FILE pointer to an opened file, each worker thread will + * dump the memory log to this file when sledge exits. The file is + * defined by an environment variable + */ +void +mem_log_init2(uint32_t log_size, FILE* file) +{ +#ifndef LOG_RUNTIME_MEM_LOG + return; +#endif + log_obj.log_size = log_size; + log_obj.logger = (char *)malloc(log_size); + if (!log_obj.logger) { + panic("failed to allocate memory for logging\n"); + } + + log_obj.offset = 0; + log_obj.fout = file; +} + +/** + * Initialize memory log. This should be called in each worker thread. + * Every worker thread writes log to its own memory. + * @param log_size the number of bytes of memory to allocate for logging + * @param file the file to dump the memory log when sledge exits + */ +void +mem_log_init(uint32_t log_size, char const* file) +{ +#ifndef LOG_RUNTIME_MEM_LOG + return; +#endif + log_obj.log_size = log_size; + log_obj.logger = (char *)malloc(log_size); + if (!log_obj.logger) { + panic("failed to allocate memory for logging\n"); + } + + log_obj.offset = 0; + log_obj.fout = fopen(file, "w"); +} + +/** + * Prints log to memory + */ +void +mem_log(char const * fmt, ...) +{ +#ifndef LOG_RUNTIME_MEM_LOG + return; +#endif + assert(log_obj.logger); + if (!log_obj.fout) { + return; + } + + va_list va; + va_start(va, fmt); + int n = vsnprintf(log_obj.logger + log_obj.offset, log_obj.log_size - log_obj.offset, fmt, va); + va_end(va); + + if (n < 0) { + /* Based on the doc of vsnprintf, the write is failed if n is negative */ + panic("failed to write data to memory, return value:%d\n", n); + } else if (n >= log_obj.log_size - log_obj.offset) { + /* Memory is full, realloc memory */ + char* old_logger = log_obj.logger; + + while (n >=log_obj.log_size - log_obj.offset) { + log_obj.logger = (char *)realloc(log_obj.logger, log_obj.log_size * 2); + if (!log_obj.logger) { + log_obj.logger = old_logger; + dump_log_to_file(log_obj); + panic("failed to realloc memory for logging\n"); + } + + log_obj.log_size = log_obj.log_size * 2; + va_start(va, fmt); + n = vsnprintf(log_obj.logger + log_obj.offset, log_obj.log_size - log_obj.offset, fmt, va); + va_end(va); + } + log_obj.offset += n; + } else { + /* Write Success */ + log_obj.offset += n; + } +} + +/** + * Dump log from memory to file. This should be called when a worker thread receives SIGINT signal + */ + +void +dump_log_to_file() +{ +#ifndef LOG_RUNTIME_MEM_LOG + return; +#endif + if (!log_obj.fout) { + return; + } + + assert(log_obj.logger); + + uint32_t write_bytes = 0; + while(write_bytes != log_obj.offset) { + int return_bytes = fprintf(log_obj.fout, "%s", log_obj.logger + write_bytes); + write_bytes += return_bytes; + } + fflush(log_obj.fout); +} + diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index fc1b3e514..d504263e9 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -24,6 +24,7 @@ #include "scheduler.h" #include "software_interrupt.h" #include "software_interrupt_counts.h" +#include "memlogging.h" extern time_t t_start; extern thread_local bool pthread_stop; @@ -216,6 +217,8 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void /* Stop the alarm timer first */ software_interrupt_disarm_timer(); sigint_propagate_workers_listener(signal_info); + dump_log_to_file(); + /* calculate the throughput */ time_t t_end = time(NULL); double seconds = difftime(t_end, t_start); diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c index 87d7b91d4..3d78ffad1 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c @@ -7,6 +7,7 @@ #include #include "current_sandbox.h" +#include "memlogging.h" #include "local_cleanup_queue.h" #include "local_runqueue.h" #include "local_runqueue_list.h" @@ -22,6 +23,7 @@ * Worker Thread State * **************************/ +extern FILE *sandbox_perf_log; thread_local bool pthread_stop = false; /* context of the runtime thread before running sandboxes or to resume its "main". */ @@ -56,6 +58,9 @@ worker_thread_main(void *argument) scheduler_runqueue_initialize(); + /* Initialize memory logging, set 100M memory for logging */ + mem_log_init2(2*1024*1024*1024*1024, sandbox_perf_log); + /* Initialize Cleanup Queue */ local_cleanup_queue_initialize(); diff --git a/runtime/tests/debug.sh b/runtime/tests/debug.sh index 849fdd415..9a792d49e 100755 --- a/runtime/tests/debug.sh +++ b/runtime/tests/debug.sh @@ -12,8 +12,10 @@ path=`pwd` echo $project_path cd $project_path/runtime/bin #export SLEDGE_DISABLE_PREEMPTION=true -#export SLEDGE_SANDBOX_PERF_LOG=$path/srsf.log -export SLEDGE_NWORKERS=1 +export SLEDGE_SANDBOX_PERF_LOG=$path/srsf.log +export SLEDGE_NWORKERS=6 +export SLEDGE_FIRST_WORKER_COREID=7 +export SLEDGE_NLISTENERS=6 export LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" #gdb --eval-command="handle SIGUSR1 nostop" \ # --eval-command="set pagination off" \ From 5f80df626794d8ec7c5bda64ff1ac97da140c4d5 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 16 Mar 2023 12:44:49 -0600 Subject: [PATCH 018/198] change memory buffer size for logging --- runtime/src/worker_thread.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c index 3d78ffad1..286f4da97 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c @@ -59,7 +59,7 @@ worker_thread_main(void *argument) scheduler_runqueue_initialize(); /* Initialize memory logging, set 100M memory for logging */ - mem_log_init2(2*1024*1024*1024*1024, sandbox_perf_log); + mem_log_init2(1024*1024*1024, sandbox_perf_log); /* Initialize Cleanup Queue */ local_cleanup_queue_initialize(); From 56a7a3f8c056ce043e6fa1ba7fc5a978a156b193 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Mon, 20 Mar 2023 00:52:23 -0600 Subject: [PATCH 019/198] comment sandbox_state_totals_decrement(last_state) in sandbox_set_as_initialized.h to show the correct number of allocated sandbox --- runtime/include/sandbox_set_as_initialized.h | 2 +- runtime/src/software_interrupt.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/runtime/include/sandbox_set_as_initialized.h b/runtime/include/sandbox_set_as_initialized.h index 9ff7771a1..e7f06a2ce 100644 --- a/runtime/include/sandbox_set_as_initialized.h +++ b/runtime/include/sandbox_set_as_initialized.h @@ -40,7 +40,7 @@ sandbox_set_as_initialized(struct sandbox *sandbox, sandbox_state_t last_state) sandbox->timestamp_of.last_state_change = now; sandbox_state_history_append(&sandbox->state_history, SANDBOX_INITIALIZED); sandbox_state_totals_increment(SANDBOX_INITIALIZED); - sandbox_state_totals_decrement(last_state); + //sandbox_state_totals_decrement(last_state); /* State Change Hooks */ sandbox_state_transition_from_hook(sandbox, last_state); diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index d504263e9..8af8b4bd9 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -224,7 +224,9 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void double seconds = difftime(t_end, t_start); double throughput = atomic_load(&sandbox_state_totals[SANDBOX_COMPLETE]) / seconds; uint32_t total_sandboxes_error = atomic_load(&sandbox_state_totals[SANDBOX_ERROR]); - printf("throughput is %f error request is %u\n", throughput, total_sandboxes_error); + printf("throughput is %f error request %u is complete requests %u total request %u\n", throughput, + total_sandboxes_error, atomic_load(&sandbox_state_totals[SANDBOX_COMPLETE]), + atomic_load(&sandbox_state_totals[SANDBOX_ALLOCATED])); fflush(stdout); pthread_stop = true; break; From 2b4c43b469f84499408b8b0377adca80f50a9a1d Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 24 Mar 2023 11:44:25 -0600 Subject: [PATCH 020/198] change fib.json to support multiple functions --- runtime/tests/fib.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/runtime/tests/fib.json b/runtime/tests/fib.json index 315ba7e31..b43aa5734 100644 --- a/runtime/tests/fib.json +++ b/runtime/tests/fib.json @@ -13,8 +13,18 @@ "expected-execution-us": 4000, "relative-deadline-us": 16000, "http-resp-content-type": "text/plain" + }, + { + "route": "/fib2", + "request-type": 2, + "path": "fibonacci.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 4000, + "relative-deadline-us": 16000, + "http-resp-content-type": "text/plain" } ] } + ] From 07981bb95144c0c3a6682c295a53724b3fe3e0cd Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 24 Mar 2023 11:44:56 -0600 Subject: [PATCH 021/198] uncomment SLEDGE_SANDBOX_PERF_LOG in start.sh --- runtime/tests/start.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/tests/start.sh b/runtime/tests/start.sh index 7262b64c8..6b7781b9d 100755 --- a/runtime/tests/start.sh +++ b/runtime/tests/start.sh @@ -27,7 +27,7 @@ export SLEDGE_FIRST_WORKER_COREID=$first_worker_core_id export SLEDGE_NWORKERS=$worker_num export SLEDGE_NLISTENERS=$listener_num #export SLEDGE_SCHEDULER=EDF -#export SLEDGE_SANDBOX_PERF_LOG=$path/$output +export SLEDGE_SANDBOX_PERF_LOG=$path/server.log #echo $SLEDGE_SANDBOX_PERF_LOG cd $project_path/runtime/bin #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_fibonacci.json From 735de18e4963fbb602d0407b102d2b434aa7135b Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 24 Mar 2023 11:54:03 -0600 Subject: [PATCH 022/198] add LOG_RUNTIME_MEM_LOG definition in runtime/Makefile --- runtime/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/runtime/Makefile b/runtime/Makefile index d0b271797..607870e7f 100644 --- a/runtime/Makefile +++ b/runtime/Makefile @@ -94,6 +94,8 @@ BINARY_NAME=sledgert # This flag has a dependency on the flag HTTP_ROUTE_TOTAL_COUNTERS # CFLAGS += -DROUTE_LATENCY +# This flag enables print any log into memory buffer + CFLAGS += -DLOG_RUNTIME_MEM_LOG # This flag tracks the total number of sandboxes in the various states # It is useful to debug if sandboxes are "getting caught" in a particular state CFLAGS += -DSANDBOX_STATE_TOTALS From cfcf62105452ed2726d9ee8d9a01d241c1864cfc Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 24 Mar 2023 13:57:27 -0600 Subject: [PATCH 023/198] 1. solve incomplete log printing when receive SIGINT 2. print out total local requests number of each worker thread --- runtime/include/sandbox_perf_log.h | 9 +++++---- runtime/src/local_runqueue.c | 2 ++ runtime/src/software_interrupt.c | 10 +++++----- runtime/src/worker_thread.c | 3 ++- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/runtime/include/sandbox_perf_log.h b/runtime/include/sandbox_perf_log.h index dac656410..4cc94888b 100644 --- a/runtime/include/sandbox_perf_log.h +++ b/runtime/include/sandbox_perf_log.h @@ -6,6 +6,7 @@ #include "memlogging.h" extern FILE *sandbox_perf_log; +extern thread_local int worker_thread_idx; /** * @brief Prints headers for the per-sandbox perf logs @@ -38,11 +39,11 @@ sandbox_perf_log_print_entry(struct sandbox *sandbox) / runtime_processor_speed_MHz; if (miss_deadline) { - mem_log("%u miss deadline total time %lu execution time %lu queue %lu module name %s\n", sandbox->id, total_time, execution_time, - queued_duration, sandbox->module->path); + mem_log("tid %d %u miss deadline total time %lu execution time %lu queue %lu module name %s\n", worker_thread_idx, + sandbox->id, total_time, execution_time, queued_duration, sandbox->module->path); } else { - mem_log("%u meet deadline total time %lu execution time %lu queue %lu module name %s\n", sandbox->id, total_time, execution_time, - queued_duration, sandbox->module->path); + mem_log("tid %d %u meet deadline total time %lu execution time %lu queue %lu module name %s\n", worker_thread_idx, + sandbox->id, total_time, execution_time, queued_duration, sandbox->module->path); } /* * Assumption: A sandbox is never able to free pages. If linear memory management diff --git a/runtime/src/local_runqueue.c b/runtime/src/local_runqueue.c index cde35dd17..1e4fd8a8a 100644 --- a/runtime/src/local_runqueue.c +++ b/runtime/src/local_runqueue.c @@ -6,6 +6,7 @@ #include "local_runqueue.h" +thread_local uint32_t total_local_requests = 0; static struct local_runqueue_config local_runqueue; #ifdef LOG_LOCAL_RUNQUEUE @@ -51,6 +52,7 @@ void local_runqueue_delete(struct sandbox *sandbox) { assert(local_runqueue.delete_fn != NULL); + total_local_requests++; #ifdef LOG_LOCAL_RUNQUEUE local_runqueue_count--; #endif diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index 8af8b4bd9..1db3b82d6 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -28,6 +28,7 @@ extern time_t t_start; extern thread_local bool pthread_stop; +extern thread_local uint32_t total_local_requests; thread_local _Atomic volatile sig_atomic_t handler_depth = 0; thread_local _Atomic volatile sig_atomic_t deferred_sigalrm = 0; @@ -217,17 +218,16 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void /* Stop the alarm timer first */ software_interrupt_disarm_timer(); sigint_propagate_workers_listener(signal_info); - dump_log_to_file(); /* calculate the throughput */ time_t t_end = time(NULL); double seconds = difftime(t_end, t_start); double throughput = atomic_load(&sandbox_state_totals[SANDBOX_COMPLETE]) / seconds; uint32_t total_sandboxes_error = atomic_load(&sandbox_state_totals[SANDBOX_ERROR]); - printf("throughput is %f error request %u is complete requests %u total request %u\n", throughput, - total_sandboxes_error, atomic_load(&sandbox_state_totals[SANDBOX_COMPLETE]), - atomic_load(&sandbox_state_totals[SANDBOX_ALLOCATED])); - fflush(stdout); + mem_log("throughput %f error request %u complete requests %u total request %u total_local_requests %u\n", + throughput, total_sandboxes_error, atomic_load(&sandbox_state_totals[SANDBOX_COMPLETE]), + atomic_load(&sandbox_state_totals[SANDBOX_ALLOCATED]), total_local_requests); + dump_log_to_file(); pthread_stop = true; break; } diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c index 286f4da97..684bca1bc 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c @@ -83,5 +83,6 @@ worker_thread_main(void *argument) scheduler_idle_loop(); - panic("Worker Thread unexpectedly completed idle loop."); + //panic("Worker Thread unexpectedly completed idle loop."); + return NULL; } From e7c50535e29b683e1c7baf528e036cc1e27d9388 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 24 Mar 2023 17:29:37 -0600 Subject: [PATCH 024/198] gracefully stop sledge when receive SIGINT --- runtime/include/listener_thread.h | 2 +- runtime/src/listener_thread.c | 21 ++++++++++++++++----- runtime/src/software_interrupt.c | 17 ++++++++++++++--- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/runtime/include/listener_thread.h b/runtime/include/listener_thread.h index c731f99f5..5c3ba6f04 100644 --- a/runtime/include/listener_thread.h +++ b/runtime/include/listener_thread.h @@ -15,7 +15,7 @@ extern thread_local pthread_t listener_thread_id; void listener_thread_initialize(uint8_t thread_id); -noreturn void *listener_thread_main(void *dummy); +void *listener_thread_main(void *dummy); void listener_thread_register_http_session(struct http_session *http); void dispatcher_send_response(void *req_handle, char* msg, size_t msg_len); diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index c1bace402..8bcdade65 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -19,6 +19,7 @@ struct priority_queue* worker_queues[1024]; extern uint32_t runtime_worker_threads_count; thread_local uint32_t rr_index = 0; +extern thread_local bool pthread_stop; time_t t_start; extern bool first_request_comming; @@ -43,6 +44,7 @@ int listener_thread_epoll_file_descriptor; thread_local uint8_t dispatcher_thread_idx; thread_local pthread_t listener_thread_id; +thread_local bool is_listener = false; /** * Initializes the listener thread, pinned to core 0, and starts to listen for requests @@ -51,6 +53,7 @@ void listener_thread_initialize(uint8_t thread_id) { printf("Starting listener thread\n"); + cpu_set_t cs; CPU_ZERO(&cs); @@ -487,9 +490,13 @@ void dispatcher_send_response(void *req_handle, char* msg, size_t msg_len) { * listener_thread_epoll_file_descriptor - the epoll file descriptor * */ -noreturn void * +void * listener_thread_main(void *dummy) { + is_listener = true; + /* Unmask SIGINT signals */ + software_interrupt_unmask_signal(SIGINT); + /* Index was passed via argument */ dispatcher_thread_idx = *(int *)dummy; @@ -504,9 +511,13 @@ listener_thread_main(void *dummy) printf("dispatcher_thread_idx is %d\n", dispatcher_thread_idx); erpc_start(NULL, dispatcher_thread_idx, NULL, 0); - erpc_run_event_loop(dispatcher_thread_idx, 100000); + + while (!pthread_stop) { + erpc_run_event_loop(dispatcher_thread_idx, 1000); + } - while (true) { + while (!pthread_stop) { + printf("pthread_stop is false\n"); /* Block indefinitely on the epoll file descriptor, waiting on up to a max number of events */ int descriptor_count = epoll_wait(listener_thread_epoll_file_descriptor, epoll_events, RUNTIME_MAX_EPOLL_EVENTS, -1); @@ -539,6 +550,6 @@ listener_thread_main(void *dummy) } } } - - panic("Listener thread unexpectedly broke loop\n"); + return NULL; + //panic("Listener thread unexpectedly broke loop\n"); } diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index 1db3b82d6..07ded3fd0 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -28,6 +28,7 @@ extern time_t t_start; extern thread_local bool pthread_stop; +extern thread_local bool is_listener; extern thread_local uint32_t total_local_requests; thread_local _Atomic volatile sig_atomic_t handler_depth = 0; thread_local _Atomic volatile sig_atomic_t deferred_sigalrm = 0; @@ -37,6 +38,7 @@ thread_local _Atomic volatile sig_atomic_t deferred_sigalrm = 0; **************************************/ extern pthread_t *runtime_worker_threads; +extern pthread_t *runtime_listener_threads; #ifdef SANDBOX_STATE_TOTALS extern _Atomic uint32_t sandbox_state_totals[SANDBOX_STATE_COUNT]; @@ -99,6 +101,12 @@ sigint_propagate_workers_listener(siginfo_t *signal_info) assert(runtime_worker_threads[i] != 0); pthread_kill(runtime_worker_threads[i], SIGINT); } + for (int i = 0; i < runtime_listener_threads_count;i++) { + if (pthread_self() == runtime_listener_threads[i]) continue; + + assert(runtime_listener_threads[i] != 0); + pthread_kill(runtime_listener_threads[i], SIGINT); + } } else { /* Signal forwarded from another thread. Just confirm it resulted from pthread_kill */ assert(signal_info->si_code == SI_TKILL); @@ -214,11 +222,14 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void break; } - case SIGINT: { - /* Stop the alarm timer first */ - software_interrupt_disarm_timer(); + case SIGINT: { /* Stop the alarm timer first */ software_interrupt_disarm_timer(); sigint_propagate_workers_listener(signal_info); + if (is_listener) { + pthread_stop = true; + break; + } + /* calculate the throughput */ time_t t_end = time(NULL); double seconds = difftime(t_end, t_start); From 9084334bcca5764b1adabcb0eff7cd0aa9864d9d Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Sat, 25 Mar 2023 01:04:06 -0600 Subject: [PATCH 025/198] increase init length to 2560000 for local runqueue. --- runtime/include/runtime.h | 2 +- runtime/include/sandbox_perf_log.h | 9 +++++---- runtime/include/scheduler.h | 4 ++++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/runtime/include/runtime.h b/runtime/include/runtime.h index 6148539f9..09d338d9d 100644 --- a/runtime/include/runtime.h +++ b/runtime/include/runtime.h @@ -26,7 +26,7 @@ #define RUNTIME_MAX_EPOLL_EVENTS 128 #define RUNTIME_MAX_TENANT_COUNT 65535 /* Use UDP port to index tenent */ #define RUNTIME_RELATIVE_DEADLINE_US_MAX 3600000000 /* One Hour. Fits in uint32_t */ -#define RUNTIME_RUNQUEUE_SIZE 256 /* Minimum guaranteed size. Might grow! */ +#define RUNTIME_RUNQUEUE_SIZE 2560000 /* Minimum guaranteed size. Might grow! */ #define RUNTIME_TENANT_QUEUE_SIZE 4096 enum RUNTIME_SIGALRM_HANDLER diff --git a/runtime/include/sandbox_perf_log.h b/runtime/include/sandbox_perf_log.h index 4cc94888b..6eec336fa 100644 --- a/runtime/include/sandbox_perf_log.h +++ b/runtime/include/sandbox_perf_log.h @@ -38,12 +38,13 @@ sandbox_perf_log_print_entry(struct sandbox *sandbox) uint64_t execution_time = (sandbox->duration_of_state[SANDBOX_RUNNING_SYS] + sandbox->duration_of_state[SANDBOX_RUNNING_USER]) / runtime_processor_speed_MHz; + uint64_t init_time = sandbox->duration_of_state[SANDBOX_INITIALIZED] / runtime_processor_speed_MHz; if (miss_deadline) { - mem_log("tid %d %u miss deadline total time %lu execution time %lu queue %lu module name %s\n", worker_thread_idx, - sandbox->id, total_time, execution_time, queued_duration, sandbox->module->path); + mem_log("%u miss %lu %lu %lu %s %lu\n", sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route, + init_time); } else { - mem_log("tid %d %u meet deadline total time %lu execution time %lu queue %lu module name %s\n", worker_thread_idx, - sandbox->id, total_time, execution_time, queued_duration, sandbox->module->path); + mem_log("%u meet %lu %lu %lu %s %lu\n", sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route, + init_time); } /* * Assumption: A sandbox is never able to free pages. If linear memory management diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index 530843b8b..4a2d8769a 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -116,6 +116,10 @@ scheduler_edf_get_next() if (local != NULL) { if (local->state == SANDBOX_INITIALIZED) { + /* add by xiaosu */ + //local->duration_of_state[SANDBOX_INITIALIZED] = 0; + //local->timestamp_of.last_state_change = __getcycles(); + /* end by xiaosu */ sandbox_prepare_execution_environment(local); assert(local->state == SANDBOX_INITIALIZED); sandbox_set_as_runnable(local, SANDBOX_INITIALIZED); From a845fa51cf3aa97771101a6920e6b71fe5e6e775 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Mon, 27 Mar 2023 10:16:00 -0600 Subject: [PATCH 026/198] upload meet_deadline_percentage.py to tests --- runtime/tests/meet_deadline_percentage.py | 343 ++++++++++++++++++++++ 1 file changed, 343 insertions(+) create mode 100644 runtime/tests/meet_deadline_percentage.py diff --git a/runtime/tests/meet_deadline_percentage.py b/runtime/tests/meet_deadline_percentage.py new file mode 100644 index 000000000..be24e23ca --- /dev/null +++ b/runtime/tests/meet_deadline_percentage.py @@ -0,0 +1,343 @@ +import sys +import json +from collections import defaultdict +import numpy as np + +def def_list_value(): + return [0, 0, 0, 0, 0] +def def_value(): + return 0 + +def count_miss_or_meet_deadline_requests(file_dir, percentage): + ### each time for a request + request_times_dict = defaultdict(def_list_value) + #### get execution time + running_time_dict = defaultdict(def_value) + queuing_times_dict = defaultdict(def_value) + total_times_dict = defaultdict(def_value) + runnable_times_dict = defaultdict(def_value) + blocked_times_dict = defaultdict(def_value) + initializing_times_dict = defaultdict(def_value) + execution_times_dict = defaultdict(def_value) + + ### init overhead + ### queuelength + queuelength_dict = defaultdict(list) + ### + running_times = defaultdict(list) + queuing_times = defaultdict(list) + total_times = defaultdict(list) + runnable_times = defaultdict(list) + blocked_times = defaultdict(list) + initializing_times = defaultdict(list) + execution_times = defaultdict(list) + #### + request_counter = defaultdict(def_value) + total_time_dist = defaultdict(list) + total_workload_dist = defaultdict(def_value) + total_real_time_workload_dist = defaultdict(def_value) + real_time_workload_times_dist = defaultdict(list) + real_time_workload_workloads_dist = defaultdict(list) + real_time_workload_requests_dist = defaultdict(list) + min_time = sys.maxsize + # list[0] is meet deadline number, list[1] is miss deadline number + delays_dict = defaultdict(list) + max_latency_dist = defaultdict(def_value) + total_deadline = 0 + miss_deadline_dist = defaultdict(def_value) + meet_deadline_dist = defaultdict(def_value) + meet_deadline = 0 + miss_deadline = 0 + max_sc = 0 + fo = open(file_dir, "r+") + for line in fo: + line = line.strip() + if "meet" in line: + meet_deadline += 1 + name = line.split(" ")[5] + request_counter[name] += 1 + total_time = int(line.split(" ")[2]) + total_time_dist[name].append(total_time) + if total_time > max_latency_dist[name]: + max_latency_dist[name] = total_time + meet_deadline_dist[name] += 1 + exe_time = int(line.split(" ")[3]) + running_times[name].append(exe_time); + queue_time = int(line.split(" ")[4]) + queuing_times[name].append(queue_time); + if "miss" in line: + miss_deadline += 1 + name = line.split(" ")[5] + total_time = int(line.split(" ")[2]) + if total_time > max_latency_dist[name]: + max_latency_dist[name] = total_time + request_counter[name] += 1 + total_time_dist[name].append(total_time) + miss_deadline_dist[name] += 1 + exe_time = int(line.split(" ")[3]) + running_times[name].append(exe_time); + queue_time = int(line.split(" ")[4]) + queuing_times[name].append(queue_time); + #print("name:", name) + if "thread id" in line: + part1,queue_len = line.split(":") + thread_id = part1.split(" ")[2] + queuelength_dict[thread_id] = queue_len.split(" ") + ### calculate the execution time + if "memory" in line or "total_time" in line or "min" in line or "miss" in line or "meet" in line or "time " in line or "scheduling count" in line or "thread id" in line: + continue + t = line.split(",") + id = t[1] #request id + func_idx = t[2][-9] #function id + if t[2][-10] == "1": + #func_idx = t[2][-10:-9] + func_idx = t[2][-10] + t[2][-9] + joined_key = id + "_" + func_idx + running_time_dict[joined_key] += int(t[9]) + queuing_times_dict[joined_key] += int(t[6]) + total_times_dict[joined_key] += int(t[5]) + runnable_times_dict[joined_key] += int(t[8]) + blocked_times_dict[joined_key] += int(t[10]) + initializing_times_dict[joined_key] += int(t[7]) + + ### get each time for a request + request_times_dict[id][0] += int(t[6]) # global queuing time + request_times_dict[id][1] += int(t[8]) # local queuing time + request_times_dict[id][2] += int(t[10]) # blocking time + request_times_dict[id][3] += int(t[5]) # total latency + ### + + miss_deadline_percentage = (miss_deadline * 100) / (miss_deadline + meet_deadline) + print("meet deadline num:", meet_deadline) + print("miss deadline num:", miss_deadline) + print("total num:", meet_deadline + miss_deadline) + print("miss deadline percentage:", miss_deadline_percentage) + print("scheduling counter:", max_sc) + +# func_name_dict = { +# "cifar10_1": "105k-2", +# "cifar10_2": "305k-2", +# "cifar10_3": "5k-2", +# "cifar10_4": "545k-2", +# "cifar10_5": "105k-4", +# "cifar10_6": "305k-4", +# "cifar10_7": "5k-4", +# "cifar10_8": "545k-4", +# "cifar10_9": "105k-8", +# "cifar10_10": "305k-8", +# "cifar10_11": "5k-8", +# "cifar10_12": "545k-8", +# "resize": "resize", +# "fibonacci": "fibonacci", +# "resize3": "resize3" +# } + func_name_with_id = { + "1": "105k-2", + "2": "305k-2", + "3": "5k-2", + "4": "40k-2", + "5": "105k-10", + "6": "305k-10", + "7": "5k-10", + "8": "40k-10", + "9": "105k-8", + "10": "305k-8", + "11": "5k-8", + "12": "40k-8", + "noop1" : "noop1", + "noop2" : "noop2", + "noop3" : "noop3", + "noop4" : "noop4", + "noop5" : "noop5" + } + + func_name_dict = { + "cifar10_1": "105k-2", + "cifar10_2": "305k-2", + "cifar10_3": "5k-2", + "cifar10_4": "40k-2", + "cifar10_5": "105k-10", + "cifar10_6": "305k-10", + "cifar10_7": "5k-10", + "cifar10_8": "40k-10", + "cifar10_9": "105k-8", + "cifar10_10": "305k-8", + "cifar10_11": "5k-8", + "cifar10_12": "40k-8", + "resize": "resize", + "fibonacci": "fibonacci", + "fibonacci5": "fibonacci5", + "resize3": "resize3", + "noop1" : "noop1", + "noop2" : "noop2", + "noop3" : "noop3", + "noop4" : "noop4", + "noop5" : "noop5" + } +# func_name_dict = { +# "cifar10_1": "105k-2", +# "cifar10_2": "305k-2", +# "cifar10_3": "5k-2", +# "cifar10_4": "40k-2", +# "cifar10_5": "105k-8", +# "cifar10_6": "305k-8", +# "cifar10_7": "5k-8", +# "cifar10_8": "40k-4", +# "cifar10_9": "105k-8", +# "cifar10_10": "305k-8", +# "cifar10_11": "5k-8", +# "cifar10_12": "40k-8", +# "resize": "resize", +# "fibonacci": "fibonacci", +# "resize3": "resize3" +# } + fun_execution_time = { + "cifar10_1": 39786, + "cifar10_2": 98794, + "cifar10_3": 8985, + "cifar10_4": 23826, + "cifar10_5": 39786, + "cifar10_6": 98794, + "cifar10_7": 8985, + "cifar10_8": 23826, + "cifar10_9": 39786, + "cifar10_10": 98794, + "cifar10_11": 8985, + "cifar10_12": 23826, + "fibonacci5": 0, + "fibonacci4": 0, + "noop1" : 0, + "noop2" : 0, + "noop3" : 0, + "noop4" : 0, + "noop5" : 0 + + } +# func_name_with_id = { +# "1": "105k-2", +# "2": "305k-2", +# "3": "5k-2", +# "4": "40k-2", +# "5": "305k-4", +# "6": "5k-4", +# "7": "105k-8", +# "8": "305k-8", +# "9": "5k-8", +# "10": "305k-8", +# "11": "5k-8", +# "12": "40k-8" +# } +# func_name_with_id = { +# "1": "105k-2", +# "2": "305k-2", +# "3": "5k-2", +# "4": "40k-2", +# "5": "105k-8", +# "6": "305k-8", +# "7": "5k-8", +# "8": "305k-8", +# "9": "5k-8", +# "10": "305k-8", +# "11": "5k-8", +# "12": "40k-8" +# } + + for key,value in request_counter.items(): + print(key, ":", str(value), "proportion:", (100*value)/(meet_deadline + miss_deadline)) + for key,value in total_time_dist.items(): + a = np.array(value) + p = np.percentile(a, int(percentage)) + print(key + " " + percentage + " percentage is:" + str(p) + " mean is:" + str(np.mean(value)) + " max latency is:" + str(max_latency_dist[key])) + #total_cpu_times = 0 + #for key,value in meet_deadline_dist.items(): + # total_cpu_times += value * fun_execution_time[key] + # miss_value = miss_deadline_dist[key] + # total_request = miss_value + value + # miss_rate = (miss_value * 100) / total_request + # + # print(func_name_dict[key] + " miss deadline rate:" + str(miss_rate) + " miss count is:" + str(miss_value) + " total request:" + str(total_request)) + #print("effective total cpu times:", total_cpu_times) + #for key,value in real_time_workload_times_dist.items(): + # real_time_workload_times_dist[key] = [x - min_time for x in value] + + for key,value in running_times.items(): + #print("function times:", func_name_with_id[key], np.median(total_times[key]), np.median(running_times[key]), np.median(queuing_times[key]), np.median(runnable_times[key]), np.median(blocked_times[key]), np.median(initializing_times[key])) + print("function exe times:", key, np.median(total_times[key]), np.median(running_times[key]), np.median(queuing_times[key]), np.mean(initializing_times[key])) + for key, value in delays_dict.items(): + new_value = [i/1000 for i in value] + p99 = np.percentile(new_value, 99) + print("function:", key, " delays:", p99) + + total_workload = 0 + with open("total_workload.txt", "w") as f: + for key,value in total_workload_dist.items(): + total_workload += value + #print("thread " + key + " total workload:" + str(value)) + pair = [key + " "] + pair.append(str(value)) + f.writelines(pair) + f.write("\n") + print("total workload is:", total_workload) + + with open("total_real_time_workload.txt", "w") as f: + for key,value in total_real_time_workload_dist.items(): + #print("thread " + key + " total real time workload:" + str(value)) + pair = [key + " "] + pair.append(str(value)) + f.writelines(pair) + f.write("\n") + + js = json.dumps(total_time_dist) + f = open("total_time.txt", 'w') + f.write(js) + f.close() + js2 = json.dumps(real_time_workload_times_dist) + f2 = open("real_workload_times.txt", 'w') + f2.write(js2) + f2.close() + + js3 = json.dumps(real_time_workload_workloads_dist) + f3 = open("real_workload_workloads.txt", 'w') + f3.write(js3) + f3.close() + + js4 = json.dumps(real_time_workload_requests_dist) + f4 = open("real_workload_requests.txt", 'w') + f4.write(js4) + f4.close() + + js5 = json.dumps(running_times) + f5 = open("running_time.txt", 'w') + f5.write(js5) + f5.close() + + js6 = json.dumps(total_times) + f6 = open("total_time2.txt", 'w') + f6.write(js6) + f6.close() + + js7 = json.dumps(delays_dict) + f7 = open("delays.txt", 'w') + f7.write(js7) + f7.close() + + js8 = json.dumps(request_times_dict) + f8 = open("request_time.txt", 'w') + f8.write(js8) + f8.close() + + js9 = json.dumps(queuelength_dict) + f9 = open("5m_queuelength.txt", "w") + f9.write(js9) + f9.close() + + for key,value in total_time_dist.items(): + print(key + ": time list length is ", len(value)) + for key,value in queuelength_dict.items(): + print("thread id:", key, " queuelength:", len(value)) +if __name__ == "__main__": + argv = sys.argv[1:] + if len(argv) < 1: + print("usage ", sys.argv[0], " file dir" " percentage") + sys.exit() + count_miss_or_meet_deadline_requests(argv[0], argv[1]) From 717d64b23b138fb64a1be272918752f73691f9b5 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Mon, 27 Mar 2023 15:27:56 -0600 Subject: [PATCH 027/198] update meet_deadline_percentage.py --- runtime/tests/meet_deadline_percentage.py | 208 +--------------------- 1 file changed, 8 insertions(+), 200 deletions(-) diff --git a/runtime/tests/meet_deadline_percentage.py b/runtime/tests/meet_deadline_percentage.py index be24e23ca..b0d7bf5ba 100644 --- a/runtime/tests/meet_deadline_percentage.py +++ b/runtime/tests/meet_deadline_percentage.py @@ -9,6 +9,7 @@ def def_value(): return 0 def count_miss_or_meet_deadline_requests(file_dir, percentage): + throughput = 0; ### each time for a request request_times_dict = defaultdict(def_list_value) #### get execution time @@ -79,41 +80,18 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): queue_time = int(line.split(" ")[4]) queuing_times[name].append(queue_time); #print("name:", name) - if "thread id" in line: - part1,queue_len = line.split(":") - thread_id = part1.split(" ")[2] - queuelength_dict[thread_id] = queue_len.split(" ") + if "throughput" in line: + throughput = line.split(" ")[1] ### calculate the execution time - if "memory" in line or "total_time" in line or "min" in line or "miss" in line or "meet" in line or "time " in line or "scheduling count" in line or "thread id" in line: - continue - t = line.split(",") - id = t[1] #request id - func_idx = t[2][-9] #function id - if t[2][-10] == "1": - #func_idx = t[2][-10:-9] - func_idx = t[2][-10] + t[2][-9] - joined_key = id + "_" + func_idx - running_time_dict[joined_key] += int(t[9]) - queuing_times_dict[joined_key] += int(t[6]) - total_times_dict[joined_key] += int(t[5]) - runnable_times_dict[joined_key] += int(t[8]) - blocked_times_dict[joined_key] += int(t[10]) - initializing_times_dict[joined_key] += int(t[7]) - - ### get each time for a request - request_times_dict[id][0] += int(t[6]) # global queuing time - request_times_dict[id][1] += int(t[8]) # local queuing time - request_times_dict[id][2] += int(t[10]) # blocking time - request_times_dict[id][3] += int(t[5]) # total latency - ### + #if "memory" in line or "total_time" in line or "min" in line or "miss" in line or "meet" in line or "time " in line or "scheduling count" in line or "thread id" in line: + # continue miss_deadline_percentage = (miss_deadline * 100) / (miss_deadline + meet_deadline) print("meet deadline num:", meet_deadline) print("miss deadline num:", miss_deadline) print("total num:", meet_deadline + miss_deadline) print("miss deadline percentage:", miss_deadline_percentage) - print("scheduling counter:", max_sc) - + print("throughput:", throughput) # func_name_dict = { # "cifar10_1": "105k-2", # "cifar10_2": "305k-2", @@ -130,116 +108,6 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): # "resize": "resize", # "fibonacci": "fibonacci", # "resize3": "resize3" -# } - func_name_with_id = { - "1": "105k-2", - "2": "305k-2", - "3": "5k-2", - "4": "40k-2", - "5": "105k-10", - "6": "305k-10", - "7": "5k-10", - "8": "40k-10", - "9": "105k-8", - "10": "305k-8", - "11": "5k-8", - "12": "40k-8", - "noop1" : "noop1", - "noop2" : "noop2", - "noop3" : "noop3", - "noop4" : "noop4", - "noop5" : "noop5" - } - - func_name_dict = { - "cifar10_1": "105k-2", - "cifar10_2": "305k-2", - "cifar10_3": "5k-2", - "cifar10_4": "40k-2", - "cifar10_5": "105k-10", - "cifar10_6": "305k-10", - "cifar10_7": "5k-10", - "cifar10_8": "40k-10", - "cifar10_9": "105k-8", - "cifar10_10": "305k-8", - "cifar10_11": "5k-8", - "cifar10_12": "40k-8", - "resize": "resize", - "fibonacci": "fibonacci", - "fibonacci5": "fibonacci5", - "resize3": "resize3", - "noop1" : "noop1", - "noop2" : "noop2", - "noop3" : "noop3", - "noop4" : "noop4", - "noop5" : "noop5" - } -# func_name_dict = { -# "cifar10_1": "105k-2", -# "cifar10_2": "305k-2", -# "cifar10_3": "5k-2", -# "cifar10_4": "40k-2", -# "cifar10_5": "105k-8", -# "cifar10_6": "305k-8", -# "cifar10_7": "5k-8", -# "cifar10_8": "40k-4", -# "cifar10_9": "105k-8", -# "cifar10_10": "305k-8", -# "cifar10_11": "5k-8", -# "cifar10_12": "40k-8", -# "resize": "resize", -# "fibonacci": "fibonacci", -# "resize3": "resize3" -# } - fun_execution_time = { - "cifar10_1": 39786, - "cifar10_2": 98794, - "cifar10_3": 8985, - "cifar10_4": 23826, - "cifar10_5": 39786, - "cifar10_6": 98794, - "cifar10_7": 8985, - "cifar10_8": 23826, - "cifar10_9": 39786, - "cifar10_10": 98794, - "cifar10_11": 8985, - "cifar10_12": 23826, - "fibonacci5": 0, - "fibonacci4": 0, - "noop1" : 0, - "noop2" : 0, - "noop3" : 0, - "noop4" : 0, - "noop5" : 0 - - } -# func_name_with_id = { -# "1": "105k-2", -# "2": "305k-2", -# "3": "5k-2", -# "4": "40k-2", -# "5": "305k-4", -# "6": "5k-4", -# "7": "105k-8", -# "8": "305k-8", -# "9": "5k-8", -# "10": "305k-8", -# "11": "5k-8", -# "12": "40k-8" -# } -# func_name_with_id = { -# "1": "105k-2", -# "2": "305k-2", -# "3": "5k-2", -# "4": "40k-2", -# "5": "105k-8", -# "6": "305k-8", -# "7": "5k-8", -# "8": "305k-8", -# "9": "5k-8", -# "10": "305k-8", -# "11": "5k-8", -# "12": "40k-8" # } for key,value in request_counter.items(): @@ -262,82 +130,22 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): for key,value in running_times.items(): #print("function times:", func_name_with_id[key], np.median(total_times[key]), np.median(running_times[key]), np.median(queuing_times[key]), np.median(runnable_times[key]), np.median(blocked_times[key]), np.median(initializing_times[key])) - print("function exe times:", key, np.median(total_times[key]), np.median(running_times[key]), np.median(queuing_times[key]), np.mean(initializing_times[key])) - for key, value in delays_dict.items(): - new_value = [i/1000 for i in value] - p99 = np.percentile(new_value, 99) - print("function:", key, " delays:", p99) + print("function :", key, "total:", np.median(total_time_dist[key]), "exec:", np.median(running_times[key]), "queue:", np.median(queuing_times[key])) - total_workload = 0 - with open("total_workload.txt", "w") as f: - for key,value in total_workload_dist.items(): - total_workload += value - #print("thread " + key + " total workload:" + str(value)) - pair = [key + " "] - pair.append(str(value)) - f.writelines(pair) - f.write("\n") - print("total workload is:", total_workload) - - with open("total_real_time_workload.txt", "w") as f: - for key,value in total_real_time_workload_dist.items(): - #print("thread " + key + " total real time workload:" + str(value)) - pair = [key + " "] - pair.append(str(value)) - f.writelines(pair) - f.write("\n") js = json.dumps(total_time_dist) f = open("total_time.txt", 'w') f.write(js) f.close() - js2 = json.dumps(real_time_workload_times_dist) - f2 = open("real_workload_times.txt", 'w') - f2.write(js2) - f2.close() - - js3 = json.dumps(real_time_workload_workloads_dist) - f3 = open("real_workload_workloads.txt", 'w') - f3.write(js3) - f3.close() - - js4 = json.dumps(real_time_workload_requests_dist) - f4 = open("real_workload_requests.txt", 'w') - f4.write(js4) - f4.close() js5 = json.dumps(running_times) f5 = open("running_time.txt", 'w') f5.write(js5) f5.close() - js6 = json.dumps(total_times) - f6 = open("total_time2.txt", 'w') - f6.write(js6) - f6.close() - - js7 = json.dumps(delays_dict) - f7 = open("delays.txt", 'w') - f7.write(js7) - f7.close() - - js8 = json.dumps(request_times_dict) - f8 = open("request_time.txt", 'w') - f8.write(js8) - f8.close() - - js9 = json.dumps(queuelength_dict) - f9 = open("5m_queuelength.txt", "w") - f9.write(js9) - f9.close() - - for key,value in total_time_dist.items(): - print(key + ": time list length is ", len(value)) - for key,value in queuelength_dict.items(): - print("thread id:", key, " queuelength:", len(value)) if __name__ == "__main__": argv = sys.argv[1:] if len(argv) < 1: - print("usage ", sys.argv[0], " file dir" " percentage") + print("usage ", sys.argv[0], " " " ") sys.exit() count_miss_or_meet_deadline_requests(argv[0], argv[1]) From e9757449ace9bd89f6557683cd8541e27a838225 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Mon, 27 Mar 2023 15:41:03 -0600 Subject: [PATCH 028/198] update meet_deadline_percentage.py --- runtime/tests/meet_deadline_percentage.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/runtime/tests/meet_deadline_percentage.py b/runtime/tests/meet_deadline_percentage.py index b0d7bf5ba..82c0418c9 100644 --- a/runtime/tests/meet_deadline_percentage.py +++ b/runtime/tests/meet_deadline_percentage.py @@ -56,6 +56,7 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): if "meet" in line: meet_deadline += 1 name = line.split(" ")[5] + name = name[1:] request_counter[name] += 1 total_time = int(line.split(" ")[2]) total_time_dist[name].append(total_time) @@ -69,6 +70,7 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): if "miss" in line: miss_deadline += 1 name = line.split(" ")[5] + name = name[1:] total_time = int(line.split(" ")[2]) if total_time > max_latency_dist[name]: max_latency_dist[name] = total_time @@ -89,7 +91,7 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): miss_deadline_percentage = (miss_deadline * 100) / (miss_deadline + meet_deadline) print("meet deadline num:", meet_deadline) print("miss deadline num:", miss_deadline) - print("total num:", meet_deadline + miss_deadline) + print("total requests:", meet_deadline + miss_deadline) print("miss deadline percentage:", miss_deadline_percentage) print("throughput:", throughput) # func_name_dict = { @@ -130,7 +132,7 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): for key,value in running_times.items(): #print("function times:", func_name_with_id[key], np.median(total_times[key]), np.median(running_times[key]), np.median(queuing_times[key]), np.median(runnable_times[key]), np.median(blocked_times[key]), np.median(initializing_times[key])) - print("function :", key, "total:", np.median(total_time_dist[key]), "exec:", np.median(running_times[key]), "queue:", np.median(queuing_times[key])) + print("function :", key, "avg total:", np.median(total_time_dist[key]), "exec:", np.median(running_times[key]), "queue:", np.median(queuing_times[key])) js = json.dumps(total_time_dist) From 7e8f9e390db4f69f173655af7d3423d40ccecbf9 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 31 Mar 2023 16:35:48 -0600 Subject: [PATCH 029/198] 1. add more fine-grained time cost for a request, such as clean up cost of the previous request2. preallocate two linear and stack memorys for each module in each worker thread --- runtime/include/local_cleanup_queue.h | 2 +- runtime/include/module.h | 21 ++++++++- runtime/include/sandbox_functions.h | 2 +- runtime/include/sandbox_perf_log.h | 17 ++++++-- runtime/include/sandbox_set_as_complete.h | 4 +- runtime/include/sandbox_set_as_error.h | 2 +- runtime/include/sandbox_set_as_runnable.h | 2 +- runtime/include/sandbox_types.h | 5 ++- runtime/include/scheduler.h | 53 ++++++++++++++++++++--- runtime/include/tenant_functions.h | 9 ++++ runtime/src/listener_thread.c | 3 +- runtime/src/local_cleanup_queue.c | 10 +++-- runtime/src/local_runqueue_minheap.c | 1 - runtime/src/main.c | 9 ++-- runtime/src/sandbox.c | 33 ++++++++++---- runtime/src/tenant_database.c | 10 +++-- runtime/src/worker_thread.c | 8 ++++ 17 files changed, 152 insertions(+), 39 deletions(-) diff --git a/runtime/include/local_cleanup_queue.h b/runtime/include/local_cleanup_queue.h index 9df6107aa..b2c302605 100644 --- a/runtime/include/local_cleanup_queue.h +++ b/runtime/include/local_cleanup_queue.h @@ -3,5 +3,5 @@ #include "sandbox_types.h" void local_cleanup_queue_add(struct sandbox *sandbox); -void local_cleanup_queue_free(); +int local_cleanup_queue_free(uint64_t *duration, uint64_t *ret); void local_cleanup_queue_initialize(); diff --git a/runtime/include/module.h b/runtime/include/module.h index b2ab6ad83..a56f6777c 100644 --- a/runtime/include/module.h +++ b/runtime/include/module.h @@ -178,11 +178,14 @@ module_allocate_stack(struct module *module) return stack; } -static inline void +static inline uint64_t module_free_stack(struct module *module, struct wasm_stack *stack) { + uint64_t now = __getcycles(); wasm_stack_reinit(stack); + uint64_t d = __getcycles() - now; wasm_stack_pool_add_nolock(&module->pools[worker_thread_idx].stack, stack); + return d; } static inline struct wasm_memory * @@ -214,3 +217,19 @@ module_free_linear_memory(struct module *module, struct wasm_memory *memory) wasm_memory_reinit(memory, module->abi.starting_pages * WASM_PAGE_SIZE); wasm_memory_pool_add_nolock(&module->pools[worker_thread_idx].memory, memory); } + +static inline void +module_preallocate_memory(struct module *module) { + /* preallocate two pairs of linear and stack memory */ + struct wasm_stack *stack1 = module_allocate_stack(module); + struct wasm_memory *memory1 = module_allocate_linear_memory(module); + + struct wasm_stack *stack2 = module_allocate_stack(module); + struct wasm_memory *memory2 = module_allocate_linear_memory(module); + + module_free_linear_memory(module, memory1); + module_free_linear_memory(module, memory2); + + module_free_stack(module, stack1); + module_free_stack(module, stack2); +} diff --git a/runtime/include/sandbox_functions.h b/runtime/include/sandbox_functions.h index bccd5283c..315fc5328 100644 --- a/runtime/include/sandbox_functions.h +++ b/runtime/include/sandbox_functions.h @@ -16,7 +16,7 @@ struct sandbox *sandbox_alloc(struct module *module, struct http_session *sessio struct tenant *tenant, uint64_t admissions_estimate, void *req_handle, uint8_t rpc_id); int sandbox_prepare_execution_environment(struct sandbox *sandbox); -void sandbox_free(struct sandbox *sandbox); +uint64_t sandbox_free(struct sandbox *sandbox, uint64_t *ret); void sandbox_main(struct sandbox *sandbox); void sandbox_switch_to(struct sandbox *next_sandbox); void sandbox_send_response(struct sandbox *sandbox, uint8_t response_code); diff --git a/runtime/include/sandbox_perf_log.h b/runtime/include/sandbox_perf_log.h index 6eec336fa..16d4163d5 100644 --- a/runtime/include/sandbox_perf_log.h +++ b/runtime/include/sandbox_perf_log.h @@ -37,14 +37,23 @@ sandbox_perf_log_print_entry(struct sandbox *sandbox) uint64_t total_time = (sandbox->timestamp_of.completion - sandbox->timestamp_of.allocation) / runtime_processor_speed_MHz; uint64_t execution_time = (sandbox->duration_of_state[SANDBOX_RUNNING_SYS] + sandbox->duration_of_state[SANDBOX_RUNNING_USER]) / runtime_processor_speed_MHz; + + uint64_t cleanup = sandbox->timestamp_of.cleanup / runtime_processor_speed_MHz; + uint64_t other = sandbox->timestamp_of.other / runtime_processor_speed_MHz; + uint64_t t1 = sandbox->ret[0] / runtime_processor_speed_MHz; + uint64_t t2 = sandbox->ret[1] / runtime_processor_speed_MHz; + uint64_t t3 = sandbox->ret[2] / runtime_processor_speed_MHz; + uint64_t t4 = sandbox->ret[3] / runtime_processor_speed_MHz; + uint64_t t5 = sandbox->ret[4] / runtime_processor_speed_MHz; + uint64_t init_time = sandbox->duration_of_state[SANDBOX_INITIALIZED] / runtime_processor_speed_MHz; if (miss_deadline) { - mem_log("%u miss %lu %lu %lu %s %lu\n", sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route, - init_time); + mem_log("tid %d %u miss %lu %lu %lu %s %lu %lu f%d %lu %lu %lu %lu %lu %lu\n", worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route, + init_time, cleanup, sandbox->context_switch_to, other, t1,t2,t3,t4,t5); } else { - mem_log("%u meet %lu %lu %lu %s %lu\n", sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route, - init_time); + mem_log("tid %d %u meet %lu %lu %lu %s %lu %lu f%d %lu %lu %lu %lu %lu %lu\n", worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route, + init_time, cleanup, sandbox->context_switch_to, other, t1,t2,t3,t4,t5); } /* * Assumption: A sandbox is never able to free pages. If linear memory management diff --git a/runtime/include/sandbox_set_as_complete.h b/runtime/include/sandbox_set_as_complete.h index 9ef7dd58f..a440a3870 100644 --- a/runtime/include/sandbox_set_as_complete.h +++ b/runtime/include/sandbox_set_as_complete.h @@ -28,7 +28,7 @@ sandbox_set_as_complete(struct sandbox *sandbox, sandbox_state_t last_state) switch (last_state) { case SANDBOX_RETURNED: { - sandbox->timestamp_of.completion = now; + //sandbox->timestamp_of.completion = now; break; } default: { @@ -52,7 +52,7 @@ sandbox_set_as_complete(struct sandbox *sandbox, sandbox_state_t last_state) admissions_control_subtract(sandbox->admissions_estimate); /* Terminal State Logging for Sandbox */ - sandbox_perf_log_print_entry(sandbox); + //sandbox_perf_log_print_entry(sandbox); sandbox_summarize_page_allocations(sandbox); route_latency_add(&sandbox->route->latency, sandbox->total_time); diff --git a/runtime/include/sandbox_set_as_error.h b/runtime/include/sandbox_set_as_error.h index 39020ed95..34834932c 100644 --- a/runtime/include/sandbox_set_as_error.h +++ b/runtime/include/sandbox_set_as_error.h @@ -64,7 +64,7 @@ sandbox_set_as_error(struct sandbox *sandbox, sandbox_state_t last_state) sandbox->http = NULL; /* Terminal State Logging */ - sandbox_perf_log_print_entry(sandbox); + //sandbox_perf_log_print_entry(sandbox); sandbox_summarize_page_allocations(sandbox); /* State Change Hooks */ diff --git a/runtime/include/sandbox_set_as_runnable.h b/runtime/include/sandbox_set_as_runnable.h index 593976850..115a59158 100644 --- a/runtime/include/sandbox_set_as_runnable.h +++ b/runtime/include/sandbox_set_as_runnable.h @@ -30,7 +30,7 @@ sandbox_set_as_runnable(struct sandbox *sandbox, sandbox_state_t last_state) switch (last_state) { case SANDBOX_INITIALIZED: { - sandbox->timestamp_of.dispatched = now; + //sandbox->timestamp_of.dispatched = now; break; } case SANDBOX_ASLEEP: { diff --git a/runtime/include/sandbox_types.h b/runtime/include/sandbox_types.h index 4d1412c92..2132e7f2c 100644 --- a/runtime/include/sandbox_types.h +++ b/runtime/include/sandbox_types.h @@ -24,6 +24,8 @@ struct sandbox_timestamps { uint64_t allocation; /* Timestamp when sandbox is allocated */ uint64_t dispatched; /* Timestamp when a sandbox is first added to a worker's runqueue */ uint64_t completion; /* Timestamp when sandbox runs to completion */ + uint64_t cleanup; /* Time duration of cleaning up the previous sandboxes */ + uint64_t other; /* Time duration of only sandbox_free */ #ifdef LOG_SANDBOX_MEMORY_PROFILE uint32_t page_allocations[SANDBOX_PAGE_ALLOCATION_TIMESTAMP_COUNT]; size_t page_allocations_size; @@ -78,5 +80,6 @@ struct sandbox { /* System Interface State */ int32_t return_value; wasi_context_t *wasi_context; - + int context_switch_to; /* 1 means context switch to base, 2 means context swtich to next sandbox */ + uint64_t ret[5]; } PAGE_ALIGNED; diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index 4a2d8769a..b3efeb6c9 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -23,6 +23,7 @@ #include "sandbox_set_as_interrupted.h" #include "sandbox_set_as_running_user.h" #include "scheduler_options.h" +#include "sandbox_perf_log.h" extern thread_local bool pthread_stop; @@ -117,8 +118,10 @@ scheduler_edf_get_next() if (local != NULL) { if (local->state == SANDBOX_INITIALIZED) { /* add by xiaosu */ - //local->duration_of_state[SANDBOX_INITIALIZED] = 0; - //local->timestamp_of.last_state_change = __getcycles(); + uint64_t now = __getcycles(); + local->timestamp_of.dispatched = now; + local->duration_of_state[SANDBOX_INITIALIZED] = 0; + local->timestamp_of.last_state_change = now; /* end by xiaosu */ sandbox_prepare_execution_environment(local); assert(local->state == SANDBOX_INITIALIZED); @@ -389,6 +392,10 @@ scheduler_switch_to_base_context(struct arch_context *current_context) static inline void scheduler_idle_loop() { + uint64_t cleanup_cost = 0; + uint64_t other = 0; + int cleanup_count = 0; + uint64_t ret[5] = {0}; while (!pthread_stop) { /* Assumption: only called by the "base context" */ assert(current_sandbox_get() == NULL); @@ -399,12 +406,33 @@ scheduler_idle_loop() /* Switch to a sandbox if one is ready to run */ struct sandbox *next_sandbox = scheduler_get_next(); if (next_sandbox != NULL) { + next_sandbox->timestamp_of.cleanup += cleanup_cost; + next_sandbox->timestamp_of.other += other; + next_sandbox->context_switch_to = 1; + next_sandbox->ret[0] += ret[0]; + next_sandbox->ret[1] += ret[1]; + next_sandbox->ret[2] += ret[2]; + next_sandbox->ret[3] += ret[3]; + next_sandbox->ret[4] += ret[4]; + cleanup_cost = 0; + other = 0; + ret[0] = ret[1] = ret[2] = ret[3] = ret[4] = 0; scheduler_cooperative_switch_to(&worker_thread_base_context, next_sandbox); } - /* Clear the cleanup queue */ - local_cleanup_queue_free(); - + uint64_t now = __getcycles(); + uint64_t duration = 0; + uint64_t ret_inner[5] = {0}; + cleanup_count = local_cleanup_queue_free(&duration, ret_inner); + if (cleanup_count != 0 && cleanup_cost == 0) { + cleanup_cost += __getcycles() - now; + other += duration; + ret[0] += ret_inner[0]; + ret[1] += ret_inner[1]; + ret[2] += ret_inner[2]; + ret[3] += ret_inner[3]; + ret[4] += ret_inner[4]; + } /* Improve the performance of spin-wait loops (works only if preemptions enabled) */ if (runtime_worker_spinloop_pause_enabled) pause(); } @@ -420,6 +448,7 @@ scheduler_idle_loop() static inline void scheduler_cooperative_sched(bool add_to_cleanup_queue) { + //uint64_t now = __getcycles(); struct sandbox *exiting_sandbox = current_sandbox_get(); assert(exiting_sandbox != NULL); @@ -436,9 +465,18 @@ scheduler_cooperative_sched(bool add_to_cleanup_queue) /* Deferred signals should have been cleared by this point */ assert(deferred_sigalrm == 0); + uint64_t now = __getcycles(); + uint64_t duration = 0; + uint64_t ret[5] = {0}; /* We have not added ourself to the cleanup queue, so we can free */ - local_cleanup_queue_free(); - + local_cleanup_queue_free(&duration, ret); + exiting_sandbox->timestamp_of.cleanup += (__getcycles() - now); + exiting_sandbox->timestamp_of.other += duration; + exiting_sandbox->ret[0] += ret[0]; + exiting_sandbox->ret[1] += ret[1]; + exiting_sandbox->ret[2] += ret[2]; + exiting_sandbox->ret[3] += ret[3]; + exiting_sandbox->ret[4] += ret[4]; /* Switch to a sandbox if one is ready to run */ struct sandbox *next_sandbox = scheduler_get_next(); @@ -458,6 +496,7 @@ scheduler_cooperative_sched(bool add_to_cleanup_queue) /* Do not touch sandbox struct after this point! */ if (next_sandbox != NULL) { + next_sandbox->context_switch_to = 2; scheduler_cooperative_switch_to(exiting_context, next_sandbox); } else { scheduler_switch_to_base_context(exiting_context); diff --git a/runtime/include/tenant_functions.h b/runtime/include/tenant_functions.h index fba60dce1..ce708e4a9 100644 --- a/runtime/include/tenant_functions.h +++ b/runtime/include/tenant_functions.h @@ -160,3 +160,12 @@ get_next_timeout_of_tenant(uint64_t replenishment_period) */ int tenant_listen(struct tenant *tenant); int listener_thread_register_tenant(struct tenant *tenant); + +static inline void +tenant_preallocate_memory(struct tenant *tenant, void *arg1, void *arg2) { + struct module **modules = tenant->module_db.modules; + size_t count = tenant->module_db.count; + for(int i = 0; i < count; i++) { + module_preallocate_memory(modules[i]); + } +} diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 8bcdade65..8e7127e25 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -272,7 +272,8 @@ on_client_request_received(struct http_session *session) /* If the global request scheduler is full, return a 429 to the client */ if (unlikely(global_request_scheduler_add(sandbox) == NULL)) { debuglog("Failed to add sandbox to global queue\n"); - sandbox_free(sandbox); + uint64_t ret[5] = {0}; + sandbox_free(sandbox, ret); session->state = HTTP_SESSION_EXECUTION_COMPLETE; http_session_set_response_header(session, 429); on_client_response_header_sending(session); diff --git a/runtime/src/local_cleanup_queue.c b/runtime/src/local_cleanup_queue.c index 1587c5b01..46cfdf785 100644 --- a/runtime/src/local_cleanup_queue.c +++ b/runtime/src/local_cleanup_queue.c @@ -37,15 +37,19 @@ local_cleanup_queue_add(struct sandbox *sandbox) * @brief Frees all sandboxes in the thread local cleanup queue * @return void */ -void -local_cleanup_queue_free() +int +local_cleanup_queue_free(uint64_t *duration, uint64_t *ret) { struct sandbox *sandbox_iterator = NULL; struct sandbox *buffer = NULL; + int cleanup_count = 0; ps_list_foreach_del_d(&local_cleanup_queue, sandbox_iterator, buffer) { ps_list_rem_d(sandbox_iterator); - sandbox_free(sandbox_iterator); + *duration = sandbox_free(sandbox_iterator, ret); + cleanup_count++; } + + return cleanup_count; } diff --git a/runtime/src/local_runqueue_minheap.c b/runtime/src/local_runqueue_minheap.c index 11a0dc21f..936ff0017 100644 --- a/runtime/src/local_runqueue_minheap.c +++ b/runtime/src/local_runqueue_minheap.c @@ -92,7 +92,6 @@ local_runqueue_minheap_initialize() local_runqueue_minheap = priority_queue_initialize(RUNTIME_RUNQUEUE_SIZE, true, sandbox_get_priority); worker_queues[worker_thread_idx] = local_runqueue_minheap; - printf("add local queue with index %d\n", worker_thread_idx); /* Register Function Pointers for Abstract Scheduling API */ struct local_runqueue_config config = { .add_fn = local_runqueue_minheap_add, .add_fn_idx = local_runqueue_minheap_add_index, diff --git a/runtime/src/main.c b/runtime/src/main.c index f070e9a6e..9a5a6ecc4 100644 --- a/runtime/src/main.c +++ b/runtime/src/main.c @@ -516,10 +516,10 @@ main(int argc, char **argv) runtime_allocate_available_cores(); runtime_configure(); runtime_initialize(); - runtime_start_runtime_worker_threads(); + //runtime_start_runtime_worker_threads(); runtime_get_processor_speed_MHz(); - runtime_configure_worker_spinloop_pause(); - software_interrupt_arm_timer(); + //runtime_configure_worker_spinloop_pause(); + //software_interrupt_arm_timer(); #ifdef LOG_TENANT_LOADING @@ -545,6 +545,9 @@ main(int argc, char **argv) } } + runtime_start_runtime_worker_threads(); + software_interrupt_arm_timer(); + listener_threads_initialize(); runtime_boot_timestamp = __getcycles(); diff --git a/runtime/src/sandbox.c b/runtime/src/sandbox.c index db3538d08..e078d5c79 100644 --- a/runtime/src/sandbox.c +++ b/runtime/src/sandbox.c @@ -72,12 +72,14 @@ sandbox_free_globals(struct sandbox *sandbox) wasm_globals_deinit(&sandbox->globals); } -static inline void +static inline uint64_t sandbox_free_stack(struct sandbox *sandbox) { assert(sandbox); - return module_free_stack(sandbox->module, sandbox->stack); + //return module_free_stack(sandbox->module, sandbox->stack); + uint64_t t = module_free_stack(sandbox->module, sandbox->stack); + return t; } @@ -217,17 +219,22 @@ sandbox_alloc(struct module *module, struct http_session *session, struct route } void -sandbox_deinit(struct sandbox *sandbox) +sandbox_deinit(struct sandbox *sandbox, uint64_t *ret) { assert(sandbox != NULL); assert(sandbox != current_sandbox_get()); assert(sandbox->state == SANDBOX_ERROR || sandbox->state == SANDBOX_COMPLETE); + uint64_t now = __getcycles(); auto_buf_deinit(&sandbox->response_body); + uint64_t d1 = __getcycles(); + ret[0] = d1 - now; if (sandbox->rpc_request_body) { free(sandbox->rpc_request_body); sandbox->rpc_request_body = NULL; } + uint64_t d2 = __getcycles(); + ret[1] = d2 - d1; /* Assumption: HTTP session was migrated to listener core */ assert(sandbox->http == NULL); @@ -236,24 +243,34 @@ sandbox_deinit(struct sandbox *sandbox) /* Linear Memory and Guard Page should already have been munmaped and set to NULL */ assert(sandbox->memory == NULL); - if (likely(sandbox->stack != NULL)) sandbox_free_stack(sandbox); + if (likely(sandbox->stack != NULL)) ret[2] = sandbox_free_stack(sandbox); + uint64_t d3 = __getcycles(); + //ret[2] = d3 - d2; if (likely(sandbox->globals.buffer != NULL)) sandbox_free_globals(sandbox); + uint64_t d4 = __getcycles(); + ret[3] = d4 - d3; if (likely(sandbox->wasi_context != NULL)) wasi_context_destroy(sandbox->wasi_context); + uint64_t d5 = __getcycles(); + ret[4] = d5 - d4; } /** * Free stack and heap resources.. also any I/O handles. * @param sandbox */ -void -sandbox_free(struct sandbox *sandbox) +uint64_t +sandbox_free(struct sandbox *sandbox, uint64_t *ret) { assert(sandbox != NULL); assert(sandbox != current_sandbox_get()); assert(sandbox->state == SANDBOX_ERROR || sandbox->state == SANDBOX_COMPLETE); - - sandbox_deinit(sandbox); + + uint64_t now = __getcycles(); + sandbox_perf_log_print_entry(sandbox); + sandbox_deinit(sandbox, ret); + uint64_t d = __getcycles() - now; free(sandbox); + return d; } void sandbox_send_response(struct sandbox *sandbox, uint8_t response_code) { diff --git a/runtime/src/tenant_database.c b/runtime/src/tenant_database.c index c0b5640b9..b4e6eb188 100644 --- a/runtime/src/tenant_database.c +++ b/runtime/src/tenant_database.c @@ -8,7 +8,8 @@ * Tenant Database * ******************/ -struct tenant *tenant_database[RUNTIME_MAX_TENANT_COUNT] = { NULL }; +struct tenant *tenant_database[RUNTIME_MAX_TENANT_COUNT] = { NULL }; // the index is UDP port +struct tenant *tenant_index_database[RUNTIME_MAX_TENANT_COUNT] = { NULL }; // the index is index size_t tenant_database_count = 0; /** @@ -25,6 +26,7 @@ tenant_database_add(struct tenant *tenant) if (tenant_database_count == RUNTIME_MAX_TENANT_COUNT) goto err_no_space; tenant_database[tenant->port] = tenant; + tenant_index_database[tenant_database_count] = tenant; tenant_database_count++; rc = 0; @@ -92,10 +94,10 @@ tenant_database_find_by_ptr(void *ptr) } void -tenant_database_foreach(void (*cb)(struct tenant *, void *), void *arg) +tenant_database_foreach(void (*cb)(struct tenant *, void *), void *arg, void *arg2) { for (size_t i = 0; i < tenant_database_count; i++) { - assert(tenant_database[i]); - cb(tenant_database[i], arg); + assert(tenant_index_database[i]); + cb(tenant_index_database[i], arg); } } diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c index 684bca1bc..1760e51c5 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c @@ -38,6 +38,12 @@ thread_local struct priority_queue *worker_thread_timeout_queue; * Worker Thread Logic * **********************/ +/** + */ + +void preallocate_memory() { + tenant_database_foreach(tenant_preallocate_memory, NULL, NULL); +} /** * The entry function for sandbox worker threads * Initializes thread-local state, unmasks signals, sets up epoll loop and @@ -56,6 +62,8 @@ worker_thread_main(void *argument) // runtime_set_pthread_prio(pthread_self(), 2); pthread_setschedprio(pthread_self(), -20); + preallocate_memory(); + scheduler_runqueue_initialize(); /* Initialize memory logging, set 100M memory for logging */ From da91c3cd266021e10c0de06932627eb1f2291c02 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 31 Mar 2023 17:39:58 -0600 Subject: [PATCH 030/198] 1. move logging from sandbox_free to scheduler_cooperative_sched. 2. check sandbox state to make sure it is in complete or error state before logging to memory --- runtime/include/sandbox_perf_log.h | 4 ++++ runtime/include/scheduler.h | 3 ++- runtime/src/sandbox.c | 1 - 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/runtime/include/sandbox_perf_log.h b/runtime/include/sandbox_perf_log.h index 16d4163d5..833e73ce6 100644 --- a/runtime/include/sandbox_perf_log.h +++ b/runtime/include/sandbox_perf_log.h @@ -28,6 +28,10 @@ sandbox_perf_log_print_header() static inline void sandbox_perf_log_print_entry(struct sandbox *sandbox) { + if (sandbox->state == SANDBOX_COMPLETE || sandbox->state == SANDBOX_ERROR) { + /* only logging when the sandbox is complete or error */ + return; + } /* If the log was not defined by an environment variable, early out */ if (sandbox_perf_log == NULL) return; diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index b3efeb6c9..6d69939f8 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -494,7 +494,8 @@ scheduler_cooperative_sched(bool add_to_cleanup_queue) if (add_to_cleanup_queue) local_cleanup_queue_add(exiting_sandbox); /* Do not touch sandbox struct after this point! */ - + /* Logging this sandbox to memory */ + sandbox_perf_log_print_entry(exiting_sandbox); if (next_sandbox != NULL) { next_sandbox->context_switch_to = 2; scheduler_cooperative_switch_to(exiting_context, next_sandbox); diff --git a/runtime/src/sandbox.c b/runtime/src/sandbox.c index e078d5c79..bc029a11b 100644 --- a/runtime/src/sandbox.c +++ b/runtime/src/sandbox.c @@ -266,7 +266,6 @@ sandbox_free(struct sandbox *sandbox, uint64_t *ret) assert(sandbox->state == SANDBOX_ERROR || sandbox->state == SANDBOX_COMPLETE); uint64_t now = __getcycles(); - sandbox_perf_log_print_entry(sandbox); sandbox_deinit(sandbox, ret); uint64_t d = __getcycles() - now; free(sandbox); From c5153b6f077b6cf4a4b0b08f5774a19bd51ef1a6 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 31 Mar 2023 18:18:01 -0600 Subject: [PATCH 031/198] fix bug: not longging in sandbox_perf_log.h --- runtime/include/sandbox_perf_log.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runtime/include/sandbox_perf_log.h b/runtime/include/sandbox_perf_log.h index 833e73ce6..8c269fabf 100644 --- a/runtime/include/sandbox_perf_log.h +++ b/runtime/include/sandbox_perf_log.h @@ -28,8 +28,9 @@ sandbox_perf_log_print_header() static inline void sandbox_perf_log_print_entry(struct sandbox *sandbox) { - if (sandbox->state == SANDBOX_COMPLETE || sandbox->state == SANDBOX_ERROR) { + if (sandbox->state != SANDBOX_COMPLETE && sandbox->state != SANDBOX_ERROR) { /* only logging when the sandbox is complete or error */ + printf("return state %d\n", sandbox->state); return; } /* If the log was not defined by an environment variable, early out */ From 7bf00335066a5b2109c435344297939c6b9510c0 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 5 Apr 2023 17:16:00 -0600 Subject: [PATCH 032/198] wronly comment unmask alarm signal in previous, just uncomment --- runtime/src/worker_thread.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c index 1760e51c5..427d55a6e 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c @@ -85,8 +85,8 @@ worker_thread_main(void *argument) /* Unmask signals, unless the runtime has disabled preemption */ if (runtime_preemption_enabled) { - //software_interrupt_unmask_signal(SIGALRM); - //software_interrupt_unmask_signal(SIGUSR1); + software_interrupt_unmask_signal(SIGALRM); + software_interrupt_unmask_signal(SIGUSR1); } scheduler_idle_loop(); From e21afb55a2ac0901fcdf4df5aa76fa8d90d1e03d Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 5 Apr 2023 17:39:31 -0600 Subject: [PATCH 033/198] remove one whitespace in printing log to memory --- runtime/include/sandbox_perf_log.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/include/sandbox_perf_log.h b/runtime/include/sandbox_perf_log.h index 8c269fabf..a770b585b 100644 --- a/runtime/include/sandbox_perf_log.h +++ b/runtime/include/sandbox_perf_log.h @@ -54,7 +54,7 @@ sandbox_perf_log_print_entry(struct sandbox *sandbox) uint64_t init_time = sandbox->duration_of_state[SANDBOX_INITIALIZED] / runtime_processor_speed_MHz; if (miss_deadline) { - mem_log("tid %d %u miss %lu %lu %lu %s %lu %lu f%d %lu %lu %lu %lu %lu %lu\n", worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route, + mem_log("tid %d %u miss %lu %lu %lu %s %lu %lu f%d %lu %lu %lu %lu %lu %lu\n", worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route, init_time, cleanup, sandbox->context_switch_to, other, t1,t2,t3,t4,t5); } else { mem_log("tid %d %u meet %lu %lu %lu %s %lu %lu f%d %lu %lu %lu %lu %lu %lu\n", worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route, From 1c5591bfbcf958d0906e757cb1d6ab3824146185 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 6 Apr 2023 14:40:38 -0600 Subject: [PATCH 034/198] replace local rr_index with a global automic request_index to distribute requests to workers with RR --- runtime/include/runtime.h | 14 ++++++++++++++ runtime/src/listener_thread.c | 10 +++------- runtime/src/runtime.c | 4 ++++ 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/runtime/include/runtime.h b/runtime/include/runtime.h index 09d338d9d..a29a3e174 100644 --- a/runtime/include/runtime.h +++ b/runtime/include/runtime.h @@ -35,6 +35,7 @@ enum RUNTIME_SIGALRM_HANDLER RUNTIME_SIGALRM_HANDLER_TRIAGED = 1 }; +extern _Atomic uint64_t request_index; extern pid_t runtime_pid; extern bool runtime_preemption_enabled; extern bool runtime_worker_spinloop_pause_enabled; @@ -70,3 +71,16 @@ runtime_print_sigalrm_handler(enum RUNTIME_SIGALRM_HANDLER variant) return "TRIAGED"; } } + +inline void +request_index_initialize() +{ + atomic_init(&request_index, 0); +} + +inline uint64_t +request_index_increment() +{ + return atomic_fetch_add(&request_index, 1); +} + diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 8e7127e25..53ddc701a 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -18,8 +18,8 @@ struct priority_queue* worker_queues[1024]; extern uint32_t runtime_worker_threads_count; -thread_local uint32_t rr_index = 0; extern thread_local bool pthread_stop; +extern _Atomic uint64_t request_index; time_t t_start; extern bool first_request_comming; @@ -46,6 +46,7 @@ thread_local uint8_t dispatcher_thread_idx; thread_local pthread_t listener_thread_id; thread_local bool is_listener = false; + /** * Initializes the listener thread, pinned to core 0, and starts to listen for requests */ @@ -469,12 +470,7 @@ void req_func(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uin dispatcher_send_response(req_handle, GLOBAL_QUEUE_ERROR, strlen(GLOBAL_QUEUE_ERROR)); }*/ - if (rr_index == runtime_worker_threads_count) { - rr_index = 0; - } - - local_runqueue_add_index(rr_index, sandbox); - rr_index++; + local_runqueue_add_index(request_index_increment() % runtime_worker_threads_count, sandbox); } diff --git a/runtime/src/runtime.c b/runtime/src/runtime.c index 5b2a7f6c1..fcefcbdde 100644 --- a/runtime/src/runtime.c +++ b/runtime/src/runtime.c @@ -28,6 +28,9 @@ * Shared Process State * **************************/ +/* Count of the total number of requests we've ever received. Never decrements as it is used to dispatch requests to workers with RR */ +_Atomic uint64_t request_index; + pthread_t *runtime_worker_threads; pthread_t *runtime_listener_threads; int *runtime_worker_threads_argument; @@ -120,6 +123,7 @@ runtime_initialize(void) http_total_init(); sandbox_total_initialize(); + request_index_initialize(); sandbox_state_totals_initialize(); /* Setup Scheduler */ From 3ddbfa578166fd33c2e16b796e0a1c3da84864b4 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 6 Apr 2023 14:42:42 -0600 Subject: [PATCH 035/198] update meet_deadline_percentage.py and tests/start.sh --- runtime/tests/meet_deadline_percentage.py | 81 +++++++++++++++-------- runtime/tests/start.sh | 4 +- 2 files changed, 54 insertions(+), 31 deletions(-) diff --git a/runtime/tests/meet_deadline_percentage.py b/runtime/tests/meet_deadline_percentage.py index 82c0418c9..b831e09a7 100644 --- a/runtime/tests/meet_deadline_percentage.py +++ b/runtime/tests/meet_deadline_percentage.py @@ -27,7 +27,11 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): ### running_times = defaultdict(list) queuing_times = defaultdict(list) + thread_running_times = defaultdict(list) total_times = defaultdict(list) + thread_times = defaultdict(list) + thread_throughput = defaultdict(list) + t2_cleanup = defaultdict(list) runnable_times = defaultdict(list) blocked_times = defaultdict(list) initializing_times = defaultdict(list) @@ -55,38 +59,53 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): line = line.strip() if "meet" in line: meet_deadline += 1 - name = line.split(" ")[5] + name = line.split(" ")[7] + cleanup = line.split(" ")[9] name = name[1:] + tid = line.split(" ")[1] request_counter[name] += 1 - total_time = int(line.split(" ")[2]) + total_time = int(line.split(" ")[4]) total_time_dist[name].append(total_time) + thread_times[tid].append(total_time) if total_time > max_latency_dist[name]: max_latency_dist[name] = total_time meet_deadline_dist[name] += 1 - exe_time = int(line.split(" ")[3]) + exe_time = int(line.split(" ")[5]) running_times[name].append(exe_time); - queue_time = int(line.split(" ")[4]) + queue_time = int(line.split(" ")[6]) queuing_times[name].append(queue_time); + thread_running_times[tid].append(exe_time); + t2_cleanup[tid].append(cleanup) if "miss" in line: miss_deadline += 1 - name = line.split(" ")[5] + name = line.split(" ")[7] + cleanup = line.split(" ")[9] name = name[1:] - total_time = int(line.split(" ")[2]) + tid = line.split(" ")[1] + total_time = int(line.split(" ")[4]) if total_time > max_latency_dist[name]: max_latency_dist[name] = total_time request_counter[name] += 1 total_time_dist[name].append(total_time) + thread_times[tid].append(total_time) miss_deadline_dist[name] += 1 - exe_time = int(line.split(" ")[3]) + exe_time = line.split(" ")[5] + exe_time = int(line.split(" ")[5]) running_times[name].append(exe_time); - queue_time = int(line.split(" ")[4]) + queue_time = int(line.split(" ")[6]) queuing_times[name].append(queue_time); + thread_running_times[tid].append(exe_time); + t2_cleanup[tid].append(cleanup) #print("name:", name) if "throughput" in line: throughput = line.split(" ")[1] ### calculate the execution time #if "memory" in line or "total_time" in line or "min" in line or "miss" in line or "meet" in line or "time " in line or "scheduling count" in line or "thread id" in line: # continue + if "pthroughput" in line: + tid = line.split(" ")[2] + throughput = line.split(" ")[3] + thread_throughput[tid].append(throughput) miss_deadline_percentage = (miss_deadline * 100) / (miss_deadline + meet_deadline) print("meet deadline num:", meet_deadline) @@ -94,23 +113,6 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): print("total requests:", meet_deadline + miss_deadline) print("miss deadline percentage:", miss_deadline_percentage) print("throughput:", throughput) -# func_name_dict = { -# "cifar10_1": "105k-2", -# "cifar10_2": "305k-2", -# "cifar10_3": "5k-2", -# "cifar10_4": "545k-2", -# "cifar10_5": "105k-4", -# "cifar10_6": "305k-4", -# "cifar10_7": "5k-4", -# "cifar10_8": "545k-4", -# "cifar10_9": "105k-8", -# "cifar10_10": "305k-8", -# "cifar10_11": "5k-8", -# "cifar10_12": "545k-8", -# "resize": "resize", -# "fibonacci": "fibonacci", -# "resize3": "resize3" -# } for key,value in request_counter.items(): print(key, ":", str(value), "proportion:", (100*value)/(meet_deadline + miss_deadline)) @@ -132,19 +134,40 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): for key,value in running_times.items(): #print("function times:", func_name_with_id[key], np.median(total_times[key]), np.median(running_times[key]), np.median(queuing_times[key]), np.median(runnable_times[key]), np.median(blocked_times[key]), np.median(initializing_times[key])) - print("function :", key, "avg total:", np.median(total_time_dist[key]), "exec:", np.median(running_times[key]), "queue:", np.median(queuing_times[key])) - - + print("function :", key, "median total:", np.median(total_time_dist[key]), "exec:", np.median(running_times[key]), "queue:", np.median(queuing_times[key])) + print(len(value)) + print(len(queuing_times[key])) + print(len(total_time_dist[key])) js = json.dumps(total_time_dist) f = open("total_time.txt", 'w') f.write(js) f.close() - js5 = json.dumps(running_times) + js1 = json.dumps(queuing_times) + f1 = open("queuing_time.txt", 'w') + f1.write(js1) + f1.close() + + js5 = json.dumps(thread_running_times) f5 = open("running_time.txt", 'w') f5.write(js5) f5.close() + js2 = json.dumps(thread_times) + f2 = open("thread_time.txt", 'w') + f2.write(js2) + f2.close() + + js3 = json.dumps(thread_throughput) + f3 = open("thread_throughput.txt", 'w') + f3.write(js3) + f3.close() + + js4 = json.dumps(t2_cleanup) + f4 = open("cleanup.txt", 'w') + f4.write(js4) + f4.close() + if __name__ == "__main__": argv = sys.argv[1:] if len(argv) < 1: diff --git a/runtime/tests/start.sh b/runtime/tests/start.sh index 6b7781b9d..d3fbf7490 100755 --- a/runtime/tests/start.sh +++ b/runtime/tests/start.sh @@ -21,12 +21,12 @@ declare project_path="$( )" echo $project_path path=`pwd` -export SLEDGE_DISABLE_PREEMPTION=true +#export SLEDGE_DISABLE_PREEMPTION=true #export SLEDGE_SIGALRM_HANDLER=TRIAGED export SLEDGE_FIRST_WORKER_COREID=$first_worker_core_id export SLEDGE_NWORKERS=$worker_num export SLEDGE_NLISTENERS=$listener_num -#export SLEDGE_SCHEDULER=EDF +export SLEDGE_SCHEDULER=EDF export SLEDGE_SANDBOX_PERF_LOG=$path/server.log #echo $SLEDGE_SANDBOX_PERF_LOG cd $project_path/runtime/bin From a899831fed4f4118eff8fd873e876c1946c78fd7 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 12 Apr 2023 00:59:18 -0600 Subject: [PATCH 036/198] 1.Remove perf_window lock by let each worker thread maintain its own perf_windows. 2. Distribute requests based on the amount of work of each worker thread --- runtime/include/admissions_info.h | 3 +++ runtime/include/local_runqueue_minheap.h | 22 ++++++++++++++++++++++ runtime/include/perf_window.h | 22 ++++++++++++++++++++-- runtime/include/sandbox_set_as_complete.h | 2 ++ runtime/include/sandbox_types.h | 1 + runtime/include/tenant_functions.h | 19 +++++++++++++++++++ runtime/src/admissions_info.c | 9 +++++++-- runtime/src/listener_thread.c | 20 ++++++++++++++++++-- runtime/src/local_runqueue_minheap.c | 14 ++++++++++++++ runtime/src/runtime.c | 1 + runtime/src/software_interrupt.c | 6 ++++++ runtime/src/worker_thread.c | 10 ++++++++++ 12 files changed, 123 insertions(+), 6 deletions(-) diff --git a/runtime/include/admissions_info.h b/runtime/include/admissions_info.h index d2e0dfb2a..57a152fb3 100644 --- a/runtime/include/admissions_info.h +++ b/runtime/include/admissions_info.h @@ -1,4 +1,5 @@ #pragma once +#include #include "perf_window_t.h" @@ -8,8 +9,10 @@ struct admissions_info { int control_index; /* Precomputed Lookup index when perf_window is full */ uint64_t estimate; /* cycles */ uint64_t relative_deadline; /* Relative deadline in cycles. This is duplicated state */ + uint32_t uid; /* unique id to identify an admissions_info at each thread */ }; void admissions_info_initialize(struct admissions_info *admissions_info, uint8_t percentile, uint64_t expected_execution, uint64_t relative_deadline); void admissions_info_update(struct admissions_info *admissions_info, uint64_t execution_duration); +void perf_window_per_thread_update(struct admissions_info *admissions_info, uint64_t execution_duration); diff --git a/runtime/include/local_runqueue_minheap.h b/runtime/include/local_runqueue_minheap.h index e8ba9187d..20f8cdeb0 100644 --- a/runtime/include/local_runqueue_minheap.h +++ b/runtime/include/local_runqueue_minheap.h @@ -1,3 +1,25 @@ #pragma once +extern _Atomic uint64_t worker_queuing_cost[1024]; + +static inline void +worker_queuing_cost_initialize() +{ + for (int i = 0; i < 1024; i++) atomic_init(&worker_queuing_cost[i], 0); +} + +static inline void +worker_queuing_cost_increment(int index, uint64_t cost) +{ + atomic_fetch_add(&worker_queuing_cost[index], cost); +} + +static inline void +worker_queuing_cost_decrement(int index, uint64_t cost) +{ + assert(index >= 0 && index < 1024); + atomic_fetch_sub(&worker_queuing_cost[index], cost); + assert(worker_queuing_cost[index] >= 0); +} + void local_runqueue_minheap_initialize(); diff --git a/runtime/include/perf_window.h b/runtime/include/perf_window.h index 5b2b37f93..8df4b118f 100644 --- a/runtime/include/perf_window.h +++ b/runtime/include/perf_window.h @@ -36,7 +36,7 @@ perf_window_initialize(struct perf_window *perf_window) static inline void perf_window_swap(struct perf_window *perf_window, uint16_t first_by_duration_idx, uint16_t second_by_duration_idx) { - assert(lock_is_locked(&perf_window->lock)); + //assert(lock_is_locked(&perf_window->lock)); assert(perf_window != NULL); assert(first_by_duration_idx < PERF_WINDOW_CAPACITY); assert(second_by_duration_idx < PERF_WINDOW_CAPACITY); @@ -95,7 +95,7 @@ perf_window_add(struct perf_window *perf_window, uint64_t newest_execution_time) uint64_t previous_execution_time; bool check_up; - if (unlikely(!lock_is_locked(&perf_window->lock))) panic("lock not held when calling perf_window_add\n"); + //if (unlikely(!lock_is_locked(&perf_window->lock))) panic("lock not held when calling perf_window_add\n"); /* If perf window is empty, fill all elements with newest_execution_time */ if (perf_window->count == 0) { @@ -170,6 +170,24 @@ perf_window_get_percentile(struct perf_window *perf_window, uint8_t percentile, return perf_window->by_duration[idx].execution_time; } + +static inline uint64_t +perf_window_get_mean(struct perf_window *perf_window) { + assert(perf_window != NULL); + uint64_t sum = 0; + + for (int i = 0; i < PERF_WINDOW_CAPACITY; i++) { + sum += perf_window->by_duration[i].execution_time; + } + + if (perf_window->count == 0) { + printf("perf_window count is 0\n"); + return 0; + } + uint64_t mean = sum / PERF_WINDOW_CAPACITY; + return mean / runtime_processor_speed_MHz; +} + /** * Returns the total count of executions * @returns total count diff --git a/runtime/include/sandbox_set_as_complete.h b/runtime/include/sandbox_set_as_complete.h index a440a3870..59a984d68 100644 --- a/runtime/include/sandbox_set_as_complete.h +++ b/runtime/include/sandbox_set_as_complete.h @@ -49,6 +49,8 @@ sandbox_set_as_complete(struct sandbox *sandbox, sandbox_state_t last_state) /* Admissions Control Post Processing */ admissions_info_update(&sandbox->route->admissions_info, sandbox->duration_of_state[SANDBOX_RUNNING_USER] + sandbox->duration_of_state[SANDBOX_RUNNING_SYS]); + perf_window_per_thread_update(&sandbox->route->admissions_info, sandbox->duration_of_state[SANDBOX_RUNNING_USER] + + sandbox->duration_of_state[SANDBOX_RUNNING_SYS]); admissions_control_subtract(sandbox->admissions_estimate); /* Terminal State Logging for Sandbox */ diff --git a/runtime/include/sandbox_types.h b/runtime/include/sandbox_types.h index 2132e7f2c..34e9a94e3 100644 --- a/runtime/include/sandbox_types.h +++ b/runtime/include/sandbox_types.h @@ -82,4 +82,5 @@ struct sandbox { wasi_context_t *wasi_context; int context_switch_to; /* 1 means context switch to base, 2 means context swtich to next sandbox */ uint64_t ret[5]; + uint64_t estimated_cost; /* estimated execution cost */ } PAGE_ALIGNED; diff --git a/runtime/include/tenant_functions.h b/runtime/include/tenant_functions.h index ce708e4a9..ab3fa3aeb 100644 --- a/runtime/include/tenant_functions.h +++ b/runtime/include/tenant_functions.h @@ -13,6 +13,10 @@ #include "tenant_config.h" #include "priority_queue.h" #include "sandbox_functions.h" +#include "memlogging.h" + +extern thread_local struct perf_window perf_window_per_thread[1024]; +extern thread_local int worker_thread_idx; int tenant_database_add(struct tenant *tenant); struct tenant *tenant_database_find_by_name(char *name); @@ -169,3 +173,18 @@ tenant_preallocate_memory(struct tenant *tenant, void *arg1, void *arg2) { module_preallocate_memory(modules[i]); } } + +static inline void +tenant_perf_window_init(struct tenant *tenant, void *arg1, void *arg2) { + for(int i = 0; i < tenant->router.length; i++) { + tenant->router.buffer[i].admissions_info.uid = i; + perf_window_initialize(&perf_window_per_thread[i]); + } +} + +static inline void +tenat_perf_window_print_mean(struct tenant *tenant, void *arg1, void *arg2) { + for(int i = 0; i < tenant->router.length; i++) { + mem_log("tid %d admssion id %u exec mean %lu\n", worker_thread_idx, i, perf_window_get_mean(&perf_window_per_thread[i])); + } +} diff --git a/runtime/src/admissions_info.c b/runtime/src/admissions_info.c index 540a24d05..76f3be164 100644 --- a/runtime/src/admissions_info.c +++ b/runtime/src/admissions_info.c @@ -3,6 +3,7 @@ #include "debuglog.h" #include "perf_window.h" +extern thread_local struct perf_window perf_window_per_thread[1024]; /** * Initializes perf window * @param admissions_info @@ -11,7 +12,7 @@ void admissions_info_initialize(struct admissions_info *admissions_info, uint8_t percentile, uint64_t expected_execution, uint64_t relative_deadline) { -#ifdef ADMISSIONS_CONTROL +//#ifdef ADMISSIONS_CONTROL assert(relative_deadline > 0); assert(expected_execution > 0); admissions_info->relative_deadline = relative_deadline; @@ -28,10 +29,14 @@ admissions_info_initialize(struct admissions_info *admissions_info, uint8_t perc #ifdef LOG_ADMISSIONS_CONTROL debuglog("Percentile: %u\n", admissions_info->percentile); debuglog("Control Index: %d\n", admissions_info->control_index); -#endif +//#endif #endif } +void perf_window_per_thread_update(struct admissions_info *admissions_info, uint64_t execution_duration) { + uint32_t uid = admissions_info->uid; + perf_window_add(&perf_window_per_thread[uid], execution_duration); +} /* * Adds an execution value to the perf window and calculates and caches and updated estimate diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 53ddc701a..a1beb5271 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -16,7 +16,10 @@ #include "http_session_perf_log.h" #include "sandbox_set_as_runnable.h" -struct priority_queue* worker_queues[1024]; +struct perf_window * worker_perf_windows[1024]; +struct priority_queue * worker_queues[1024]; + +extern _Atomic uint64_t worker_queuing_cost[1024]; extern uint32_t runtime_worker_threads_count; extern thread_local bool pthread_stop; extern _Atomic uint64_t request_index; @@ -470,7 +473,20 @@ void req_func(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uin dispatcher_send_response(req_handle, GLOBAL_QUEUE_ERROR, strlen(GLOBAL_QUEUE_ERROR)); }*/ - local_runqueue_add_index(request_index_increment() % runtime_worker_threads_count, sandbox); + /* Round robin to distribute requests */ + //local_runqueue_add_index(request_index_increment() % runtime_worker_threads_count, sandbox); + + /* Based on amount of work to distribute requests */ + uint64_t min_cost = UINT64_MAX; + int thread_id = 0; + for (int i = 0; i < runtime_worker_threads_count; i++) { + if (worker_queuing_cost[i] < min_cost) { + thread_id = i; + min_cost = worker_queuing_cost[i]; + } + } + + local_runqueue_add_index(thread_id, sandbox); } diff --git a/runtime/src/local_runqueue_minheap.c b/runtime/src/local_runqueue_minheap.c index 936ff0017..687818ddd 100644 --- a/runtime/src/local_runqueue_minheap.c +++ b/runtime/src/local_runqueue_minheap.c @@ -14,9 +14,13 @@ extern struct priority_queue* worker_queues[1024]; extern thread_local int worker_thread_idx; +_Atomic uint64_t worker_queuing_cost[1024]; /* index is thread id, each queue's total execution cost of queuing requests */ +extern struct perf_window * worker_perf_windows[1024]; /* index is thread id, each queue's perf windows, each queue can + have multiple perf windows */ thread_local static struct priority_queue *local_runqueue_minheap; + /** * Checks if the run queue is empty * @returns true if empty. false otherwise @@ -48,6 +52,14 @@ local_runqueue_minheap_add_index(int index, struct sandbox *sandbox) if (return_code != 0) { panic("add request to local queue failed, exit\n"); } + + uint32_t uid = sandbox->route->admissions_info.uid; + uint64_t estimated_execute_cost = perf_window_get_percentile(&worker_perf_windows[index][uid], + sandbox->route->admissions_info.percentile, + sandbox->route->admissions_info.control_index); + + worker_queuing_cost_increment(index, estimated_execute_cost); + sandbox->estimated_cost = estimated_execute_cost; } /** @@ -61,6 +73,8 @@ local_runqueue_minheap_delete(struct sandbox *sandbox) int rc = priority_queue_delete(local_runqueue_minheap, sandbox); if (rc == -1) panic("Tried to delete sandbox %lu from runqueue, but was not present\n", sandbox->id); + + worker_queuing_cost_decrement(worker_thread_idx, sandbox->estimated_cost); } /** diff --git a/runtime/src/runtime.c b/runtime/src/runtime.c index fcefcbdde..037e7897f 100644 --- a/runtime/src/runtime.c +++ b/runtime/src/runtime.c @@ -125,6 +125,7 @@ runtime_initialize(void) sandbox_total_initialize(); request_index_initialize(); sandbox_state_totals_initialize(); + worker_queuing_cost_initialize(); /* Setup Scheduler */ scheduler_initialize(); diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index 07ded3fd0..65c5d1d92 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -25,8 +25,10 @@ #include "software_interrupt.h" #include "software_interrupt_counts.h" #include "memlogging.h" +#include "tenant_functions.h" extern time_t t_start; +extern thread_local int worker_thread_idx; extern thread_local bool pthread_stop; extern thread_local bool is_listener; extern thread_local uint32_t total_local_requests; @@ -47,6 +49,10 @@ extern _Atomic uint32_t sandbox_state_totals[SANDBOX_STATE_COUNT]; /************************** * Private Static Inlines * *************************/ +void perf_window_print_mean() { + tenant_database_foreach(tenat_perf_window_print_mean, NULL, NULL); +} + /** * A POSIX signal is delivered to only one thread. diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c index 427d55a6e..39ec470bd 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c @@ -23,6 +23,9 @@ * Worker Thread State * **************************/ +extern struct perf_window * worker_perf_windows[1024]; +thread_local struct perf_window perf_window_per_thread[1024]; + extern FILE *sandbox_perf_log; thread_local bool pthread_stop = false; @@ -44,6 +47,12 @@ thread_local struct priority_queue *worker_thread_timeout_queue; void preallocate_memory() { tenant_database_foreach(tenant_preallocate_memory, NULL, NULL); } + +void perf_window_init() { + worker_perf_windows[worker_thread_idx] = perf_window_per_thread; + tenant_database_foreach(tenant_perf_window_init, NULL, NULL); +} + /** * The entry function for sandbox worker threads * Initializes thread-local state, unmasks signals, sets up epoll loop and @@ -63,6 +72,7 @@ worker_thread_main(void *argument) pthread_setschedprio(pthread_self(), -20); preallocate_memory(); + perf_window_init(); scheduler_runqueue_initialize(); From 950f89cbdeeed432c36b22f424030efa1391d07b Mon Sep 17 00:00:00 2001 From: xiaosuGW Date: Fri, 28 Apr 2023 15:31:15 -0600 Subject: [PATCH 037/198] implement new scheduling policy with binary search tree, but it has some bugs now --- runtime/include/binary_search_tree.h | 296 +++++++++++++++++++ runtime/include/current_sandbox.h | 3 + runtime/include/local_runqueue.h | 11 +- runtime/include/local_runqueue_binary_tree.h | 3 + runtime/include/runtime.h | 5 +- runtime/include/sandbox_functions.h | 14 + runtime/include/sandbox_set_as_returned.h | 3 + runtime/include/scheduler.h | 4 +- runtime/include/software_interrupt.h | 2 + runtime/src/listener_thread.c | 66 +++-- runtime/src/local_runqueue.c | 6 + runtime/src/local_runqueue_binary_tree.c | 144 +++++++++ runtime/src/main.c | 13 + runtime/src/software_interrupt.c | 24 +- runtime/src/worker_thread.c | 1 + 15 files changed, 560 insertions(+), 35 deletions(-) create mode 100644 runtime/include/binary_search_tree.h create mode 100644 runtime/include/local_runqueue_binary_tree.h create mode 100644 runtime/src/local_runqueue_binary_tree.c diff --git a/runtime/include/binary_search_tree.h b/runtime/include/binary_search_tree.h new file mode 100644 index 000000000..8fe5fb169 --- /dev/null +++ b/runtime/include/binary_search_tree.h @@ -0,0 +1,296 @@ +#include +#include +#include + +#include "lock.h" + +#define MAX_NODES 1024 // Maximum number of nodes in the pool + +typedef uint64_t (*binary_tree_get_priority_fn_t)(void *data); +typedef uint64_t (*binary_tree_get_execution_cost_fn_t)(void *data, int thread_id); + +// Definition of a binary search tree node +struct TreeNode { + struct TreeNode *left; + struct TreeNode *right; + struct TreeNode *next; // pointing to the next node + void *data; +}; + +// Definition of TreeNode memory pool +struct TreeNodePool { + struct TreeNode* head; +}; + +struct binary_tree { + struct TreeNode *root; + struct TreeNodePool nodePool; + binary_tree_get_priority_fn_t get_priority_fn; + binary_tree_get_execution_cost_fn_t get_execution_cost_fn; + lock_t lock; + bool use_lock; +}; + +// Initialize the node pool +void initNodePool(struct TreeNodePool *nodePool) { + + assert(nodePool != NULL); + + struct TreeNode *nodes = (struct TreeNode*)malloc(MAX_NODES * sizeof(struct TreeNode)); + nodePool->head = nodes; // Initialize head to the beginning of the node array + + for (int i = 0; i < MAX_NODES - 1; ++i) { + nodes[i].next = &nodes[i + 1]; // Set the next pointer of each node to the next node + nodes[i].left = NULL; + nodes[i].right = NULL; + nodes[i].data = NULL; + } + nodes[MAX_NODES - 1].next = NULL; +} + +struct binary_tree * init_binary_tree(bool use_lock, binary_tree_get_priority_fn_t get_priority_fn, + binary_tree_get_execution_cost_fn_t get_execution_cost_fn) { + + assert(get_priority_fn != NULL); + + struct binary_tree *binary_tree = (struct binary_tree *)calloc(1, sizeof(struct binary_tree)); + initNodePool(&binary_tree->nodePool); + binary_tree->root = NULL; + binary_tree->get_priority_fn = get_priority_fn; + binary_tree->get_execution_cost_fn = get_execution_cost_fn; + binary_tree->use_lock = use_lock; + + if (binary_tree->use_lock) lock_init(&binary_tree->lock); + + return binary_tree; +} + +// Get a new node from the pool +struct TreeNode* newNode(struct binary_tree *binary_tree, void *data) { + + assert(binary_tree != NULL); + + if (binary_tree->nodePool.head == NULL) { + panic("queue is full\n"); + return NULL; + } else { + // Remove a node from the head of the memory pool + struct TreeNode* new_node_t = binary_tree->nodePool.head; + binary_tree->nodePool.head = new_node_t->next; + new_node_t->next = NULL; // Reset the next pointer of the new node + new_node_t->data = data; + new_node_t->left = NULL; + new_node_t->right = NULL; + return new_node_t; + } +} +void getAvailableCapacity(struct binary_tree *binary_tree) { + + assert(binary_tree != NULL); + + int size = 0; + struct TreeNode* start = binary_tree->nodePool.head; + while(start) { + size++; + start = start->next; + } + + printf("available capacity of the queue is %d\n", size); +} +// Return a node to the pool +void deleteNode(struct binary_tree *binary_tree, struct TreeNode* node) { + + assert(binary_tree != NULL); + assert(node != NULL); + + // Insert the node back to the head of the memory pool + node->left = NULL; + node->right = NULL; + node->next = binary_tree->nodePool.head; + node->data = NULL; + binary_tree->nodePool.head = node; +} + +int findHeight(struct TreeNode *root) +{ + int lefth, righth; + if(root == NULL) + return -1; + lefth = findHeight(root->left); + righth = findHeight(root->right); + return (lefth > righth ? lefth : righth)+1; +} + +// Function to insert a value into a binary search tree +struct TreeNode* insert(struct binary_tree *binary_tree, struct TreeNode* root, void *data) { + + assert(binary_tree != NULL); + + if (root == NULL) { + return newNode(binary_tree, data); // Create a new node for an empty tree + } + + if (binary_tree->get_priority_fn(data) <= binary_tree->get_priority_fn(root->data)) { + root->left = insert(binary_tree, root->left, data); // Insert into the left subtree + } else { + root->right = insert(binary_tree, root->right, data); // Insert into the right subtree + } + return root; +} + +// Helper function to find the minimum value in a binary search tree +struct TreeNode* findMin(struct binary_tree *binary_tree, struct TreeNode *root) { + + assert(binary_tree != NULL); + + if (root == NULL) { + return NULL; + } + + lock_node_t node = {}; + lock_lock(&binary_tree->lock, &node); + while (root->left != NULL) { + root = root->left; // Keep traversing to the left until the leftmost node is reached + } + lock_unlock(&binary_tree->lock, &node); + return root; +} + +// Helper function to find the maximum value in a binary search tree +struct TreeNode* findMax(struct binary_tree *binary_tree, struct TreeNode *root) { + if (root == NULL) { + return NULL; + } + + lock_node_t node = {}; + lock_lock(&binary_tree->lock, &node); + while (root->right != NULL) { + root = root->right; // Keep traversing to the right until the rightmost node is reached + } + lock_unlock(&binary_tree->lock, &node); + return root; +} + +// Function to delete a value from a binary search tree +struct TreeNode* delete(struct binary_tree *binary_tree, struct TreeNode* root, void *data, bool *deleted) { + + assert(binary_tree != NULL); + + if (root == NULL) { + *deleted = false; + return NULL; + } + + int64_t cmp_result = binary_tree->get_priority_fn(data) - binary_tree->get_priority_fn(root->data); + if (cmp_result < 0) { + root->left = delete(binary_tree, root->left, data, deleted); + } else if (cmp_result > 0) { + root->right = delete(binary_tree, root->right, data, deleted); + } else { // cmp_result == 0 + if (root->data == data) { + if (root->left == NULL) { + struct TreeNode* temp = root->right; + deleteNode(binary_tree, root); + *deleted = true; + return temp; + } else if (root->right == NULL) { + struct TreeNode* temp = root->left; + deleteNode(binary_tree, root); + *deleted = true; + return temp; + } else { + struct TreeNode* successor = root->right; + while (successor->left != NULL) { + successor = successor->left; + } + root->data = successor->data; + root->right = delete(binary_tree, root->right, successor->data, deleted); + return root; + } + } else { + // Continue searching for the node with the same data pointer + if (root->left != NULL) { + root->left = delete(binary_tree, root->left, data, deleted); + } + + if (*deleted == false && root->right != NULL) { + root->right = delete(binary_tree, root->right, data, deleted); + } + } + } + return root; + +} + +// Function to find a value in a binary search tree (non-recursive) +/*struct TreeNode* find(struct TreeNode* root, int val) { + while (root != NULL) { + if (val == root->val) { + return root; // Return the node if value is found + } else if (val < root->val) { + root = root->left; // Move to left subtree if value is less + } else { + root = root->right; // Move to right subtree if value is greater + } + } + return NULL; // Return NULL if value is not found or if the tree is empty +}*/ + +bool is_empty(struct binary_tree *binary_tree) { + assert(binary_tree != NULL); + + return binary_tree->root == NULL; +} +void inorder(struct binary_tree *binary_tree, struct TreeNode* root) +{ + assert(binary_tree != NULL); + + if(root == NULL) + return; + inorder(binary_tree, root->left); + printf("%lu ", binary_tree->get_priority_fn(root->data)); + inorder(binary_tree, root->right); +} + +struct TreeNode* findMaxValueLessThan(struct binary_tree *binary_tree, struct TreeNode* root, void *target, uint64_t *sum, int thread_id) { + + assert(binary_tree != NULL); + + if (root == NULL) { + *sum = 0; + return NULL; // Base case: empty node, return NULL + } + + struct TreeNode* maxNode = NULL; // Initialize the node containing the maximum value to NULL + + // In-order traversal of the binary tree + struct TreeNode* leftMaxNode = findMaxValueLessThan(binary_tree, root->left, target, sum, thread_id); // Traverse left subtree + if (binary_tree->get_priority_fn(root->data) <= binary_tree->get_priority_fn(target)) { + *sum += binary_tree->get_execution_cost_fn(root->data, thread_id); // Add the current node's value to the sum + maxNode = root; // Update the maximum node + } + struct TreeNode* rightMaxNode = findMaxValueLessThan(binary_tree, root->right, target, sum, thread_id); // Traverse right subtree + + // Update the maximum node with the maximum node from left and right subtrees + if (leftMaxNode != NULL && (maxNode == NULL || binary_tree->get_priority_fn(leftMaxNode->data) > binary_tree->get_priority_fn(maxNode->data))) { + maxNode = leftMaxNode; + } + if (rightMaxNode != NULL && (maxNode == NULL || binary_tree->get_priority_fn(rightMaxNode->data) > binary_tree->get_priority_fn(maxNode->data))) { + maxNode = rightMaxNode; + } + + return maxNode; +} + +struct TreeNode* makeEmpty(struct binary_tree *binary_tree, struct TreeNode* root) +{ + assert(binary_tree != NULL); + + if(root != NULL) { + makeEmpty(binary_tree, root->left); + makeEmpty(binary_tree, root->right); + deleteNode(binary_tree, root); + } + return NULL; +} + diff --git a/runtime/include/current_sandbox.h b/runtime/include/current_sandbox.h index fa84dff94..3b360f3ae 100644 --- a/runtime/include/current_sandbox.h +++ b/runtime/include/current_sandbox.h @@ -7,6 +7,7 @@ /* current sandbox that is active.. */ extern thread_local struct sandbox *worker_thread_current_sandbox; +extern struct sandbox* current_sandboxes[1024]; void current_sandbox_start(void); @@ -47,6 +48,7 @@ current_sandbox_set(struct sandbox *sandbox) .wasi_context = NULL, }; worker_thread_current_sandbox = NULL; + current_sandboxes[worker_thread_idx] = NULL; runtime_worker_threads_deadline[worker_thread_idx] = UINT64_MAX; } else { sledge_abi__current_wasm_module_instance.wasi_context = sandbox->wasi_context; @@ -56,6 +58,7 @@ current_sandbox_set(struct sandbox *sandbox) wasm_globals_update_if_used(&sandbox->globals, 0, &sledge_abi__current_wasm_module_instance.abi.wasmg_0); worker_thread_current_sandbox = sandbox; + current_sandboxes[worker_thread_idx] = sandbox; runtime_worker_threads_deadline[worker_thread_idx] = sandbox->absolute_deadline; } } diff --git a/runtime/include/local_runqueue.h b/runtime/include/local_runqueue.h index d8def7db5..ba986f2c6 100644 --- a/runtime/include/local_runqueue.h +++ b/runtime/include/local_runqueue.h @@ -7,20 +7,23 @@ /* Returns pointer back if successful, null otherwise */ typedef void (*local_runqueue_add_fn_t)(struct sandbox *); typedef void (*local_runqueue_add_fn_t_idx)(int index, struct sandbox *); +typedef uint64_t (*local_runqueue_try_add_fn_t_idx)(int index, struct sandbox *, bool *need_interrupt); typedef bool (*local_runqueue_is_empty_fn_t)(void); typedef void (*local_runqueue_delete_fn_t)(struct sandbox *sandbox); typedef struct sandbox *(*local_runqueue_get_next_fn_t)(); struct local_runqueue_config { - local_runqueue_add_fn_t add_fn; + local_runqueue_add_fn_t add_fn; local_runqueue_add_fn_t_idx add_fn_idx; - local_runqueue_is_empty_fn_t is_empty_fn; - local_runqueue_delete_fn_t delete_fn; - local_runqueue_get_next_fn_t get_next_fn; + local_runqueue_try_add_fn_t_idx try_add_fn_idx; + local_runqueue_is_empty_fn_t is_empty_fn; + local_runqueue_delete_fn_t delete_fn; + local_runqueue_get_next_fn_t get_next_fn; }; void local_runqueue_add(struct sandbox *); void local_runqueue_add_index(int index, struct sandbox *); +uint64_t local_runqueue_try_add_index(int index, struct sandbox *, bool *need_interrupt); void local_runqueue_delete(struct sandbox *); bool local_runqueue_is_empty(); struct sandbox *local_runqueue_get_next(); diff --git a/runtime/include/local_runqueue_binary_tree.h b/runtime/include/local_runqueue_binary_tree.h new file mode 100644 index 000000000..b4970a386 --- /dev/null +++ b/runtime/include/local_runqueue_binary_tree.h @@ -0,0 +1,3 @@ +#pragma once + +void local_runqueue_binary_tree_initialize(); diff --git a/runtime/include/runtime.h b/runtime/include/runtime.h index a29a3e174..4437596ed 100644 --- a/runtime/include/runtime.h +++ b/runtime/include/runtime.h @@ -72,13 +72,12 @@ runtime_print_sigalrm_handler(enum RUNTIME_SIGALRM_HANDLER variant) } } -inline void +static inline void request_index_initialize() { atomic_init(&request_index, 0); } - -inline uint64_t +static inline uint64_t request_index_increment() { return atomic_fetch_add(&request_index, 1); diff --git a/runtime/include/sandbox_functions.h b/runtime/include/sandbox_functions.h index 315fc5328..7721bbdc1 100644 --- a/runtime/include/sandbox_functions.h +++ b/runtime/include/sandbox_functions.h @@ -12,6 +12,7 @@ * Public API * **************************/ +extern struct perf_window * worker_perf_windows[1024]; struct sandbox *sandbox_alloc(struct module *module, struct http_session *session, struct route *route, struct tenant *tenant, uint64_t admissions_estimate, void *req_handle, uint8_t rpc_id); @@ -49,10 +50,23 @@ sandbox_get_module(struct sandbox *sandbox) static inline uint64_t sandbox_get_priority(void *element) { + assert(element != NULL); struct sandbox *sandbox = (struct sandbox *)element; return sandbox->absolute_deadline; } +static inline uint64_t +sandbox_get_execution_cost(void *element, int thread_id) +{ + assert(element != NULL); + struct sandbox *sandbox = (struct sandbox *)element; + uint32_t uid = sandbox->route->admissions_info.uid; + return perf_window_get_percentile(&worker_perf_windows[thread_id][uid], + sandbox->route->admissions_info.percentile, + sandbox->route->admissions_info.control_index); + + +} static inline void sandbox_process_scheduler_updates(struct sandbox *sandbox) { diff --git a/runtime/include/sandbox_set_as_returned.h b/runtime/include/sandbox_set_as_returned.h index 589b052bb..c5a3f4a4a 100644 --- a/runtime/include/sandbox_set_as_returned.h +++ b/runtime/include/sandbox_set_as_returned.h @@ -14,6 +14,8 @@ #include "sandbox_state_transition.h" #include "sandbox_types.h" +extern struct sandbox* current_sandboxes[1024]; +extern thread_local int worker_thread_idx; /** * Transitions a sandbox to the SANDBOX_RETURNED state. * This occurs when a sandbox is executing and runs to completion. @@ -33,6 +35,7 @@ sandbox_set_as_returned(struct sandbox *sandbox, sandbox_state_t last_state) switch (last_state) { case SANDBOX_RUNNING_SYS: { local_runqueue_delete(sandbox); + current_sandboxes[worker_thread_idx] = NULL; sandbox_free_linear_memory(sandbox); break; } diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index 6d69939f8..fe0e42da7 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -11,6 +11,7 @@ #include "global_request_scheduler_mtds.h" #include "local_runqueue.h" #include "local_runqueue_minheap.h" +#include "local_runqueue_binary_tree.h" #include "local_runqueue_list.h" #include "local_cleanup_queue.h" #include "local_runqueue_mtds.h" @@ -204,7 +205,8 @@ scheduler_runqueue_initialize() local_runqueue_mtds_initialize(); break; case SCHEDULER_EDF: - local_runqueue_minheap_initialize(); + //local_runqueue_minheap_initialize(); + local_runqueue_binary_tree_initialize(); break; case SCHEDULER_FIFO: local_runqueue_list_initialize(); diff --git a/runtime/include/software_interrupt.h b/runtime/include/software_interrupt.h index 87d3bb27b..319f1e5b6 100644 --- a/runtime/include/software_interrupt.h +++ b/runtime/include/software_interrupt.h @@ -96,3 +96,5 @@ void software_interrupt_arm_timer(void); void software_interrupt_cleanup(void); void software_interrupt_disarm_timer(void); void software_interrupt_initialize(void); +bool sandbox_is_preemptable(void *sandbox); +void preempt_worker(int thread_id); diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index a1beb5271..fd9eba297 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -18,11 +18,17 @@ struct perf_window * worker_perf_windows[1024]; struct priority_queue * worker_queues[1024]; +struct binary_tree * worker_binary_trees[1024]; extern _Atomic uint64_t worker_queuing_cost[1024]; +//struct sandbox *urgent_request[1024] = { NULL }; extern uint32_t runtime_worker_threads_count; extern thread_local bool pthread_stop; extern _Atomic uint64_t request_index; +extern uint32_t runtime_worker_group_size; + +thread_local uint32_t worker_start_id; +thread_local uint32_t worker_end_id; time_t t_start; extern bool first_request_comming; @@ -466,27 +472,45 @@ void req_func(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uin memcpy(sandbox->rpc_request_body, msg, size); sandbox->rpc_request_body_size = size; - /* If the global request scheduler is full, return a 429 to the client */ - /*if (unlikely(global_request_scheduler_add(sandbox) == NULL)) { - debuglog("Failed to add sandbox to global queue\n"); - sandbox_free(sandbox); - dispatcher_send_response(req_handle, GLOBAL_QUEUE_ERROR, strlen(GLOBAL_QUEUE_ERROR)); - }*/ - - /* Round robin to distribute requests */ - //local_runqueue_add_index(request_index_increment() % runtime_worker_threads_count, sandbox); - - /* Based on amount of work to distribute requests */ - uint64_t min_cost = UINT64_MAX; + uint64_t min_serving_time = UINT64_MAX; int thread_id = 0; - for (int i = 0; i < runtime_worker_threads_count; i++) { - if (worker_queuing_cost[i] < min_cost) { - thread_id = i; - min_cost = worker_queuing_cost[i]; - } + int candidate_thread_id = -1; + + for (uint32_t i = worker_start_id; i < worker_end_id; i++) { + bool need_interrupt; + uint64_t serving_time = local_runqueue_try_add_index(i, sandbox, &need_interrupt); + /* The local queue is empty, can be served this request immediately without interrupting + * current one + */ + if (serving_time == 0 && need_interrupt == false) { + printf("case 1\n"); + local_runqueue_add_index(i, sandbox); + return; + } else if (serving_time == 0 && need_interrupt == true) {//The worker can serve the request immediately + // by interrupting the current one + /* We already have a candidate thread, continue to find a + * better thread without needing interrupt + */ + if (candidate_thread_id != -1) { + continue; + } else { + candidate_thread_id = i; + } + } else if (min_serving_time > serving_time) { + min_serving_time = serving_time; + thread_id = i; + } } - - local_runqueue_add_index(thread_id, sandbox); + + if (candidate_thread_id != -1) { + printf("case 2\n"); + //urgent_request[candidate_thread_id] = sandbox; + local_runqueue_add_index(candidate_thread_id, sandbox); + preempt_worker(candidate_thread_id); + } else { + printf("case 3\n"); + local_runqueue_add_index(thread_id, sandbox); + } } @@ -513,6 +537,10 @@ listener_thread_main(void *dummy) /* Index was passed via argument */ dispatcher_thread_idx = *(int *)dummy; + /* calucate the worker start and end id for this listener */ + worker_start_id = dispatcher_thread_idx * runtime_worker_group_size; + worker_end_id = worker_start_id + runtime_worker_group_size; + struct epoll_event epoll_events[RUNTIME_MAX_EPOLL_EVENTS]; metrics_server_init(); diff --git a/runtime/src/local_runqueue.c b/runtime/src/local_runqueue.c index 1e4fd8a8a..73dce85e3 100644 --- a/runtime/src/local_runqueue.c +++ b/runtime/src/local_runqueue.c @@ -44,6 +44,12 @@ local_runqueue_add_index(int index, struct sandbox *sandbox) return local_runqueue.add_fn_idx(index, sandbox); } +uint64_t +local_runqueue_try_add_index(int index, struct sandbox *sandbox, bool *need_interrupt) +{ + assert(local_runqueue.try_add_fn_idx != NULL); + return local_runqueue.try_add_fn_idx(index, sandbox, need_interrupt); +} /** * Delete a sandbox from the run queue * @param sandbox to delete diff --git a/runtime/src/local_runqueue_binary_tree.c b/runtime/src/local_runqueue_binary_tree.c new file mode 100644 index 000000000..b3cb0527a --- /dev/null +++ b/runtime/src/local_runqueue_binary_tree.c @@ -0,0 +1,144 @@ +#include +#include + +#include "software_interrupt.h" +#include "arch/context.h" +#include "current_sandbox.h" +#include "debuglog.h" +#include "global_request_scheduler.h" +#include "local_runqueue.h" +#include "local_runqueue_binary_tree.h" +#include "panic.h" +#include "binary_search_tree.h" +#include "sandbox_functions.h" +#include "runtime.h" + +extern thread_local int worker_thread_idx; +extern struct perf_window * worker_perf_windows[1024]; /* index is thread id, each queue's perf windows, each queue can + have multiple perf windows */ +extern struct sandbox* current_sandboxes[1024]; +extern struct binary_tree *worker_binary_trees[1024]; +thread_local static struct binary_tree *local_runqueue_binary_tree = NULL; + + +/** + * Checks if the run queue is empty + * @returns true if empty. false otherwise + */ +bool +local_runqueue_binary_tree_is_empty() +{ + assert(local_runqueue_binary_tree != NULL); + + return is_empty(local_runqueue_binary_tree); +} + +/** + * Adds a sandbox to the run queue + * @param sandbox + * @returns pointer to sandbox added + */ +void +local_runqueue_binary_tree_add(struct sandbox *sandbox) +{ + lock_node_t node_lock = {}; + lock_lock(&local_runqueue_binary_tree->lock, &node_lock); + local_runqueue_binary_tree->root = insert(local_runqueue_binary_tree, local_runqueue_binary_tree->root, sandbox); + lock_unlock(&local_runqueue_binary_tree->lock, &node_lock); +} + +void +local_runqueue_binary_tree_add_index(int index, struct sandbox *sandbox) +{ + struct binary_tree *binary_tree = worker_binary_trees[index]; + lock_node_t node_lock = {}; + lock_lock(&binary_tree->lock, &node_lock); + binary_tree->root = insert(binary_tree, binary_tree->root, sandbox); + lock_unlock(&binary_tree->lock, &node_lock); +} + +/** + * Deletes a sandbox from the runqueue + * @param sandbox to delete + */ +static void +local_runqueue_binary_tree_delete(struct sandbox *sandbox) +{ + assert(sandbox != NULL); + + lock_node_t node_lock = {}; + lock_lock(&local_runqueue_binary_tree->lock, &node_lock); + bool deleted = false; + local_runqueue_binary_tree->root = delete(local_runqueue_binary_tree, local_runqueue_binary_tree->root, sandbox, &deleted); + lock_unlock(&local_runqueue_binary_tree->lock, &node_lock); + if (deleted == false) panic("Tried to delete sandbox %lu from runqueue, but was not present\n", sandbox->id); +} + +/** + * This function determines the next sandbox to run. + * This is the head of the local runqueue + * + * Execute the sandbox at the head of the thread local runqueue + * @return the sandbox to execute or NULL if none are available + */ +struct sandbox * +local_runqueue_binary_tree_get_next() +{ + /* Get the minimum deadline of the sandbox of the local request queue */ + struct TreeNode *node = findMin(local_runqueue_binary_tree, local_runqueue_binary_tree->root); + if (node != NULL) { + return node->data; + } else { + return NULL; + } +} + +/** + * Try but not real add a item to the local runqueue. + * @param index The worker thread id + * @param sandbox Try to add + * @returns The waiting serving time for this sandbox + */ +uint64_t +local_runqueue_binary_tree_try_add_index(int index, struct sandbox *sandbox, bool *need_interrupt) +{ + struct binary_tree *binary_tree = worker_binary_trees[index]; + if (is_empty(binary_tree)) { + *need_interrupt = false; + return 0; + } else if (current_sandboxes[index] != NULL && sandbox_is_preemptable(current_sandboxes[index]) == true && + sandbox_get_priority(sandbox) < sandbox_get_priority(current_sandboxes[index])) { + *need_interrupt = true; + return 0; + } else { + need_interrupt = false; + uint64_t waiting_serving_time = 0; + lock_node_t node_lock = {}; + lock_lock(&binary_tree->lock, &node_lock); + struct TreeNode* node = findMaxValueLessThan(binary_tree, binary_tree->root, sandbox, &waiting_serving_time, index); + lock_unlock(&binary_tree->lock, &node_lock); + return waiting_serving_time; + } + +} + +/** + * Registers the PS variant with the polymorphic interface + */ +void +local_runqueue_binary_tree_initialize() +{ + /* Initialize local state */ + local_runqueue_binary_tree = init_binary_tree(true, sandbox_get_priority, sandbox_get_execution_cost); + + worker_binary_trees[worker_thread_idx] = local_runqueue_binary_tree; + /* Register Function Pointers for Abstract Scheduling API */ + struct local_runqueue_config config = { .add_fn = local_runqueue_binary_tree_add, + .add_fn_idx = local_runqueue_binary_tree_add_index, + .try_add_fn_idx = local_runqueue_binary_tree_try_add_index, + .is_empty_fn = local_runqueue_binary_tree_is_empty, + .delete_fn = local_runqueue_binary_tree_delete, + .get_next_fn = local_runqueue_binary_tree_get_next }; + + local_runqueue_initialize(&config); +} diff --git a/runtime/src/main.c b/runtime/src/main.c index 9a5a6ecc4..7811bb217 100644 --- a/runtime/src/main.c +++ b/runtime/src/main.c @@ -40,6 +40,8 @@ uint32_t runtime_listener_threads_count = 0; uint32_t max_possible_workers = 0; bool first_request_comming = false; +uint32_t runtime_worker_group_size = 1; + enum RUNTIME_SIGALRM_HANDLER runtime_sigalrm_handler = RUNTIME_SIGALRM_HANDLER_BROADCAST; bool runtime_preemption_enabled = true; @@ -154,6 +156,16 @@ runtime_get_processor_speed_MHz(void) panic("Failed to detect processor frequency"); } +static inline void +runtime_get_worker_group_size() { + char *worker_group_size_raw = getenv("SLEDGE_WORKER_GROUP_SIZE"); + if (worker_group_size_raw != NULL) { + runtime_worker_group_size = atoi(worker_group_size_raw); + assert(runtime_listener_threads_count * runtime_worker_group_size == runtime_worker_threads_count); + } else { + printf("Not specify worker group size, default group size is 1\n"); + } +} /** * Controls the behavior of the debuglog macro defined in types.h * If LOG_TO_FILE is defined, close stdin, stdout, stderr, and debuglog writes to a logfile named awesome.log. @@ -549,6 +561,7 @@ main(int argc, char **argv) software_interrupt_arm_timer(); listener_threads_initialize(); + runtime_get_worker_group_size(); runtime_boot_timestamp = __getcycles(); diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index 65c5d1d92..069338f0d 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -27,6 +27,7 @@ #include "memlogging.h" #include "tenant_functions.h" +extern struct sandbox* current_sandboxes[1024]; extern time_t t_start; extern thread_local int worker_thread_idx; extern thread_local bool pthread_stop; @@ -53,7 +54,6 @@ void perf_window_print_mean() { tenant_database_foreach(tenat_perf_window_print_mean, NULL, NULL); } - /** * A POSIX signal is delivered to only one thread. * This function broadcasts the sigalarm signal to all other worker threads @@ -126,13 +126,24 @@ worker_thread_is_running_cooperative_scheduler(void) } -static inline bool +bool current_sandbox_is_preemptable() { struct sandbox *sandbox = current_sandbox_get(); return sandbox != NULL && sandbox->state == SANDBOX_RUNNING_USER; } +bool +sandbox_is_preemptable(void *sandbox) { + return sandbox != NULL && ((struct sandbox *)sandbox)->state == SANDBOX_RUNNING_USER; +} + +void preempt_worker(int thread_id) { + if (current_sandbox_is_preemptable()) { + pthread_kill(runtime_worker_threads[thread_id], SIGALRM); + } +} + /** * The handler function for Software Interrupts (signals) * SIGALRM is executed periodically by an interval timer, causing preemption of the current sandbox @@ -156,7 +167,7 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void switch (signal_type) { case SIGALRM: { - assert(runtime_preemption_enabled); + //assert(runtime_preemption_enabled); if (worker_thread_is_running_cooperative_scheduler()) { /* There is no benefit to deferring SIGALRMs that occur when we are already in the cooperative @@ -165,7 +176,6 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void /* Global tenant promotions */ global_timeout_queue_process_promotions(); } - propagate_sigalrm(signal_info); } else if (current_sandbox_is_preemptable()) { /* Preemptable, so run scheduler. The scheduler handles outgoing state changes */ sandbox_interrupt(current_sandbox); @@ -173,7 +183,6 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void /* Global tenant promotions */ global_timeout_queue_process_promotions(); } - propagate_sigalrm(signal_info); scheduler_preemptive_sched(interrupted_context); } else { /* We transition the sandbox to an interrupted state to exclude time propagating signals and @@ -182,7 +191,6 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void /* Global tenant promotions */ global_timeout_queue_process_promotions(); } - propagate_sigalrm(signal_info); atomic_fetch_add(&deferred_sigalrm, 1); } @@ -241,8 +249,8 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void double seconds = difftime(t_end, t_start); double throughput = atomic_load(&sandbox_state_totals[SANDBOX_COMPLETE]) / seconds; uint32_t total_sandboxes_error = atomic_load(&sandbox_state_totals[SANDBOX_ERROR]); - mem_log("throughput %f error request %u complete requests %u total request %u total_local_requests %u\n", - throughput, total_sandboxes_error, atomic_load(&sandbox_state_totals[SANDBOX_COMPLETE]), + mem_log("throughput %f tid(%d) error request %u complete requests %u total request %u total_local_requests %u\n", + throughput, worker_thread_idx, total_sandboxes_error, atomic_load(&sandbox_state_totals[SANDBOX_COMPLETE]), atomic_load(&sandbox_state_totals[SANDBOX_ALLOCATED]), total_local_requests); dump_log_to_file(); pthread_stop = true; diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c index 39ec470bd..2db745bf7 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c @@ -25,6 +25,7 @@ extern struct perf_window * worker_perf_windows[1024]; thread_local struct perf_window perf_window_per_thread[1024]; +struct sandbox* current_sandboxes[1024] = { NULL }; extern FILE *sandbox_perf_log; thread_local bool pthread_stop = false; From dc121be82bf8266a4f9b0414d00ac5e677d2ece0 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 28 Apr 2023 17:21:58 -0600 Subject: [PATCH 038/198] fix previous submit bug: calculating the total waiting serving time is wrong --- runtime/include/binary_search_tree.h | 1 - runtime/src/listener_thread.c | 4 +-- runtime/src/main.c | 38 +++++++++++++++------------- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/runtime/include/binary_search_tree.h b/runtime/include/binary_search_tree.h index 8fe5fb169..889b3bbff 100644 --- a/runtime/include/binary_search_tree.h +++ b/runtime/include/binary_search_tree.h @@ -257,7 +257,6 @@ struct TreeNode* findMaxValueLessThan(struct binary_tree *binary_tree, struct Tr assert(binary_tree != NULL); if (root == NULL) { - *sum = 0; return NULL; // Base case: empty node, return NULL } diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index fd9eba297..4db677953 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -540,7 +540,8 @@ listener_thread_main(void *dummy) /* calucate the worker start and end id for this listener */ worker_start_id = dispatcher_thread_idx * runtime_worker_group_size; worker_end_id = worker_start_id + runtime_worker_group_size; - + printf("listener %d worker_start_id %d worker_end_id %d\n", dispatcher_thread_idx, worker_start_id, worker_end_id - 1); + struct epoll_event epoll_events[RUNTIME_MAX_EPOLL_EVENTS]; metrics_server_init(); @@ -550,7 +551,6 @@ listener_thread_main(void *dummy) // runtime_set_pthread_prio(pthread_self(), 2); pthread_setschedprio(pthread_self(), -20); - printf("dispatcher_thread_idx is %d\n", dispatcher_thread_idx); erpc_start(NULL, dispatcher_thread_idx, NULL, 0); while (!pthread_stop) { diff --git a/runtime/src/main.c b/runtime/src/main.c index 7811bb217..aeb0aa944 100644 --- a/runtime/src/main.c +++ b/runtime/src/main.c @@ -156,6 +156,24 @@ runtime_get_processor_speed_MHz(void) panic("Failed to detect processor frequency"); } +static inline void +runtime_get_listener_count() { + /* Number of Listener */ + char *listener_count_raw = getenv("SLEDGE_NLISTENERS"); + if (listener_count_raw != NULL) { + int listener_count = atoi(listener_count_raw); + int max_possible_listeners = max_possible_workers - runtime_worker_threads_count; + + if (listener_count <= 0 || listener_count > max_possible_listeners) { + panic("Invalid Lisenter Count. Was %d. Must be {1..%d}\n", listener_count, max_possible_listeners); + } + + runtime_listener_threads_count = listener_count; + } else { + runtime_listener_threads_count = 1; + } +} + static inline void runtime_get_worker_group_size() { char *worker_group_size_raw = getenv("SLEDGE_WORKER_GROUP_SIZE"); @@ -480,21 +498,6 @@ load_file_into_buffer(const char *file_name, char **file_buffer) } void listener_threads_initialize() { - /* Number of Listener */ - char *listener_count_raw = getenv("SLEDGE_NLISTENERS"); - if (listener_count_raw != NULL) { - int listener_count = atoi(listener_count_raw); - int max_possible_listeners = max_possible_workers - runtime_worker_threads_count; - - if (listener_count <= 0 || listener_count > max_possible_listeners) { - panic("Invalid Lisenter Count. Was %d. Must be {1..%d}\n", listener_count, max_possible_listeners); - } - - runtime_listener_threads_count = listener_count; - } else { - runtime_listener_threads_count = 1; - } - printf("Starting %d listener thread(s)\n", runtime_listener_threads_count); for (int i = 0; i < runtime_listener_threads_count; i++) { listener_thread_initialize(i); @@ -559,9 +562,10 @@ main(int argc, char **argv) runtime_start_runtime_worker_threads(); software_interrupt_arm_timer(); - - listener_threads_initialize(); + + runtime_get_listener_count(); runtime_get_worker_group_size(); + listener_threads_initialize(); runtime_boot_timestamp = __getcycles(); From 8e4d09ae087838273c3a2d8532609db9dbe6f211 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 28 Apr 2023 17:25:55 -0600 Subject: [PATCH 039/198] remove debug log --- runtime/src/listener_thread.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 4db677953..31f51ace7 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -483,7 +483,6 @@ void req_func(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uin * current one */ if (serving_time == 0 && need_interrupt == false) { - printf("case 1\n"); local_runqueue_add_index(i, sandbox); return; } else if (serving_time == 0 && need_interrupt == true) {//The worker can serve the request immediately @@ -503,12 +502,10 @@ void req_func(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uin } if (candidate_thread_id != -1) { - printf("case 2\n"); //urgent_request[candidate_thread_id] = sandbox; local_runqueue_add_index(candidate_thread_id, sandbox); preempt_worker(candidate_thread_id); } else { - printf("case 3\n"); local_runqueue_add_index(thread_id, sandbox); } } From 71e3eb09f94bc58328aad78d9faa1adcd1e0646d Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 12 May 2023 23:51:15 -0600 Subject: [PATCH 040/198] fix bug: worker thread cannot receive sigalarm signal --- runtime/src/software_interrupt.c | 12 ++++++------ runtime/src/worker_thread.c | 6 ++---- runtime/tests/fib.json | 8 ++++---- runtime/tests/start.sh | 3 ++- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index 069338f0d..d3ae93cfc 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -27,6 +27,7 @@ #include "memlogging.h" #include "tenant_functions.h" +thread_local uint32_t interrupts = 0; extern struct sandbox* current_sandboxes[1024]; extern time_t t_start; extern thread_local int worker_thread_idx; @@ -139,9 +140,7 @@ sandbox_is_preemptable(void *sandbox) { } void preempt_worker(int thread_id) { - if (current_sandbox_is_preemptable()) { - pthread_kill(runtime_worker_threads[thread_id], SIGALRM); - } + pthread_kill(runtime_worker_threads[thread_id], SIGALRM); } /** @@ -183,6 +182,7 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void /* Global tenant promotions */ global_timeout_queue_process_promotions(); } + interrupts++; scheduler_preemptive_sched(interrupted_context); } else { /* We transition the sandbox to an interrupted state to exclude time propagating signals and @@ -197,7 +197,7 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void break; } case SIGUSR1: { - assert(runtime_preemption_enabled); + //assert(runtime_preemption_enabled); assert(current_sandbox); assert(current_sandbox->state == SANDBOX_PREEMPTED); assert(current_sandbox->ctxt.variant == ARCH_CONTEXT_VARIANT_SLOW); @@ -249,9 +249,9 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void double seconds = difftime(t_end, t_start); double throughput = atomic_load(&sandbox_state_totals[SANDBOX_COMPLETE]) / seconds; uint32_t total_sandboxes_error = atomic_load(&sandbox_state_totals[SANDBOX_ERROR]); - mem_log("throughput %f tid(%d) error request %u complete requests %u total request %u total_local_requests %u\n", + mem_log("throughput %f tid(%d) error request %u complete requests %u total request %u total_local_requests %u interrupts %u\n", throughput, worker_thread_idx, total_sandboxes_error, atomic_load(&sandbox_state_totals[SANDBOX_COMPLETE]), - atomic_load(&sandbox_state_totals[SANDBOX_ALLOCATED]), total_local_requests); + atomic_load(&sandbox_state_totals[SANDBOX_ALLOCATED]), total_local_requests, interrupts); dump_log_to_file(); pthread_stop = true; break; diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c index 2db745bf7..4ede81435 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c @@ -95,10 +95,8 @@ worker_thread_main(void *argument) software_interrupt_unmask_signal(SIGINT); /* Unmask signals, unless the runtime has disabled preemption */ - if (runtime_preemption_enabled) { - software_interrupt_unmask_signal(SIGALRM); - software_interrupt_unmask_signal(SIGUSR1); - } + software_interrupt_unmask_signal(SIGALRM); + software_interrupt_unmask_signal(SIGUSR1); scheduler_idle_loop(); diff --git a/runtime/tests/fib.json b/runtime/tests/fib.json index b43aa5734..cbccc6118 100644 --- a/runtime/tests/fib.json +++ b/runtime/tests/fib.json @@ -10,8 +10,8 @@ "request-type": 1, "path": "fibonacci.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 4000, - "relative-deadline-us": 16000, + "expected-execution-us": 6, + "relative-deadline-us": 60, "http-resp-content-type": "text/plain" }, { @@ -19,8 +19,8 @@ "request-type": 2, "path": "fibonacci.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 4000, - "relative-deadline-us": 16000, + "expected-execution-us": 785, + "relative-deadline-us": 7850, "http-resp-content-type": "text/plain" } ] diff --git a/runtime/tests/start.sh b/runtime/tests/start.sh index d3fbf7490..56005ab99 100755 --- a/runtime/tests/start.sh +++ b/runtime/tests/start.sh @@ -21,11 +21,12 @@ declare project_path="$( )" echo $project_path path=`pwd` -#export SLEDGE_DISABLE_PREEMPTION=true +export SLEDGE_DISABLE_PREEMPTION=true #export SLEDGE_SIGALRM_HANDLER=TRIAGED export SLEDGE_FIRST_WORKER_COREID=$first_worker_core_id export SLEDGE_NWORKERS=$worker_num export SLEDGE_NLISTENERS=$listener_num +export SLEDGE_WORKER_GROUP_SIZE=3 export SLEDGE_SCHEDULER=EDF export SLEDGE_SANDBOX_PERF_LOG=$path/server.log #echo $SLEDGE_SANDBOX_PERF_LOG From c90fbe95b4cbe73eac2783fe613f0fe5ac93bd8c Mon Sep 17 00:00:00 2001 From: xiaosuGW Date: Fri, 19 May 2023 15:07:47 -0600 Subject: [PATCH 041/198] implemented the main framework for DARC scheduling --- runtime/include/dispatcher.h | 15 ++++++++++++++ runtime/include/dispatcher_options.h | 10 ++++++++++ runtime/include/erpc_handler.h | 3 ++- runtime/include/http_router.h | 12 +++++++++--- runtime/src/dispatcher.c | 4 ++++ runtime/src/listener_thread.c | 29 +++++++++++++++++++++++----- runtime/src/main.c | 13 +++++++++++++ 7 files changed, 77 insertions(+), 9 deletions(-) create mode 100644 runtime/include/dispatcher.h create mode 100644 runtime/include/dispatcher_options.h create mode 100644 runtime/src/dispatcher.c diff --git a/runtime/include/dispatcher.h b/runtime/include/dispatcher.h new file mode 100644 index 000000000..8e83b65df --- /dev/null +++ b/runtime/include/dispatcher.h @@ -0,0 +1,15 @@ +#pragma once + +#include "dispatcher_options.h" + +static inline char * +dispatcher_print(enum DISPATCHER variant) +{ + switch (variant) { + case DISPATCHER_EDF_INTERRUPT: + return "EDF_INTERRUPT"; + case DISPATCHER_DARC: + return "DARC"; + } +} + diff --git a/runtime/include/dispatcher_options.h b/runtime/include/dispatcher_options.h new file mode 100644 index 000000000..7f6af8017 --- /dev/null +++ b/runtime/include/dispatcher_options.h @@ -0,0 +1,10 @@ +#pragma once + +enum DISPATCHER +{ + DISPATCHER_EDF_INTERRUPT = 0, + DISPATCHER_DARC = 1 +}; + +extern enum DISPATCHER dispatcher; + diff --git a/runtime/include/erpc_handler.h b/runtime/include/erpc_handler.h index 31abe5ae5..57d7d901f 100644 --- a/runtime/include/erpc_handler.h +++ b/runtime/include/erpc_handler.h @@ -1,4 +1,5 @@ #pragma once #include -void req_func(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); +void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); +void darc_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); diff --git a/runtime/include/http_router.h b/runtime/include/http_router.h index d5863ebfe..99a0a9f48 100644 --- a/runtime/include/http_router.h +++ b/runtime/include/http_router.h @@ -11,8 +11,8 @@ #include "route.h" #include "route_config.h" #include "vec.h" +#include "dispatcher_options.h" -//extern void (req_func) (void *req_handle, uint8_t req_type, uint8_t *msg, size_t size); typedef struct route route_t; VEC(route_t) @@ -46,8 +46,14 @@ http_router_add_route(http_router_t *router, struct route_config *config, struct /* Register RPC request handler */ - if (erpc_register_req_func(config->request_type, req_func, 0) != 0) { - panic("register erpc function failed\n"); + if (dispatcher == DISPATCHER_EDF_INTERRUPT) { + if (erpc_register_req_func(config->request_type, edf_interrupt_req_handler, 0) != 0) { + panic("register erpc function for EDF_INTERRUPT dispatcher failed\n"); + } + } else if (dispatcher == DISPATCHER_DARC) { + if (erpc_register_req_func(config->request_type, darc_req_handler, 0) != 0) { + panic("register erpc function for DARC dispatcher failed\n"); + } } /* Admissions Control */ diff --git a/runtime/src/dispatcher.c b/runtime/src/dispatcher.c new file mode 100644 index 000000000..027fcf65c --- /dev/null +++ b/runtime/src/dispatcher.c @@ -0,0 +1,4 @@ +#include "dispatcher.h" + +enum DISPATCHER dispatcher = DISPATCHER_EDF_INTERRUPT; + diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 31f51ace7..3396844c8 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -424,7 +424,7 @@ on_client_socket_epoll_event(struct epoll_event *evt) * @param msg the payload of the rpc request. It is the input parameter fot the function * @param size the size of the msg */ -void req_func(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { +void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { if (first_request_comming == false){ t_start = time(NULL); @@ -510,7 +510,20 @@ void req_func(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uin } } +/** + * @brief Request routing function + * @param req_handle used by eRPC internal, it is used to send out the response packet + * @param req_type the type of the request. Each function has a unique reqest type id + * @param msg the payload of the rpc request. It is the input parameter fot the function + * @param size the size of the msg + */ +void darc_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { +} + +void darc_dispatch() { + +} void dispatcher_send_response(void *req_handle, char* msg, size_t msg_len) { erpc_req_response_enqueue(dispatcher_thread_idx, req_handle, msg, msg_len, 1); } @@ -549,11 +562,17 @@ listener_thread_main(void *dummy) pthread_setschedprio(pthread_self(), -20); erpc_start(NULL, dispatcher_thread_idx, NULL, 0); - - while (!pthread_stop) { - erpc_run_event_loop(dispatcher_thread_idx, 1000); - } + if (dispatcher == DISPATCHER_EDF_INTERRUPT) { + while (!pthread_stop) { + erpc_run_event_loop(dispatcher_thread_idx, 1000); + } + } else if (dispatcher == DISPATCHER_DARC) { + while (!pthread_stop) { + erpc_run_event_loop_once(dispatcher_thread_idx); + darc_dispatch(); + } + } while (!pthread_stop) { printf("pthread_stop is false\n"); /* Block indefinitely on the epoll file descriptor, waiting on up to a max number of events */ diff --git a/runtime/src/main.c b/runtime/src/main.c index aeb0aa944..7937e0c46 100644 --- a/runtime/src/main.c +++ b/runtime/src/main.c @@ -26,6 +26,7 @@ #include "sandbox_perf_log.h" #include "sandbox_types.h" #include "scheduler.h" +#include "dispatcher.h" #include "software_interrupt.h" #include "tenant_functions.h" #include "worker_thread.h" @@ -253,6 +254,18 @@ runtime_configure() } pretty_print_key_value("Scheduler Policy", "%s\n", scheduler_print(scheduler)); + /* Dispatcher Policy */ + char *dispatcher_policy = getenv("SLEDGE_DISPATCHER"); + if (dispatcher_policy == NULL) dispatcher_policy = "EDF_INTERRUPT"; + if (strcmp(dispatcher_policy, "DARC") == 0) { + dispatcher = DISPATCHER_DARC; + } else if (strcmp(dispatcher_policy, "EDF_INTERRUPT") == 0) { + dispatcher = DISPATCHER_EDF_INTERRUPT; + } else { + panic("Invalid dispatcher policy: %s. Must be {EDF_INTERRUPT|DARC\n", dispatcher_policy); + } + pretty_print_key_value("Dispatcher Policy", "%s\n", dispatcher_print(dispatcher)); + /* Sigalrm Handler Technique */ char *sigalrm_policy = getenv("SLEDGE_SIGALRM_HANDLER"); if (sigalrm_policy == NULL) sigalrm_policy = "BROADCAST"; From a13e5d2e37ce91d043cefe03c5c3be51187d3d4c Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 19 May 2023 15:16:51 -0600 Subject: [PATCH 042/198] update runtime/tests/start.sh --- runtime/tests/start.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/tests/start.sh b/runtime/tests/start.sh index 56005ab99..0c39c4c18 100755 --- a/runtime/tests/start.sh +++ b/runtime/tests/start.sh @@ -28,6 +28,7 @@ export SLEDGE_NWORKERS=$worker_num export SLEDGE_NLISTENERS=$listener_num export SLEDGE_WORKER_GROUP_SIZE=3 export SLEDGE_SCHEDULER=EDF +#export SLEDGE_DISPATCHER=DARC export SLEDGE_SANDBOX_PERF_LOG=$path/server.log #echo $SLEDGE_SANDBOX_PERF_LOG cd $project_path/runtime/bin From b23c47391f0e33b6e414ab4e51c3f0a5c5577817 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Sat, 20 May 2023 02:06:39 -0600 Subject: [PATCH 043/198] implemented DARC algo but have a bug that the finished work doesn't correctly notify the listener it is idle --- runtime/include/request_typed_queue.h | 86 +++++++++++++++++++ runtime/include/route_config.h | 2 + runtime/include/route_config_parse.h | 12 ++- runtime/include/scheduler.h | 12 ++- runtime/include/tenant.h | 2 + runtime/include/tenant_functions.h | 22 ++++- runtime/src/listener_thread.c | 116 +++++++++++++++++++++++++- runtime/tests/debug.sh | 7 +- runtime/tests/fib.json | 10 ++- runtime/tests/start.sh | 2 +- 10 files changed, 255 insertions(+), 16 deletions(-) create mode 100644 runtime/include/request_typed_queue.h diff --git a/runtime/include/request_typed_queue.h b/runtime/include/request_typed_queue.h new file mode 100644 index 000000000..26c6daa60 --- /dev/null +++ b/runtime/include/request_typed_queue.h @@ -0,0 +1,86 @@ +#pragma once + +#define RQUEUE_LEN 4096 +#define MAX_WORKERS 32 + +extern uint32_t runtime_worker_group_size; + +struct request_msg { + uint8_t *msg; + size_t size; +}; + +struct request_typed_queue { + uint8_t type; + uint64_t mean_ns; + uint64_t deadline; + double ratio; + struct sandbox *rqueue[RQUEUE_LEN]; + unsigned int rqueue_tail; + unsigned int rqueue_head; + uint64_t tsqueue[RQUEUE_LEN]; + + // Profiling variables + uint64_t windows_mean_ns; + uint64_t windows_count; + uint64_t delay; + + //DARC variables + uint32_t res_workers[MAX_WORKERS]; //record the worker id from 0 to the maximum id for a listener, + //not the true worker id. It's value is the index of worker_list + uint32_t n_resas; + uint64_t last_resa; + uint32_t stealable_workers[MAX_WORKERS]; + uint32_t n_stealable; + int type_group; + uint64_t max_delay; + double prev_demand; + + /*RequestType(enum ReqType type, uint64_t mean_ns, uint64_t deadline, double ratio) : + type(type), mean_ns(mean_ns), deadline(deadline), ratio(ratio) { + //There must be a way to 0-init an C array from initializer list + memset(rqueue, 0, RQUEUE_LEN * sizeof(unsigned long)); + rqueue_tail = 0; + rqueue_head = 0; + }; + */ +}; + +static inline struct request_typed_queue * +request_typed_queue_init(uint8_t type, uint32_t n_resas) { + struct request_typed_queue *queue = malloc(sizeof(struct request_typed_queue)); + queue->type = type; + queue->mean_ns = 0; + queue->deadline = 0; + queue->rqueue_tail = 0; + queue->rqueue_head = 0; + queue->n_resas = n_resas; + for (unsigned int i = 0; i < n_resas; ++i) { + queue->res_workers[i] = i; + } + + queue->n_stealable = runtime_worker_group_size - n_resas; + int index = 0; + for (unsigned int i = n_resas; i < runtime_worker_group_size; i++) { + queue->stealable_workers[index] = i; + index++; + } + + memset(queue->rqueue, 0, RQUEUE_LEN * sizeof(struct sandbox*)); + + return queue; + +} + +static inline int push_to_rqueue(struct sandbox *sandbox, struct request_typed_queue *rtype, uint64_t tsc) { + if (unlikely(rtype->rqueue_head - rtype->rqueue_tail == RQUEUE_LEN)) { + panic("Dispatcher dropped request as type %hhu because queue is full\n", rtype->type); + return -1; + } else { + //PSP_DEBUG("Pushed one request to queue " << req_type_str[static_cast(rtype.type)]); + rtype->tsqueue[rtype->rqueue_head & (RQUEUE_LEN - 1)] = tsc; + rtype->rqueue[rtype->rqueue_head++ & (RQUEUE_LEN - 1)] = sandbox; + return 0; + } +} + diff --git a/runtime/include/route_config.h b/runtime/include/route_config.h index cc7053bd4..43bf0926a 100644 --- a/runtime/include/route_config.h +++ b/runtime/include/route_config.h @@ -12,6 +12,7 @@ enum route_config_member { route_config_member_route, route_config_member_request_type, + route_config_member_n_resas, route_config_member_path, route_config_member_admissions_percentile, route_config_member_expected_execution_us, @@ -23,6 +24,7 @@ enum route_config_member struct route_config { char *route; uint8_t request_type; + uint32_t n_resas; char *path; uint8_t admissions_percentile; uint32_t expected_execution_us; diff --git a/runtime/include/route_config_parse.h b/runtime/include/route_config_parse.h index c7403df4a..11f0a2c10 100644 --- a/runtime/include/route_config_parse.h +++ b/runtime/include/route_config_parse.h @@ -8,6 +8,7 @@ static const char *route_config_json_keys[route_config_member_len] = { "route", "request-type", + "n-resas", "path", "admissions-percentile", "expected-execution-us", @@ -66,7 +67,16 @@ route_config_parse(struct route_config *config, const char *json_buf, jsmntok_t route_config_json_keys[route_config_member_request_type], &config->request_type); if (rc < 0) return -1; - } else if (strcmp(key, route_config_json_keys[route_config_member_path]) == 0) { + } else if (strcmp(key, route_config_json_keys[route_config_member_n_resas]) == 0) { + if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1; + if (route_config_set_key_once(did_set, route_config_member_n_resas) == -1) + return -1; + + int rc = parse_uint32_t(tokens[i], json_buf, + route_config_json_keys[route_config_member_n_resas], + &config->n_resas); + if (rc < 0) return -1; + } else if (strcmp(key, route_config_json_keys[route_config_member_path]) == 0) { if (!is_nonempty_string(tokens[i], key)) return -1; if (route_config_set_key_once(did_set, route_config_member_path) == -1) return -1; diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index fe0e42da7..0550a29ed 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -27,7 +27,8 @@ #include "sandbox_perf_log.h" extern thread_local bool pthread_stop; - +extern uint32_t runtime_worker_group_size; +extern thread_local _Atomic uint32_t free_workers; /** * This scheduler provides for cooperative and preemptive multitasking in a OS process's userspace. * @@ -408,6 +409,7 @@ scheduler_idle_loop() /* Switch to a sandbox if one is ready to run */ struct sandbox *next_sandbox = scheduler_get_next(); if (next_sandbox != NULL) { + printf("poped a sandbox\n"); next_sandbox->timestamp_of.cleanup += cleanup_cost; next_sandbox->timestamp_of.other += other; next_sandbox->context_switch_to = 1; @@ -452,7 +454,9 @@ scheduler_cooperative_sched(bool add_to_cleanup_queue) { //uint64_t now = __getcycles(); struct sandbox *exiting_sandbox = current_sandbox_get(); + assert(exiting_sandbox != NULL); + uint8_t dispatcher_id = exiting_sandbox->rpc_id; /* Clearing current sandbox indicates we are entering the cooperative scheduler */ current_sandbox_set(NULL); @@ -498,6 +502,12 @@ scheduler_cooperative_sched(bool add_to_cleanup_queue) /* Do not touch sandbox struct after this point! */ /* Logging this sandbox to memory */ sandbox_perf_log_print_entry(exiting_sandbox); + + if (dispatcher == DISPATCHER_DARC) { + int virtual_id = worker_thread_idx - dispatcher_id * runtime_worker_group_size; + atomic_fetch_or(&free_workers, 1 << virtual_id); + } + if (next_sandbox != NULL) { next_sandbox->context_switch_to = 2; scheduler_cooperative_switch_to(exiting_context, next_sandbox); diff --git a/runtime/include/tenant.h b/runtime/include/tenant.h index 6c121a5d7..113fdca35 100644 --- a/runtime/include/tenant.h +++ b/runtime/include/tenant.h @@ -36,6 +36,8 @@ struct tenant { enum epoll_tag tag; /* Tag must be first member */ char *name; uint16_t port; + struct route_config *routes_config; + size_t routes_len; struct tcp_server tcp_server; http_router_t router; struct module_database module_db; diff --git a/runtime/include/tenant_functions.h b/runtime/include/tenant_functions.h index ab3fa3aeb..465c655bf 100644 --- a/runtime/include/tenant_functions.h +++ b/runtime/include/tenant_functions.h @@ -13,8 +13,11 @@ #include "tenant_config.h" #include "priority_queue.h" #include "sandbox_functions.h" +#include "request_typed_queue.h" #include "memlogging.h" +extern thread_local uint32_t n_rtypes; +extern thread_local struct request_typed_queue *request_type_queue[10]; extern thread_local struct perf_window perf_window_per_thread[1024]; extern thread_local int worker_thread_idx; @@ -88,10 +91,12 @@ tenant_alloc(struct tenant_config *config) struct tenant *tenant = (struct tenant *)calloc(1, sizeof(struct tenant)); /* Move name */ - tenant->tag = EPOLL_TAG_TENANT_SERVER_SOCKET; - tenant->name = config->name; - tenant->port = config->port; - config->name = NULL; + tenant->tag = EPOLL_TAG_TENANT_SERVER_SOCKET; + tenant->name = config->name; + tenant->port = config->port; + tenant->routes_config = config->routes; + tenant->routes_len = config->routes_len; + config->name = NULL; tcp_server_init(&tenant->tcp_server, config->port); http_router_init(&tenant->router, config->routes_len); @@ -182,6 +187,15 @@ tenant_perf_window_init(struct tenant *tenant, void *arg1, void *arg2) { } } +static inline void +tenant_request_typed_queue_init(struct tenant *tenant, void *arg1, void *arg2) { + for(int i = 0; i < tenant->routes_len; i++) { + request_type_queue[tenant->routes_config[i].request_type - 1] = + request_typed_queue_init(tenant->routes_config[i].request_type, tenant->routes_config[i].n_resas); + } + n_rtypes = tenant->routes_len; +} + static inline void tenat_perf_window_print_mean(struct tenant *tenant, void *arg1, void *arg2) { for(int i = 0; i < tenant->router.length; i++) { diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 3396844c8..846bacbd5 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -15,6 +15,7 @@ #include "tenant_functions.h" #include "http_session_perf_log.h" #include "sandbox_set_as_runnable.h" +#include "request_typed_queue.h" struct perf_window * worker_perf_windows[1024]; struct priority_queue * worker_queues[1024]; @@ -29,6 +30,10 @@ extern uint32_t runtime_worker_group_size; thread_local uint32_t worker_start_id; thread_local uint32_t worker_end_id; +thread_local uint32_t worker_list[MAX_WORKERS]; // record the worker's true index +thread_local _Atomic uint32_t free_workers = 0; +thread_local struct request_typed_queue *request_type_queue[10]; +thread_local uint32_t n_rtypes = 0; time_t t_start; extern bool first_request_comming; @@ -56,6 +61,10 @@ thread_local pthread_t listener_thread_id; thread_local bool is_listener = false; +void typed_queue_init() { + tenant_database_foreach(tenant_request_typed_queue_init, NULL, NULL); +} + /** * Initializes the listener thread, pinned to core 0, and starts to listen for requests */ @@ -518,12 +527,102 @@ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, * @param size the size of the msg */ void darc_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { + if (first_request_comming == false){ + t_start = time(NULL); + first_request_comming = true; + } + + uint8_t kMsgSize = 16; + //TODO: rpc_id is hardcode now + + struct tenant *tenant = tenant_database_find_by_port(port); + assert(tenant != NULL); + struct route *route = http_router_match_request_type(&tenant->router, req_type); + if (route == NULL) { + debuglog("Did not match any routes\n"); + dispatcher_send_response(req_handle, DIPATCH_ROUNTE_ERROR, strlen(DIPATCH_ROUNTE_ERROR)); + return; + } + + /* + * Perform admissions control. + * If 0, workload was rejected, so close with 429 "Too Many Requests" and continue + * TODO: Consider providing a Retry-After header + */ + uint64_t work_admitted = admissions_control_decide(route->admissions_info.estimate); + if (work_admitted == 0) { + dispatcher_send_response(req_handle, WORK_ADMITTED_ERROR, strlen(WORK_ADMITTED_ERROR)); + return; + } + + /* Allocate a Sandbox */ + //session->state = HTTP_SESSION_EXECUTING; + struct sandbox *sandbox = sandbox_alloc(route->module, NULL, route, tenant, work_admitted, req_handle, dispatcher_thread_idx); + if (unlikely(sandbox == NULL)) { + debuglog("Failed to allocate sandbox\n"); + dispatcher_send_response(req_handle, SANDBOX_ALLOCATION_ERROR, strlen(SANDBOX_ALLOCATION_ERROR)); + return; + } + + /* copy the received data since it will be released by erpc */ + sandbox->rpc_request_body = malloc(size); + if (!sandbox->rpc_request_body) { + panic("malloc request body failed\n"); + } + + memcpy(sandbox->rpc_request_body, msg, size); + sandbox->rpc_request_body_size = size; + push_to_rqueue(sandbox, request_type_queue[req_type - 1], 0); } -void darc_dispatch() { +void drain_queue(struct request_typed_queue *rtype) { + assert(rtype != NULL); + while (rtype->rqueue_head > rtype->rqueue_tail && free_workers > 0) { + uint32_t worker_id = MAX_WORKERS + 1; + // Lookup for a core reserved to this type's group + for (uint32_t i = 0; i < rtype->n_resas; ++i) { + uint32_t candidate = rtype->res_workers[i]; + if ((1 << candidate) & free_workers) { + worker_id = candidate; + printf("Using reserved core %u\n", worker_list[worker_id]); + break; + } + } + // Otherwise attempt to steal worker + if (worker_id == MAX_WORKERS + 1) { + for (unsigned int i = 0; i < rtype->n_stealable; ++i) { + uint32_t candidate = rtype->stealable_workers[i]; + if ((1 << candidate) & free_workers) { + worker_id = candidate; + printf("Stealing core %u\n", worker_list[worker_id]); + break; + } + } + } + // No peer found + if (worker_id == MAX_WORKERS + 1) { + return; + } + + // Dispatch + struct sandbox *sandbox = rtype->rqueue[rtype->rqueue_tail & (RQUEUE_LEN - 1)]; + //add sandbox to worker's local queue + local_runqueue_add_index(worker_list[worker_id], sandbox); + rtype->rqueue_tail++; + atomic_fetch_xor(&free_workers, 1 << worker_id); + } } + +void darc_dispatch() { + for (uint32_t i = 0; i < n_rtypes; ++i) { + if (request_type_queue[i]->rqueue_head > request_type_queue[i]->rqueue_tail) { + drain_queue(request_type_queue[i]); + } + } +} + void dispatcher_send_response(void *req_handle, char* msg, size_t msg_len) { erpc_req_response_enqueue(dispatcher_thread_idx, req_handle, msg, msg_len, 1); } @@ -540,6 +639,9 @@ void dispatcher_send_response(void *req_handle, char* msg, size_t msg_len) { void * listener_thread_main(void *dummy) { + /* init typed queue */ + typed_queue_init(); + is_listener = true; /* Unmask SIGINT signals */ software_interrupt_unmask_signal(SIGINT); @@ -551,7 +653,17 @@ listener_thread_main(void *dummy) worker_start_id = dispatcher_thread_idx * runtime_worker_group_size; worker_end_id = worker_start_id + runtime_worker_group_size; printf("listener %d worker_start_id %d worker_end_id %d\n", dispatcher_thread_idx, worker_start_id, worker_end_id - 1); - + + int index = 0; + for (uint32_t i = worker_start_id; i < worker_end_id; i++) { + worker_list[index] = i; + index++; + } + + free_workers = __builtin_powi(2, runtime_worker_group_size) - 1; + + printf("free_workers is %u\n", free_workers); + struct epoll_event epoll_events[RUNTIME_MAX_EPOLL_EVENTS]; metrics_server_init(); diff --git a/runtime/tests/debug.sh b/runtime/tests/debug.sh index 9a792d49e..53efa9bd3 100755 --- a/runtime/tests/debug.sh +++ b/runtime/tests/debug.sh @@ -13,9 +13,10 @@ echo $project_path cd $project_path/runtime/bin #export SLEDGE_DISABLE_PREEMPTION=true export SLEDGE_SANDBOX_PERF_LOG=$path/srsf.log -export SLEDGE_NWORKERS=6 -export SLEDGE_FIRST_WORKER_COREID=7 -export SLEDGE_NLISTENERS=6 +export SLEDGE_NWORKERS=9 +export SLEDGE_FIRST_WORKER_COREID=4 +export SLEDGE_NLISTENERS=3 +export SLEDGE_DISPATCHER=DARC export LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" #gdb --eval-command="handle SIGUSR1 nostop" \ # --eval-command="set pagination off" \ diff --git a/runtime/tests/fib.json b/runtime/tests/fib.json index cbccc6118..452d58f2a 100644 --- a/runtime/tests/fib.json +++ b/runtime/tests/fib.json @@ -8,19 +8,21 @@ { "route": "/fib", "request-type": 1, + "n-resas": 2, "path": "fibonacci.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 6, - "relative-deadline-us": 60, + "expected-execution-us": 10, + "relative-deadline-us": 100, "http-resp-content-type": "text/plain" }, { "route": "/fib2", "request-type": 2, + "n-resas": 1, "path": "fibonacci.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 785, - "relative-deadline-us": 7850, + "expected-execution-us": 1376, + "relative-deadline-us": 13760, "http-resp-content-type": "text/plain" } ] diff --git a/runtime/tests/start.sh b/runtime/tests/start.sh index 0c39c4c18..e2da5d84c 100755 --- a/runtime/tests/start.sh +++ b/runtime/tests/start.sh @@ -28,7 +28,7 @@ export SLEDGE_NWORKERS=$worker_num export SLEDGE_NLISTENERS=$listener_num export SLEDGE_WORKER_GROUP_SIZE=3 export SLEDGE_SCHEDULER=EDF -#export SLEDGE_DISPATCHER=DARC +export SLEDGE_DISPATCHER=DARC export SLEDGE_SANDBOX_PERF_LOG=$path/server.log #echo $SLEDGE_SANDBOX_PERF_LOG cd $project_path/runtime/bin From 72a33224b9cf7f4310295fc3a4e56ff4e5cefea4 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Sat, 20 May 2023 18:03:40 -0600 Subject: [PATCH 044/198] fix the previous bug for DARC algo --- runtime/include/scheduler.h | 6 +++--- runtime/src/listener_thread.c | 18 +++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index 0550a29ed..abe34ed64 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -28,7 +28,7 @@ extern thread_local bool pthread_stop; extern uint32_t runtime_worker_group_size; -extern thread_local _Atomic uint32_t free_workers; +extern _Atomic uint32_t free_workers[10]; /** * This scheduler provides for cooperative and preemptive multitasking in a OS process's userspace. * @@ -409,7 +409,7 @@ scheduler_idle_loop() /* Switch to a sandbox if one is ready to run */ struct sandbox *next_sandbox = scheduler_get_next(); if (next_sandbox != NULL) { - printf("poped a sandbox\n"); + //printf("poped a sandbox\n"); next_sandbox->timestamp_of.cleanup += cleanup_cost; next_sandbox->timestamp_of.other += other; next_sandbox->context_switch_to = 1; @@ -505,7 +505,7 @@ scheduler_cooperative_sched(bool add_to_cleanup_queue) if (dispatcher == DISPATCHER_DARC) { int virtual_id = worker_thread_idx - dispatcher_id * runtime_worker_group_size; - atomic_fetch_or(&free_workers, 1 << virtual_id); + atomic_fetch_or(&free_workers[dispatcher_id], 1 << virtual_id); } if (next_sandbox != NULL) { diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 846bacbd5..4da6e1167 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -31,7 +31,7 @@ extern uint32_t runtime_worker_group_size; thread_local uint32_t worker_start_id; thread_local uint32_t worker_end_id; thread_local uint32_t worker_list[MAX_WORKERS]; // record the worker's true index -thread_local _Atomic uint32_t free_workers = 0; +_Atomic uint32_t free_workers[10] = {0}; thread_local struct request_typed_queue *request_type_queue[10]; thread_local uint32_t n_rtypes = 0; @@ -578,14 +578,14 @@ void darc_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t s void drain_queue(struct request_typed_queue *rtype) { assert(rtype != NULL); - while (rtype->rqueue_head > rtype->rqueue_tail && free_workers > 0) { + while (rtype->rqueue_head > rtype->rqueue_tail && free_workers[dispatcher_thread_idx] > 0) { uint32_t worker_id = MAX_WORKERS + 1; // Lookup for a core reserved to this type's group for (uint32_t i = 0; i < rtype->n_resas; ++i) { uint32_t candidate = rtype->res_workers[i]; - if ((1 << candidate) & free_workers) { + if ((1 << candidate) & free_workers[dispatcher_thread_idx]) { worker_id = candidate; - printf("Using reserved core %u\n", worker_list[worker_id]); + //printf("Using reserved core %u\n", worker_list[worker_id]); break; } } @@ -593,9 +593,9 @@ void drain_queue(struct request_typed_queue *rtype) { if (worker_id == MAX_WORKERS + 1) { for (unsigned int i = 0; i < rtype->n_stealable; ++i) { uint32_t candidate = rtype->stealable_workers[i]; - if ((1 << candidate) & free_workers) { + if ((1 << candidate) & free_workers[dispatcher_thread_idx]) { worker_id = candidate; - printf("Stealing core %u\n", worker_list[worker_id]); + //printf("Stealing core %u\n", worker_list[worker_id]); break; } } @@ -610,7 +610,7 @@ void drain_queue(struct request_typed_queue *rtype) { //add sandbox to worker's local queue local_runqueue_add_index(worker_list[worker_id], sandbox); rtype->rqueue_tail++; - atomic_fetch_xor(&free_workers, 1 << worker_id); + atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << worker_id); } } @@ -660,9 +660,9 @@ listener_thread_main(void *dummy) index++; } - free_workers = __builtin_powi(2, runtime_worker_group_size) - 1; + free_workers[dispatcher_thread_idx] = __builtin_powi(2, runtime_worker_group_size) - 1; - printf("free_workers is %u\n", free_workers); + printf("free_workers is %u\n", free_workers[dispatcher_thread_idx]); struct epoll_event epoll_events[RUNTIME_MAX_EPOLL_EVENTS]; From 68889929e69fe4bd7c9cfa4d2ba3bbae755bbfc5 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Sat, 20 May 2023 20:25:44 -0600 Subject: [PATCH 045/198] update fib.json --- runtime/tests/fib.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/runtime/tests/fib.json b/runtime/tests/fib.json index 452d58f2a..c73167ac6 100644 --- a/runtime/tests/fib.json +++ b/runtime/tests/fib.json @@ -11,8 +11,8 @@ "n-resas": 2, "path": "fibonacci.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 10, - "relative-deadline-us": 100, + "expected-execution-us": 5, + "relative-deadline-us": 50, "http-resp-content-type": "text/plain" }, { @@ -21,8 +21,8 @@ "n-resas": 1, "path": "fibonacci.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 1376, - "relative-deadline-us": 13760, + "expected-execution-us": 798, + "relative-deadline-us": 7980, "http-resp-content-type": "text/plain" } ] From a4e1c4ab86cf7dd6ef8c98bbaf66b7f60abdb37b Mon Sep 17 00:00:00 2001 From: xiaosuGW Date: Tue, 12 Sep 2023 19:00:51 -0500 Subject: [PATCH 046/198] add comment --- runtime/include/binary_search_tree.h | 2 +- runtime/include/request_typed_queue.h | 3 +++ runtime/src/listener_thread.c | 23 +++++++++++++++++++---- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/runtime/include/binary_search_tree.h b/runtime/include/binary_search_tree.h index 889b3bbff..10b42596b 100644 --- a/runtime/include/binary_search_tree.h +++ b/runtime/include/binary_search_tree.h @@ -14,7 +14,7 @@ struct TreeNode { struct TreeNode *left; struct TreeNode *right; struct TreeNode *next; // pointing to the next node - void *data; + void *data; // sandbox }; // Definition of TreeNode memory pool diff --git a/runtime/include/request_typed_queue.h b/runtime/include/request_typed_queue.h index 26c6daa60..0e444db05 100644 --- a/runtime/include/request_typed_queue.h +++ b/runtime/include/request_typed_queue.h @@ -46,6 +46,9 @@ struct request_typed_queue { */ }; +/* + * n_resas the number of reserved workers. Leaving the last n_resas workers as the reserved workers + */ static inline struct request_typed_queue * request_typed_queue_init(uint8_t type, uint32_t n_resas) { struct request_typed_queue *queue = malloc(sizeof(struct request_typed_queue)); diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 4da6e1167..f995bf1a0 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -31,8 +31,18 @@ extern uint32_t runtime_worker_group_size; thread_local uint32_t worker_start_id; thread_local uint32_t worker_end_id; thread_local uint32_t worker_list[MAX_WORKERS]; // record the worker's true index -_Atomic uint32_t free_workers[10] = {0}; -thread_local struct request_typed_queue *request_type_queue[10]; +_Atomic uint32_t free_workers[10] = {0}; // the index is the dispatercher id, free_workers[dispatcher_id] + // is decimal value of the bitmap of avaliable workers. + // For example, if there are 3 workers available, the bitmap + // will be 111, then the free_workers[dispatcher_id] is 7 +thread_local struct request_typed_queue *request_type_queue[10]; // the index is the request type + // We implicitly represent the request + // execution time as long or short based + // on the value of the request type. + // For example, the execution time of + // request with type 1 is shorter than request + // with type 2, that's reducing the sorting + // cost of the typed queue thread_local uint32_t n_rtypes = 0; time_t t_start; @@ -578,6 +588,7 @@ void darc_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t s void drain_queue(struct request_typed_queue *rtype) { assert(rtype != NULL); + /* queue is not empty and there is free workers */ while (rtype->rqueue_head > rtype->rqueue_tail && free_workers[dispatcher_thread_idx] > 0) { uint32_t worker_id = MAX_WORKERS + 1; // Lookup for a core reserved to this type's group @@ -617,6 +628,8 @@ void drain_queue(struct request_typed_queue *rtype) { void darc_dispatch() { for (uint32_t i = 0; i < n_rtypes; ++i) { + // request_type_queue is a sorted queue, so the loop will dispatch packets from + // the earliest deadline to least earliest deadline if (request_type_queue[i]->rqueue_head > request_type_queue[i]->rqueue_tail) { drain_queue(request_type_queue[i]); } @@ -681,10 +694,12 @@ listener_thread_main(void *dummy) } } else if (dispatcher == DISPATCHER_DARC) { while (!pthread_stop) { - erpc_run_event_loop_once(dispatcher_thread_idx); - darc_dispatch(); + erpc_run_event_loop_once(dispatcher_thread_idx); // get a group of packets from the NIC and enqueue them to the typed queue + darc_dispatch(); //dispatch packets } } + + /* won't go to the following implementaion */ while (!pthread_stop) { printf("pthread_stop is false\n"); /* Block indefinitely on the epoll file descriptor, waiting on up to a max number of events */ From 5179ed3fe697875eca66862c3b9e3c24d55d28b9 Mon Sep 17 00:00:00 2001 From: xiaosuGW Date: Wed, 13 Sep 2023 23:30:48 -0600 Subject: [PATCH 047/198] 1. rename variables to make it more easy to understand. 2. add commment --- runtime/src/listener_thread.c | 30 ++++++++++++------------ runtime/src/local_runqueue_binary_tree.c | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index f995bf1a0..09a3b1144 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -491,39 +491,39 @@ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, memcpy(sandbox->rpc_request_body, msg, size); sandbox->rpc_request_body_size = size; - uint64_t min_serving_time = UINT64_MAX; + uint64_t min_waiting_serving_time = UINT64_MAX; int thread_id = 0; - int candidate_thread_id = -1; + int candidate_thread_with_interrupt = -1; for (uint32_t i = worker_start_id; i < worker_end_id; i++) { bool need_interrupt; - uint64_t serving_time = local_runqueue_try_add_index(i, sandbox, &need_interrupt); - /* The local queue is empty, can be served this request immediately without interrupting - * current one + uint64_t waiting_serving_time = local_runqueue_try_add_index(i, sandbox, &need_interrupt); + /* The local queue is empty, the worker is idle, can be served this request immediately + * without interrupting */ - if (serving_time == 0 && need_interrupt == false) { + if (waiting_serving_time == 0 && need_interrupt == false) { local_runqueue_add_index(i, sandbox); return; - } else if (serving_time == 0 && need_interrupt == true) {//The worker can serve the request immediately + } else if (waiting_serving_time == 0 && need_interrupt == true) {//The worker can serve the request immediately // by interrupting the current one /* We already have a candidate thread, continue to find a * better thread without needing interrupt */ - if (candidate_thread_id != -1) { + if (candidate_thread_with_interrupt != -1) { continue; } else { - candidate_thread_id = i; + candidate_thread_with_interrupt = i; } - } else if (min_serving_time > serving_time) { - min_serving_time = serving_time; + } else if (min_waiting_serving_time > waiting_serving_time) { + min_waiting_serving_time = waiting_serving_time; thread_id = i; } } - if (candidate_thread_id != -1) { - //urgent_request[candidate_thread_id] = sandbox; - local_runqueue_add_index(candidate_thread_id, sandbox); - preempt_worker(candidate_thread_id); + if (candidate_thread_with_interrupt != -1) { + //urgent_request[candidate_thread_with_interrupt] = sandbox; + local_runqueue_add_index(candidate_thread_with_interrupt, sandbox); + preempt_worker(candidate_thread_with_interrupt); } else { local_runqueue_add_index(thread_id, sandbox); } diff --git a/runtime/src/local_runqueue_binary_tree.c b/runtime/src/local_runqueue_binary_tree.c index b3cb0527a..49b8b5618 100644 --- a/runtime/src/local_runqueue_binary_tree.c +++ b/runtime/src/local_runqueue_binary_tree.c @@ -97,7 +97,7 @@ local_runqueue_binary_tree_get_next() * Try but not real add a item to the local runqueue. * @param index The worker thread id * @param sandbox Try to add - * @returns The waiting serving time for this sandbox + * @returns The waiting serving time for this sandbox if adding it to the queue */ uint64_t local_runqueue_binary_tree_try_add_index(int index, struct sandbox *sandbox, bool *need_interrupt) From 0c4f886ff7a775c48e31a9b526bc6d88111a1b69 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Sat, 23 Sep 2023 00:37:39 -0600 Subject: [PATCH 048/198] shinjuku implementation with bugs --- runtime/include/binary_search_tree.h | 3 +- runtime/include/current_sandbox.h | 8 +- runtime/include/dispatcher.h | 2 + runtime/include/dispatcher_options.h | 3 +- runtime/include/erpc_handler.h | 2 +- runtime/include/http_router.h | 12 +- runtime/include/listener_thread.h | 5 +- runtime/include/module.h | 10 +- runtime/include/request_typed_queue.h | 51 +--- runtime/include/route.h | 12 +- runtime/include/sandbox_perf_log.h | 6 +- runtime/include/sandbox_set_as_returned.h | 4 +- runtime/include/sandbox_set_as_running_sys.h | 2 +- runtime/include/sandbox_set_as_running_user.h | 2 +- runtime/include/sandbox_types.h | 3 + runtime/include/scheduler.h | 30 ++- runtime/include/software_interrupt_counts.h | 16 +- runtime/include/tenant_functions.h | 10 +- runtime/include/worker_thread.h | 2 +- runtime/src/arch_context.c | 3 +- runtime/src/listener_thread.c | 235 ++++++++++++++---- runtime/src/local_runqueue_binary_tree.c | 4 +- runtime/src/local_runqueue_minheap.c | 6 +- runtime/src/local_runqueue_mtds.c | 4 +- runtime/src/main.c | 23 +- runtime/src/sandbox.c | 7 + runtime/src/software_interrupt.c | 6 +- runtime/src/worker_thread.c | 19 +- 28 files changed, 324 insertions(+), 166 deletions(-) diff --git a/runtime/include/binary_search_tree.h b/runtime/include/binary_search_tree.h index 10b42596b..6c3de7988 100644 --- a/runtime/include/binary_search_tree.h +++ b/runtime/include/binary_search_tree.h @@ -13,7 +13,8 @@ typedef uint64_t (*binary_tree_get_execution_cost_fn_t)(void *data, int thread_i struct TreeNode { struct TreeNode *left; struct TreeNode *right; - struct TreeNode *next; // pointing to the next node + struct TreeNode *next; // pointing to the next node, this is used for nodePool + // to find next available node void *data; // sandbox }; diff --git a/runtime/include/current_sandbox.h b/runtime/include/current_sandbox.h index 3b360f3ae..2e9b5522e 100644 --- a/runtime/include/current_sandbox.h +++ b/runtime/include/current_sandbox.h @@ -48,8 +48,8 @@ current_sandbox_set(struct sandbox *sandbox) .wasi_context = NULL, }; worker_thread_current_sandbox = NULL; - current_sandboxes[worker_thread_idx] = NULL; - runtime_worker_threads_deadline[worker_thread_idx] = UINT64_MAX; + current_sandboxes[global_worker_thread_idx] = NULL; + runtime_worker_threads_deadline[global_worker_thread_idx] = UINT64_MAX; } else { sledge_abi__current_wasm_module_instance.wasi_context = sandbox->wasi_context; memcpy(&sledge_abi__current_wasm_module_instance.abi.memory, &sandbox->memory->abi, @@ -58,8 +58,8 @@ current_sandbox_set(struct sandbox *sandbox) wasm_globals_update_if_used(&sandbox->globals, 0, &sledge_abi__current_wasm_module_instance.abi.wasmg_0); worker_thread_current_sandbox = sandbox; - current_sandboxes[worker_thread_idx] = sandbox; - runtime_worker_threads_deadline[worker_thread_idx] = sandbox->absolute_deadline; + current_sandboxes[global_worker_thread_idx] = sandbox; + runtime_worker_threads_deadline[global_worker_thread_idx] = sandbox->absolute_deadline; } } diff --git a/runtime/include/dispatcher.h b/runtime/include/dispatcher.h index 8e83b65df..522f109de 100644 --- a/runtime/include/dispatcher.h +++ b/runtime/include/dispatcher.h @@ -10,6 +10,8 @@ dispatcher_print(enum DISPATCHER variant) return "EDF_INTERRUPT"; case DISPATCHER_DARC: return "DARC"; + case DISPATCHER_SHINJUKU: + return "SHINJUKU"; } } diff --git a/runtime/include/dispatcher_options.h b/runtime/include/dispatcher_options.h index 7f6af8017..4b82903e2 100644 --- a/runtime/include/dispatcher_options.h +++ b/runtime/include/dispatcher_options.h @@ -3,7 +3,8 @@ enum DISPATCHER { DISPATCHER_EDF_INTERRUPT = 0, - DISPATCHER_DARC = 1 + DISPATCHER_DARC = 1, + DISPATCHER_SHINJUKU = 2, }; extern enum DISPATCHER dispatcher; diff --git a/runtime/include/erpc_handler.h b/runtime/include/erpc_handler.h index 57d7d901f..c753fd9b9 100644 --- a/runtime/include/erpc_handler.h +++ b/runtime/include/erpc_handler.h @@ -2,4 +2,4 @@ #include void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); -void darc_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); +void darc_shinjuku_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); diff --git a/runtime/include/http_router.h b/runtime/include/http_router.h index 99a0a9f48..332fa7950 100644 --- a/runtime/include/http_router.h +++ b/runtime/include/http_router.h @@ -47,13 +47,13 @@ http_router_add_route(http_router_t *router, struct route_config *config, struct /* Register RPC request handler */ if (dispatcher == DISPATCHER_EDF_INTERRUPT) { - if (erpc_register_req_func(config->request_type, edf_interrupt_req_handler, 0) != 0) { - panic("register erpc function for EDF_INTERRUPT dispatcher failed\n"); + if (erpc_register_req_func(config->request_type, edf_interrupt_req_handler, 0) != 0) { + panic("register erpc function for EDF_INTERRUPT dispatcher failed\n"); } - } else if (dispatcher == DISPATCHER_DARC) { - if (erpc_register_req_func(config->request_type, darc_req_handler, 0) != 0) { - panic("register erpc function for DARC dispatcher failed\n"); - } + } else if (dispatcher == DISPATCHER_DARC || dispatcher == DISPATCHER_SHINJUKU) { + if (erpc_register_req_func(config->request_type, darc_shinjuku_req_handler, 0) != 0) { + panic("register erpc function for DARC dispatcher failed\n"); + } } /* Admissions Control */ diff --git a/runtime/include/listener_thread.h b/runtime/include/listener_thread.h index 5c3ba6f04..4206699ed 100644 --- a/runtime/include/listener_thread.h +++ b/runtime/include/listener_thread.h @@ -6,12 +6,15 @@ #include "http_session.h" #include "module.h" -#define LISTENER_THREAD_CORE_ID 1 +#define LISTENER_THREAD_START_CORE_ID 1 #define DIPATCH_ROUNTE_ERROR "Did not match any routes" #define WORK_ADMITTED_ERROR "Work is not admitted" #define SANDBOX_ALLOCATION_ERROR "Failed to allocate a sandbox" #define GLOBAL_QUEUE_ERROR "Failed to add sandbox to global queue" +#define MAX_DISPATCHER 10 +#define MAX_REQUEST_TYPE 10 + extern thread_local pthread_t listener_thread_id; void listener_thread_initialize(uint8_t thread_id); diff --git a/runtime/include/module.h b/runtime/include/module.h index a56f6777c..28b583015 100644 --- a/runtime/include/module.h +++ b/runtime/include/module.h @@ -18,7 +18,7 @@ #include "wasm_memory.h" #include "wasm_table.h" -extern thread_local int worker_thread_idx; +extern thread_local int global_worker_thread_idx; INIT_POOL(wasm_memory, wasm_memory_free) INIT_POOL(wasm_stack, wasm_stack_free) @@ -168,7 +168,7 @@ module_allocate_stack(struct module *module) { assert(module != NULL); - struct wasm_stack *stack = wasm_stack_pool_remove_nolock(&module->pools[worker_thread_idx].stack); + struct wasm_stack *stack = wasm_stack_pool_remove_nolock(&module->pools[global_worker_thread_idx].stack); if (stack == NULL) { stack = wasm_stack_alloc(module->stack_size); @@ -184,7 +184,7 @@ module_free_stack(struct module *module, struct wasm_stack *stack) uint64_t now = __getcycles(); wasm_stack_reinit(stack); uint64_t d = __getcycles() - now; - wasm_stack_pool_add_nolock(&module->pools[worker_thread_idx].stack, stack); + wasm_stack_pool_add_nolock(&module->pools[global_worker_thread_idx].stack, stack); return d; } @@ -202,7 +202,7 @@ module_allocate_linear_memory(struct module *module) assert(starting_bytes <= (uint64_t)UINT32_MAX + 1); assert(max_bytes <= (uint64_t)UINT32_MAX + 1); - struct wasm_memory *linear_memory = wasm_memory_pool_remove_nolock(&module->pools[worker_thread_idx].memory); + struct wasm_memory *linear_memory = wasm_memory_pool_remove_nolock(&module->pools[global_worker_thread_idx].memory); if (linear_memory == NULL) { linear_memory = wasm_memory_alloc(starting_bytes, max_bytes); if (unlikely(linear_memory == NULL)) return NULL; @@ -215,7 +215,7 @@ static inline void module_free_linear_memory(struct module *module, struct wasm_memory *memory) { wasm_memory_reinit(memory, module->abi.starting_pages * WASM_PAGE_SIZE); - wasm_memory_pool_add_nolock(&module->pools[worker_thread_idx].memory, memory); + wasm_memory_pool_add_nolock(&module->pools[global_worker_thread_idx].memory, memory); } static inline void diff --git a/runtime/include/request_typed_queue.h b/runtime/include/request_typed_queue.h index 0e444db05..ec121bcfc 100644 --- a/runtime/include/request_typed_queue.h +++ b/runtime/include/request_typed_queue.h @@ -1,4 +1,6 @@ #pragma once +#include +#include #define RQUEUE_LEN 4096 #define MAX_WORKERS 32 @@ -17,7 +19,7 @@ struct request_typed_queue { double ratio; struct sandbox *rqueue[RQUEUE_LEN]; unsigned int rqueue_tail; - unsigned int rqueue_head; + _Atomic unsigned int rqueue_head; uint64_t tsqueue[RQUEUE_LEN]; // Profiling variables @@ -36,54 +38,11 @@ struct request_typed_queue { uint64_t max_delay; double prev_demand; - /*RequestType(enum ReqType type, uint64_t mean_ns, uint64_t deadline, double ratio) : - type(type), mean_ns(mean_ns), deadline(deadline), ratio(ratio) { - //There must be a way to 0-init an C array from initializer list - memset(rqueue, 0, RQUEUE_LEN * sizeof(unsigned long)); - rqueue_tail = 0; - rqueue_head = 0; - }; - */ }; /* * n_resas the number of reserved workers. Leaving the last n_resas workers as the reserved workers */ -static inline struct request_typed_queue * -request_typed_queue_init(uint8_t type, uint32_t n_resas) { - struct request_typed_queue *queue = malloc(sizeof(struct request_typed_queue)); - queue->type = type; - queue->mean_ns = 0; - queue->deadline = 0; - queue->rqueue_tail = 0; - queue->rqueue_head = 0; - queue->n_resas = n_resas; - for (unsigned int i = 0; i < n_resas; ++i) { - queue->res_workers[i] = i; - } - - queue->n_stealable = runtime_worker_group_size - n_resas; - int index = 0; - for (unsigned int i = n_resas; i < runtime_worker_group_size; i++) { - queue->stealable_workers[index] = i; - index++; - } - - memset(queue->rqueue, 0, RQUEUE_LEN * sizeof(struct sandbox*)); - - return queue; - -} - -static inline int push_to_rqueue(struct sandbox *sandbox, struct request_typed_queue *rtype, uint64_t tsc) { - if (unlikely(rtype->rqueue_head - rtype->rqueue_tail == RQUEUE_LEN)) { - panic("Dispatcher dropped request as type %hhu because queue is full\n", rtype->type); - return -1; - } else { - //PSP_DEBUG("Pushed one request to queue " << req_type_str[static_cast(rtype.type)]); - rtype->tsqueue[rtype->rqueue_head & (RQUEUE_LEN - 1)] = tsc; - rtype->rqueue[rtype->rqueue_head++ & (RQUEUE_LEN - 1)] = sandbox; - return 0; - } -} +struct request_typed_queue * request_typed_queue_init(uint8_t type, uint32_t n_resas); +int push_to_rqueue(struct sandbox *sandbox, struct request_typed_queue *rtype, uint64_t tsc); diff --git a/runtime/include/route.h b/runtime/include/route.h index c549de089..374a230ee 100644 --- a/runtime/include/route.h +++ b/runtime/include/route.h @@ -11,13 +11,13 @@ /* Assumption: entrypoint is always _start. This should be enhanced later */ struct route { char *route; - uint8_t request_type; + uint8_t request_type; struct http_route_total metrics; struct module *module; /* HTTP State */ - uint32_t relative_deadline_us; - uint64_t relative_deadline; /* cycles */ - char *response_content_type; - struct admissions_info admissions_info; - struct perf_window latency; + uint32_t relative_deadline_us; + uint64_t relative_deadline; /* cycles */ + char *response_content_type; + struct admissions_info admissions_info; + struct perf_window latency; }; diff --git a/runtime/include/sandbox_perf_log.h b/runtime/include/sandbox_perf_log.h index a770b585b..17f830ef8 100644 --- a/runtime/include/sandbox_perf_log.h +++ b/runtime/include/sandbox_perf_log.h @@ -6,7 +6,7 @@ #include "memlogging.h" extern FILE *sandbox_perf_log; -extern thread_local int worker_thread_idx; +extern thread_local int global_worker_thread_idx; /** * @brief Prints headers for the per-sandbox perf logs @@ -54,10 +54,10 @@ sandbox_perf_log_print_entry(struct sandbox *sandbox) uint64_t init_time = sandbox->duration_of_state[SANDBOX_INITIALIZED] / runtime_processor_speed_MHz; if (miss_deadline) { - mem_log("tid %d %u miss %lu %lu %lu %s %lu %lu f%d %lu %lu %lu %lu %lu %lu\n", worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route, + mem_log("tid %d %u miss %lu %lu %lu %s %lu %lu f%d %lu %lu %lu %lu %lu %lu\n", global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route, init_time, cleanup, sandbox->context_switch_to, other, t1,t2,t3,t4,t5); } else { - mem_log("tid %d %u meet %lu %lu %lu %s %lu %lu f%d %lu %lu %lu %lu %lu %lu\n", worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route, + mem_log("tid %d %u meet %lu %lu %lu %s %lu %lu f%d %lu %lu %lu %lu %lu %lu\n", global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route, init_time, cleanup, sandbox->context_switch_to, other, t1,t2,t3,t4,t5); } /* diff --git a/runtime/include/sandbox_set_as_returned.h b/runtime/include/sandbox_set_as_returned.h index c5a3f4a4a..dfe0ed7bc 100644 --- a/runtime/include/sandbox_set_as_returned.h +++ b/runtime/include/sandbox_set_as_returned.h @@ -15,7 +15,7 @@ #include "sandbox_types.h" extern struct sandbox* current_sandboxes[1024]; -extern thread_local int worker_thread_idx; +extern thread_local int global_worker_thread_idx; /** * Transitions a sandbox to the SANDBOX_RETURNED state. * This occurs when a sandbox is executing and runs to completion. @@ -35,7 +35,7 @@ sandbox_set_as_returned(struct sandbox *sandbox, sandbox_state_t last_state) switch (last_state) { case SANDBOX_RUNNING_SYS: { local_runqueue_delete(sandbox); - current_sandboxes[worker_thread_idx] = NULL; + current_sandboxes[global_worker_thread_idx] = NULL; sandbox_free_linear_memory(sandbox); break; } diff --git a/runtime/include/sandbox_set_as_running_sys.h b/runtime/include/sandbox_set_as_running_sys.h index 5c00013aa..a77a69788 100644 --- a/runtime/include/sandbox_set_as_running_sys.h +++ b/runtime/include/sandbox_set_as_running_sys.h @@ -25,7 +25,7 @@ sandbox_set_as_running_sys(struct sandbox *sandbox, sandbox_state_t last_state) switch (last_state) { case SANDBOX_RUNNING_USER: { assert(sandbox == current_sandbox_get()); - assert(runtime_worker_threads_deadline[worker_thread_idx] == sandbox->absolute_deadline); + assert(runtime_worker_threads_deadline[global_worker_thread_idx] == sandbox->absolute_deadline); break; } case SANDBOX_RUNNABLE: { diff --git a/runtime/include/sandbox_set_as_running_user.h b/runtime/include/sandbox_set_as_running_user.h index bf6ade7ac..3d784fc6b 100644 --- a/runtime/include/sandbox_set_as_running_user.h +++ b/runtime/include/sandbox_set_as_running_user.h @@ -21,7 +21,7 @@ sandbox_set_as_running_user(struct sandbox *sandbox, sandbox_state_t last_state) switch (last_state) { case SANDBOX_RUNNING_SYS: { assert(sandbox == current_sandbox_get()); - assert(runtime_worker_threads_deadline[worker_thread_idx] == sandbox->absolute_deadline); + assert(runtime_worker_threads_deadline[global_worker_thread_idx] == sandbox->absolute_deadline); break; } case SANDBOX_PREEMPTED: { diff --git a/runtime/include/sandbox_types.h b/runtime/include/sandbox_types.h index 34e9a94e3..8b97220ee 100644 --- a/runtime/include/sandbox_types.h +++ b/runtime/include/sandbox_types.h @@ -83,4 +83,7 @@ struct sandbox { int context_switch_to; /* 1 means context switch to base, 2 means context swtich to next sandbox */ uint64_t ret[5]; uint64_t estimated_cost; /* estimated execution cost */ + int global_worker_thread_idx; /* which thread in a global view processes this sandbox. + pause and restore the sandbox must be done in the same thread */ + int group_worker_thread_idx; /* what's the thread index in the group */ } PAGE_ALIGNED; diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index abe34ed64..0f2dc47ae 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -25,10 +25,14 @@ #include "sandbox_set_as_running_user.h" #include "scheduler_options.h" #include "sandbox_perf_log.h" +#include "request_typed_queue.h" +#include "listener_thread.h" extern thread_local bool pthread_stop; extern uint32_t runtime_worker_group_size; extern _Atomic uint32_t free_workers[10]; +extern thread_local int dispatcher_id; +extern struct request_typed_queue *request_type_queue[MAX_DISPATCHER][MAX_REQUEST_TYPE]; /** * This scheduler provides for cooperative and preemptive multitasking in a OS process's userspace. * @@ -82,7 +86,7 @@ scheduler_mtds_get_next() enum MULTI_TENANCY_CLASS local_mt_class = MT_DEFAULT; struct sandbox *global = NULL; - if (local) local_mt_class = local->tenant->pwt_sandboxes[worker_thread_idx].mt_class; + if (local) local_mt_class = local->tenant->pwt_sandboxes[global_worker_thread_idx].mt_class; uint64_t global_guaranteed_deadline = global_request_scheduler_mtds_guaranteed_peek(); uint64_t global_default_deadline = global_request_scheduler_mtds_default_peek(); @@ -126,6 +130,7 @@ scheduler_edf_get_next() local->timestamp_of.last_state_change = now; /* end by xiaosu */ sandbox_prepare_execution_environment(local); + //printf("sandbox state %d\n", local->state); assert(local->state == SANDBOX_INITIALIZED); sandbox_set_as_runnable(local, SANDBOX_INITIALIZED); } @@ -319,9 +324,13 @@ scheduler_preemptive_sched(ucontext_t *interrupted_context) struct sandbox *interrupted_sandbox = current_sandbox_get(); assert(interrupted_sandbox != NULL); assert(interrupted_sandbox->state == SANDBOX_INTERRUPTED); - // printf ("Worker #%d interrupted sandbox #%lu\n", worker_thread_idx, interrupted_sandbox->id); + // printf ("Worker #%d interrupted sandbox #%lu\n", global_worker_thread_idx, interrupted_sandbox->id); scheduler_process_policy_specific_updates_on_interrupts(interrupted_sandbox); + /* Delete current sandbox from local queue if dispatcher is DISPATCHER_SHINJUKU */ + if (dispatcher == DISPATCHER_SHINJUKU) { + local_runqueue_delete(interrupted_sandbox); + } struct sandbox *next = scheduler_get_next(); /* Assumption: the current sandbox is on the runqueue, so the scheduler should always return something */ assert(next != NULL); @@ -343,8 +352,12 @@ scheduler_preemptive_sched(ucontext_t *interrupted_context) // Write back global at idx 0 wasm_globals_set_i64(&interrupted_sandbox->globals, 0, sledge_abi__current_wasm_module_instance.abi.wasmg_0, true); - arch_context_save_slow(&interrupted_sandbox->ctxt, &interrupted_context->uc_mcontext); + + if (dispatcher == DISPATCHER_SHINJUKU) { + int req_type = interrupted_sandbox->route->request_type; + push_to_rqueue(interrupted_sandbox, request_type_queue[dispatcher_id][req_type - 1], __getcycles()); + } scheduler_preemptive_switch_to(interrupted_context, next); } @@ -456,7 +469,7 @@ scheduler_cooperative_sched(bool add_to_cleanup_queue) struct sandbox *exiting_sandbox = current_sandbox_get(); assert(exiting_sandbox != NULL); - uint8_t dispatcher_id = exiting_sandbox->rpc_id; + //uint8_t dispatcher_id = exiting_sandbox->rpc_id; /* Clearing current sandbox indicates we are entering the cooperative scheduler */ current_sandbox_set(NULL); @@ -503,15 +516,16 @@ scheduler_cooperative_sched(bool add_to_cleanup_queue) /* Logging this sandbox to memory */ sandbox_perf_log_print_entry(exiting_sandbox); - if (dispatcher == DISPATCHER_DARC) { - int virtual_id = worker_thread_idx - dispatcher_id * runtime_worker_group_size; - atomic_fetch_or(&free_workers[dispatcher_id], 1 << virtual_id); - } if (next_sandbox != NULL) { next_sandbox->context_switch_to = 2; scheduler_cooperative_switch_to(exiting_context, next_sandbox); } else { + if (dispatcher == DISPATCHER_DARC || dispatcher == DISPATCHER_SHINJUKU) { + int virtual_id = global_worker_thread_idx - dispatcher_id * runtime_worker_group_size; + atomic_fetch_or(&free_workers[dispatcher_id], 1 << virtual_id); + } + //printf("finish one request\n"); scheduler_switch_to_base_context(exiting_context); } } diff --git a/runtime/include/software_interrupt_counts.h b/runtime/include/software_interrupt_counts.h index 9daa5afe5..ed6d72d3a 100644 --- a/runtime/include/software_interrupt_counts.h +++ b/runtime/include/software_interrupt_counts.h @@ -46,8 +46,8 @@ static inline void software_interrupt_counts_deferred_sigalrm_max_update(int deferred_sigalrm_count) { #ifdef LOG_SOFTWARE_INTERRUPT_COUNTS - if (unlikely(deferred_sigalrm_count > software_interrupt_counts_deferred_sigalrm_max[worker_thread_idx])) { - software_interrupt_counts_deferred_sigalrm_max[worker_thread_idx] = deferred_sigalrm_count; + if (unlikely(deferred_sigalrm_count > software_interrupt_counts_deferred_sigalrm_max[global_worker_thread_idx])) { + software_interrupt_counts_deferred_sigalrm_max[global_worker_thread_idx] = deferred_sigalrm_count; } #endif } @@ -56,7 +56,7 @@ static inline void software_interrupt_counts_deferred_sigalrm_replay_increment() { #ifdef LOG_SOFTWARE_INTERRUPT_COUNTS - atomic_fetch_add(&software_interrupt_counts_deferred_sigalrm_replay[worker_thread_idx], 1); + atomic_fetch_add(&software_interrupt_counts_deferred_sigalrm_replay[global_worker_thread_idx], 1); #endif } @@ -64,7 +64,7 @@ static inline void software_interrupt_counts_sigalrm_kernel_increment() { #ifdef LOG_SOFTWARE_INTERRUPT_COUNTS - atomic_fetch_add(&software_interrupt_counts_sigalrm_kernel[worker_thread_idx], 1); + atomic_fetch_add(&software_interrupt_counts_sigalrm_kernel[global_worker_thread_idx], 1); #endif } @@ -72,7 +72,7 @@ static inline void software_interrupt_counts_sigalrm_thread_increment() { #ifdef LOG_SOFTWARE_INTERRUPT_COUNTS - atomic_fetch_add(&software_interrupt_counts_sigalrm_thread[worker_thread_idx], 1); + atomic_fetch_add(&software_interrupt_counts_sigalrm_thread[global_worker_thread_idx], 1); #endif } @@ -80,7 +80,7 @@ static inline void software_interrupt_counts_sigfpe_increment() { #ifdef LOG_SOFTWARE_INTERRUPT_COUNTS - atomic_fetch_add(&software_interrupt_counts_sigfpe[worker_thread_idx], 1); + atomic_fetch_add(&software_interrupt_counts_sigfpe[global_worker_thread_idx], 1); #endif } @@ -88,7 +88,7 @@ static inline void software_interrupt_counts_sigsegv_increment() { #ifdef LOG_SOFTWARE_INTERRUPT_COUNTS - atomic_fetch_add(&software_interrupt_counts_sigsegv[worker_thread_idx], 1); + atomic_fetch_add(&software_interrupt_counts_sigsegv[global_worker_thread_idx], 1); #endif } @@ -96,7 +96,7 @@ static inline void software_interrupt_counts_sigusr_increment() { #ifdef LOG_SOFTWARE_INTERRUPT_COUNTS - atomic_fetch_add(&software_interrupt_counts_sigusr[worker_thread_idx], 1); + atomic_fetch_add(&software_interrupt_counts_sigusr[global_worker_thread_idx], 1); #endif } diff --git a/runtime/include/tenant_functions.h b/runtime/include/tenant_functions.h index 465c655bf..ec46d9d9d 100644 --- a/runtime/include/tenant_functions.h +++ b/runtime/include/tenant_functions.h @@ -17,9 +17,11 @@ #include "memlogging.h" extern thread_local uint32_t n_rtypes; -extern thread_local struct request_typed_queue *request_type_queue[10]; +//extern thread_local struct request_typed_queue *request_type_queue[10]; +extern thread_local uint8_t dispatcher_thread_idx; +extern struct request_typed_queue *request_type_queue[MAX_DISPATCHER][MAX_REQUEST_TYPE]; extern thread_local struct perf_window perf_window_per_thread[1024]; -extern thread_local int worker_thread_idx; +extern thread_local int global_worker_thread_idx; int tenant_database_add(struct tenant *tenant); struct tenant *tenant_database_find_by_name(char *name); @@ -190,7 +192,7 @@ tenant_perf_window_init(struct tenant *tenant, void *arg1, void *arg2) { static inline void tenant_request_typed_queue_init(struct tenant *tenant, void *arg1, void *arg2) { for(int i = 0; i < tenant->routes_len; i++) { - request_type_queue[tenant->routes_config[i].request_type - 1] = + request_type_queue[dispatcher_thread_idx][tenant->routes_config[i].request_type - 1] = request_typed_queue_init(tenant->routes_config[i].request_type, tenant->routes_config[i].n_resas); } n_rtypes = tenant->routes_len; @@ -199,6 +201,6 @@ tenant_request_typed_queue_init(struct tenant *tenant, void *arg1, void *arg2) { static inline void tenat_perf_window_print_mean(struct tenant *tenant, void *arg1, void *arg2) { for(int i = 0; i < tenant->router.length; i++) { - mem_log("tid %d admssion id %u exec mean %lu\n", worker_thread_idx, i, perf_window_get_mean(&perf_window_per_thread[i])); + mem_log("tid %d admssion id %u exec mean %lu\n", global_worker_thread_idx, i, perf_window_get_mean(&perf_window_per_thread[i])); } } diff --git a/runtime/include/worker_thread.h b/runtime/include/worker_thread.h index c006f3812..de435ab70 100644 --- a/runtime/include/worker_thread.h +++ b/runtime/include/worker_thread.h @@ -5,6 +5,6 @@ #include "runtime.h" extern thread_local struct arch_context worker_thread_base_context; -extern thread_local int worker_thread_idx; +extern thread_local int global_worker_thread_idx; void *worker_thread_main(void *return_code); diff --git a/runtime/src/arch_context.c b/runtime/src/arch_context.c index c359927d6..1fd5df02e 100644 --- a/runtime/src/arch_context.c +++ b/runtime/src/arch_context.c @@ -14,6 +14,7 @@ */ noreturn void __attribute__((noinline)) arch_context_restore_preempted(void) { - pthread_kill(pthread_self(), SIGUSR1); + pthread_t tid = pthread_self(); + pthread_kill(tid, SIGUSR1); panic("Unexpectedly reached code after sending self SIGUSR1\n"); } diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 09a3b1144..bea88407b 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -27,15 +27,18 @@ extern uint32_t runtime_worker_threads_count; extern thread_local bool pthread_stop; extern _Atomic uint64_t request_index; extern uint32_t runtime_worker_group_size; +extern struct sandbox* current_sandboxes[1024]; thread_local uint32_t worker_start_id; thread_local uint32_t worker_end_id; -thread_local uint32_t worker_list[MAX_WORKERS]; // record the worker's true index -_Atomic uint32_t free_workers[10] = {0}; // the index is the dispatercher id, free_workers[dispatcher_id] +thread_local uint32_t worker_list[MAX_WORKERS]; // record the worker's true id(0 - N workers - 1). worker_list[0] - worker_list[2] +_Atomic uint32_t free_workers[MAX_DISPATCHER] = {0}; // the index is the dispatercher id, free_workers[dispatcher_id] // is decimal value of the bitmap of avaliable workers. // For example, if there are 3 workers available, the bitmap // will be 111, then the free_workers[dispatcher_id] is 7 -thread_local struct request_typed_queue *request_type_queue[10]; // the index is the request type + + +/*thread_local struct request_typed_queue *request_type_queue[MAX_REQUEST_TYPE]; // the index is the request type // We implicitly represent the request // execution time as long or short based // on the value of the request type. @@ -43,6 +46,9 @@ thread_local struct request_typed_queue *request_type_queue[10]; // the index is // request with type 1 is shorter than request // with type 2, that's reducing the sorting // cost of the typed queue +*/ +struct request_typed_queue *request_type_queue[MAX_DISPATCHER][MAX_REQUEST_TYPE]; + thread_local uint32_t n_rtypes = 0; time_t t_start; @@ -86,7 +92,7 @@ listener_thread_initialize(uint8_t thread_id) cpu_set_t cs; CPU_ZERO(&cs); - CPU_SET(LISTENER_THREAD_CORE_ID + thread_id, &cs); + CPU_SET(LISTENER_THREAD_START_CORE_ID + thread_id, &cs); /* Setup epoll */ listener_thread_epoll_file_descriptor = epoll_create1(0); @@ -446,41 +452,41 @@ on_client_socket_epoll_event(struct epoll_event *evt) void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { if (first_request_comming == false){ - t_start = time(NULL); - first_request_comming = true; - } + t_start = time(NULL); + first_request_comming = true; + } uint8_t kMsgSize = 16; //TODO: rpc_id is hardcode now struct tenant *tenant = tenant_database_find_by_port(port); assert(tenant != NULL); - struct route *route = http_router_match_request_type(&tenant->router, req_type); - if (route == NULL) { - debuglog("Did not match any routes\n"); + struct route *route = http_router_match_request_type(&tenant->router, req_type); + if (route == NULL) { + debuglog("Did not match any routes\n"); dispatcher_send_response(req_handle, DIPATCH_ROUNTE_ERROR, strlen(DIPATCH_ROUNTE_ERROR)); - return; - } + return; + } - /* - * Perform admissions control. - * If 0, workload was rejected, so close with 429 "Too Many Requests" and continue - * TODO: Consider providing a Retry-After header - */ - uint64_t work_admitted = admissions_control_decide(route->admissions_info.estimate); - if (work_admitted == 0) { - dispatcher_send_response(req_handle, WORK_ADMITTED_ERROR, strlen(WORK_ADMITTED_ERROR)); - return; - } + /* + * Perform admissions control. + * If 0, workload was rejected, so close with 429 "Too Many Requests" and continue + * TODO: Consider providing a Retry-After header + */ + uint64_t work_admitted = admissions_control_decide(route->admissions_info.estimate); + if (work_admitted == 0) { + dispatcher_send_response(req_handle, WORK_ADMITTED_ERROR, strlen(WORK_ADMITTED_ERROR)); + return; + } - /* Allocate a Sandbox */ - //session->state = HTTP_SESSION_EXECUTING; - struct sandbox *sandbox = sandbox_alloc(route->module, NULL, route, tenant, work_admitted, req_handle, dispatcher_thread_idx); - if (unlikely(sandbox == NULL)) { - debuglog("Failed to allocate sandbox\n"); + /* Allocate a Sandbox */ + //session->state = HTTP_SESSION_EXECUTING; + struct sandbox *sandbox = sandbox_alloc(route->module, NULL, route, tenant, work_admitted, req_handle, dispatcher_thread_idx); + if (unlikely(sandbox == NULL)) { + debuglog("Failed to allocate sandbox\n"); dispatcher_send_response(req_handle, SANDBOX_ALLOCATION_ERROR, strlen(SANDBOX_ALLOCATION_ERROR)); - return; - } + return; + } /* copy the received data since it will be released by erpc */ sandbox->rpc_request_body = malloc(size); @@ -536,7 +542,7 @@ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, * @param msg the payload of the rpc request. It is the input parameter fot the function * @param size the size of the msg */ -void darc_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { +void darc_shinjuku_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { if (first_request_comming == false){ t_start = time(NULL); first_request_comming = true; @@ -582,7 +588,7 @@ void darc_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t s memcpy(sandbox->rpc_request_body, msg, size); sandbox->rpc_request_body_size = size; - push_to_rqueue(sandbox, request_type_queue[req_type - 1], 0); + push_to_rqueue(sandbox, request_type_queue[dispatcher_thread_idx][req_type - 1], __getcycles()); } @@ -618,22 +624,156 @@ void drain_queue(struct request_typed_queue *rtype) { // Dispatch struct sandbox *sandbox = rtype->rqueue[rtype->rqueue_tail & (RQUEUE_LEN - 1)]; - //add sandbox to worker's local queue - local_runqueue_add_index(worker_list[worker_id], sandbox); - rtype->rqueue_tail++; - atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << worker_id); + //add sandbox to worker's local queue + local_runqueue_add_index(worker_list[worker_id], sandbox); + rtype->rqueue_tail++; + atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << worker_id); + } + +} + +/* Return selected sandbox and selected queue type */ +struct sandbox * shinjuku_peek_selected_sandbox(int *selected_queue_idx) { + float highest_priority = 0; + *selected_queue_idx = -1; + struct sandbox *selected_sandbox = NULL; + + for (uint32_t i = 0; i < n_rtypes; ++i) { + if (request_type_queue[dispatcher_thread_idx][i]->rqueue_head > request_type_queue[dispatcher_thread_idx][i]->rqueue_tail) { + //get the tail sandbox of the queue + struct sandbox *sandbox = request_type_queue[dispatcher_thread_idx][i]->rqueue[request_type_queue[dispatcher_thread_idx][i]->rqueue_tail & (RQUEUE_LEN - 1)]; + uint64_t ts = request_type_queue[dispatcher_thread_idx][i]->tsqueue[request_type_queue[dispatcher_thread_idx][i]->rqueue_tail & (RQUEUE_LEN - 1)]; + uint64_t dt = __getcycles() - ts; + float priority = (float)dt / (float)sandbox->route->relative_deadline; + if (priority > highest_priority) { + highest_priority = priority; + *selected_queue_idx = i; + selected_sandbox = sandbox; + } + } } + return selected_sandbox; + +} + +void shinjuku_dequeue_selected_sandbox(int selected_queue_type) { + assert(selected_queue_type >= 0 && selected_queue_type < MAX_REQUEST_TYPE); + request_type_queue[dispatcher_thread_idx][selected_queue_type]->rqueue_tail++; } void darc_dispatch() { for (uint32_t i = 0; i < n_rtypes; ++i) { // request_type_queue is a sorted queue, so the loop will dispatch packets from // the earliest deadline to least earliest deadline - if (request_type_queue[i]->rqueue_head > request_type_queue[i]->rqueue_tail) { - drain_queue(request_type_queue[i]); + if (request_type_queue[dispatcher_thread_idx][i]->rqueue_head > request_type_queue[dispatcher_thread_idx][i]->rqueue_tail) { + drain_queue(request_type_queue[dispatcher_thread_idx][i]); + } + } +} + +/*void shinjuku_dispatch() { + for (uint32_t i = 0; i < runtime_worker_group_size; ++i) { + if ((1 << i) & free_workers[dispatcher_thread_idx]) { + struct sandbox *sandbox = shinjuku_select_sandbox(); + if (sandbox) { + local_runqueue_add_index(worker_list[i], sandbox); + atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << i); + } else { + // queue is empty, exit loop + break; + } + } else { // core is busy + //check if the current sandbox is running longer than the specified time duration + struct sandbox *current = current_sandboxes[worker_list[i]]; + if (!current) continue; // In case that worker thread hasn't call current_sandbox_set to set the current sandbox + uint64_t duration = (__getcycles() - current->timestamp_of.last_state_change) / runtime_processor_speed_MHz; + if (duration >= 10 && current->state == SANDBOX_RUNNING_USER) { + //preempt the current sandbox and put it back the typed queue, select a new one to send to it + struct sandbox *sandbox = shinjuku_select_sandbox(); + if (sandbox) { + local_runqueue_add_index(worker_list[i], sandbox); + //preempt worker + preempt_worker(worker_list[i]); + atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << i); + } else { + // queue is empty, exit loop + break; + } + } + } + } +}*/ + +void shinjuku_dispatch() { + + while (true) { + int selected_queue_type; + struct sandbox *sandbox = shinjuku_peek_selected_sandbox(&selected_queue_type); + + /* This sandbox was preempted by a worker thread, re-dispatch it to the same worker thread + * no matter if it is free + */ + if (sandbox && sandbox->global_worker_thread_idx != -1) { + assert(selected_queue_type != -1); + //printf("dispatch %p to worker %d\n", sandbox, sandbox->global_worker_thread_idx); + local_runqueue_add_index(sandbox->global_worker_thread_idx, sandbox); + shinjuku_dequeue_selected_sandbox(selected_queue_type); + } else if (sandbox && sandbox->global_worker_thread_idx == -1) { + if (free_workers[dispatcher_thread_idx] == 0) { + /* No available workers, return */ + return; + } else { + for (uint32_t i = 0; i < runtime_worker_group_size; ++i) { + if ((1 << i) & free_workers[dispatcher_thread_idx]) { + local_runqueue_add_index(worker_list[i], sandbox); + atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << i); + shinjuku_dequeue_selected_sandbox(selected_queue_type); + break; + } else { // core is busy + //check if the current sandbox is running longer than the specified time duration + struct sandbox *current = current_sandboxes[worker_list[i]]; + if (!current) continue; // TODO????? In case that worker thread hasn't call current_sandbox_set to set the current sandbox + uint64_t duration = (__getcycles() - current->timestamp_of.last_state_change) / runtime_processor_speed_MHz; + if (duration >= 100 && current->state == SANDBOX_RUNNING_USER) { + //preempt the current sandbox and put it back the typed queue, select a new one to send to it + local_runqueue_add_index(worker_list[i], sandbox); + //preempt worker + preempt_worker(worker_list[i]); + shinjuku_dequeue_selected_sandbox(selected_queue_type); + break; + } + } + } } + } else { + /* typed queues are empty, return */ + return; } + } +} + +void shinjuku_dispatch_test() { + while(true) { + int selected_queue_type = 0; + struct sandbox *sandbox = shinjuku_peek_selected_sandbox(&selected_queue_type); + if (sandbox) { + assert(sandbox->state == SANDBOX_INITIALIZED); + if (free_workers[dispatcher_thread_idx] == 0) { + return; + } + for (uint32_t i = 0; i < runtime_worker_group_size; ++i) { + if ((1 << i) & free_workers[dispatcher_thread_idx]) { + local_runqueue_add_index(worker_list[i], sandbox); + atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << i); + shinjuku_dequeue_selected_sandbox(selected_queue_type); + break; + } + } + } else { + return; + } + } } void dispatcher_send_response(void *req_handle, char* msg, size_t msg_len) { @@ -652,15 +792,16 @@ void dispatcher_send_response(void *req_handle, char* msg, size_t msg_len) { void * listener_thread_main(void *dummy) { - /* init typed queue */ - typed_queue_init(); - is_listener = true; /* Unmask SIGINT signals */ - software_interrupt_unmask_signal(SIGINT); + software_interrupt_unmask_signal(SIGINT); /* Index was passed via argument */ - dispatcher_thread_idx = *(int *)dummy; + dispatcher_thread_idx = *(int *)dummy; + + printf("listener thread, id %d\n", dispatcher_thread_idx); + /* init typed queue */ + typed_queue_init(); /* calucate the worker start and end id for this listener */ worker_start_id = dispatcher_thread_idx * runtime_worker_group_size; @@ -688,15 +829,23 @@ listener_thread_main(void *dummy) erpc_start(NULL, dispatcher_thread_idx, NULL, 0); - if (dispatcher == DISPATCHER_EDF_INTERRUPT) { + if (dispatcher == DISPATCHER_EDF_INTERRUPT) { + printf("edf_interrupt....\n"); while (!pthread_stop) { erpc_run_event_loop(dispatcher_thread_idx, 1000); } } else if (dispatcher == DISPATCHER_DARC) { + printf("darc....\n"); while (!pthread_stop) { erpc_run_event_loop_once(dispatcher_thread_idx); // get a group of packets from the NIC and enqueue them to the typed queue darc_dispatch(); //dispatch packets } + } else if (dispatcher == DISPATCHER_SHINJUKU) { + printf("shinjuku....\n"); + while (!pthread_stop) { + erpc_run_event_loop_once(dispatcher_thread_idx); // get a group of packets from the NIC and enqueue them to the typed queue + shinjuku_dispatch(); //dispatch packets + } } /* won't go to the following implementaion */ diff --git a/runtime/src/local_runqueue_binary_tree.c b/runtime/src/local_runqueue_binary_tree.c index 49b8b5618..ba28ba6d8 100644 --- a/runtime/src/local_runqueue_binary_tree.c +++ b/runtime/src/local_runqueue_binary_tree.c @@ -13,7 +13,7 @@ #include "sandbox_functions.h" #include "runtime.h" -extern thread_local int worker_thread_idx; +extern thread_local int global_worker_thread_idx; extern struct perf_window * worker_perf_windows[1024]; /* index is thread id, each queue's perf windows, each queue can have multiple perf windows */ extern struct sandbox* current_sandboxes[1024]; @@ -131,7 +131,7 @@ local_runqueue_binary_tree_initialize() /* Initialize local state */ local_runqueue_binary_tree = init_binary_tree(true, sandbox_get_priority, sandbox_get_execution_cost); - worker_binary_trees[worker_thread_idx] = local_runqueue_binary_tree; + worker_binary_trees[global_worker_thread_idx] = local_runqueue_binary_tree; /* Register Function Pointers for Abstract Scheduling API */ struct local_runqueue_config config = { .add_fn = local_runqueue_binary_tree_add, .add_fn_idx = local_runqueue_binary_tree_add_index, diff --git a/runtime/src/local_runqueue_minheap.c b/runtime/src/local_runqueue_minheap.c index 687818ddd..8398ff220 100644 --- a/runtime/src/local_runqueue_minheap.c +++ b/runtime/src/local_runqueue_minheap.c @@ -13,7 +13,7 @@ #include "runtime.h" extern struct priority_queue* worker_queues[1024]; -extern thread_local int worker_thread_idx; +extern thread_local int global_worker_thread_idx; _Atomic uint64_t worker_queuing_cost[1024]; /* index is thread id, each queue's total execution cost of queuing requests */ extern struct perf_window * worker_perf_windows[1024]; /* index is thread id, each queue's perf windows, each queue can have multiple perf windows */ @@ -74,7 +74,7 @@ local_runqueue_minheap_delete(struct sandbox *sandbox) int rc = priority_queue_delete(local_runqueue_minheap, sandbox); if (rc == -1) panic("Tried to delete sandbox %lu from runqueue, but was not present\n", sandbox->id); - worker_queuing_cost_decrement(worker_thread_idx, sandbox->estimated_cost); + worker_queuing_cost_decrement(global_worker_thread_idx, sandbox->estimated_cost); } /** @@ -105,7 +105,7 @@ local_runqueue_minheap_initialize() /* Initialize local state */ local_runqueue_minheap = priority_queue_initialize(RUNTIME_RUNQUEUE_SIZE, true, sandbox_get_priority); - worker_queues[worker_thread_idx] = local_runqueue_minheap; + worker_queues[global_worker_thread_idx] = local_runqueue_minheap; /* Register Function Pointers for Abstract Scheduling API */ struct local_runqueue_config config = { .add_fn = local_runqueue_minheap_add, .add_fn_idx = local_runqueue_minheap_add_index, diff --git a/runtime/src/local_runqueue_mtds.c b/runtime/src/local_runqueue_mtds.c index 6f7c0ca5c..e4ea3c94e 100644 --- a/runtime/src/local_runqueue_mtds.c +++ b/runtime/src/local_runqueue_mtds.c @@ -53,7 +53,7 @@ local_runqueue_mtds_add(struct sandbox *sandbox) { assert(sandbox != NULL); - struct perworker_tenant_sandbox_queue *pwt = &sandbox->tenant->pwt_sandboxes[worker_thread_idx]; + struct perworker_tenant_sandbox_queue *pwt = &sandbox->tenant->pwt_sandboxes[global_worker_thread_idx]; struct priority_queue *destination_queue = pwt->mt_class == MT_GUARANTEED ? local_runqueue_mtds_guaranteed : local_runqueue_mtds_default; @@ -96,7 +96,7 @@ static void local_runqueue_mtds_delete(struct sandbox *sandbox) { assert(sandbox != NULL); - struct perworker_tenant_sandbox_queue *pwt = &sandbox->tenant->pwt_sandboxes[worker_thread_idx]; + struct perworker_tenant_sandbox_queue *pwt = &sandbox->tenant->pwt_sandboxes[global_worker_thread_idx]; /* Delete the sandbox from the corresponding Per-Worker-Tenant queue */ if (priority_queue_delete_nolock(pwt->sandboxes, sandbox) == -1) { diff --git a/runtime/src/main.c b/runtime/src/main.c index 7937e0c46..52f143b8a 100644 --- a/runtime/src/main.c +++ b/runtime/src/main.c @@ -102,7 +102,7 @@ runtime_allocate_available_cores() runtime_worker_threads_count = max_possible_workers; } - pretty_print_key_value("Listener core ID", "%u\n", LISTENER_THREAD_CORE_ID); + pretty_print_key_value("Listener start core ID", "%u\n", LISTENER_THREAD_START_CORE_ID); pretty_print_key_value("First Worker core ID", "%u\n", runtime_first_worker_processor); pretty_print_key_value("Worker core count", "%u\n", runtime_worker_threads_count); } @@ -261,8 +261,10 @@ runtime_configure() dispatcher = DISPATCHER_DARC; } else if (strcmp(dispatcher_policy, "EDF_INTERRUPT") == 0) { dispatcher = DISPATCHER_EDF_INTERRUPT; - } else { - panic("Invalid dispatcher policy: %s. Must be {EDF_INTERRUPT|DARC\n", dispatcher_policy); + } else if (strcmp(dispatcher_policy, "SHINJUKU") == 0) { + dispatcher = DISPATCHER_SHINJUKU; + } else { + panic("Invalid dispatcher policy: %s. Must be {EDF_INTERRUPT|DARC|SHINJUKU\n", dispatcher_policy); } pretty_print_key_value("Dispatcher Policy", "%s\n", dispatcher_print(dispatcher)); @@ -573,20 +575,15 @@ main(int argc, char **argv) } } + runtime_get_listener_count(); + runtime_get_worker_group_size(); runtime_start_runtime_worker_threads(); software_interrupt_arm_timer(); - runtime_get_listener_count(); - runtime_get_worker_group_size(); listener_threads_initialize(); runtime_boot_timestamp = __getcycles(); - for (int tenant_idx = 0; tenant_idx < tenant_config_vec_len; tenant_idx++) { - tenant_config_deinit(&tenant_config_vec[tenant_idx]); - } - free(tenant_config_vec); - for (int i = 0; i < runtime_worker_threads_count; i++) { int ret = pthread_join(runtime_worker_threads[i], NULL); if (ret) { @@ -604,5 +601,11 @@ main(int argc, char **argv) exit(-1); } } + + for (int tenant_idx = 0; tenant_idx < tenant_config_vec_len; tenant_idx++) { + tenant_config_deinit(&tenant_config_vec[tenant_idx]); + } + free(tenant_config_vec); + exit(-1); } diff --git a/runtime/src/sandbox.c b/runtime/src/sandbox.c index bc029a11b..25dd675c3 100644 --- a/runtime/src/sandbox.c +++ b/runtime/src/sandbox.c @@ -15,6 +15,8 @@ #include "wasm_memory.h" #include "wasm_stack.h" +extern thread_local int group_worker_thread_idx; + _Atomic uint64_t sandbox_total = 0; static inline void @@ -108,6 +110,9 @@ sandbox_prepare_execution_environment(struct sandbox *sandbox) { assert(sandbox != NULL); + sandbox->global_worker_thread_idx = global_worker_thread_idx; + sandbox->group_worker_thread_idx = group_worker_thread_idx; + char *error_message = ""; int rc; @@ -176,6 +181,8 @@ sandbox_init(struct sandbox *sandbox, struct module *module, struct http_session sandbox->cursor = 0; sandbox->absolute_deadline = sandbox->timestamp_of.allocation + sandbox->route->relative_deadline; + sandbox->global_worker_thread_idx = -1; + sandbox->group_worker_thread_idx = -1; /* * Admissions Control State diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index d3ae93cfc..1da517425 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -30,7 +30,7 @@ thread_local uint32_t interrupts = 0; extern struct sandbox* current_sandboxes[1024]; extern time_t t_start; -extern thread_local int worker_thread_idx; +extern thread_local int global_worker_thread_idx; extern thread_local bool pthread_stop; extern thread_local bool is_listener; extern thread_local uint32_t total_local_requests; @@ -183,6 +183,7 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void global_timeout_queue_process_promotions(); } interrupts++; + //printf("preempt\n"); scheduler_preemptive_sched(interrupted_context); } else { /* We transition the sandbox to an interrupted state to exclude time propagating signals and @@ -202,6 +203,7 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void assert(current_sandbox->state == SANDBOX_PREEMPTED); assert(current_sandbox->ctxt.variant == ARCH_CONTEXT_VARIANT_SLOW); + printf("sigusr1 received\n"); software_interrupt_counts_sigusr_increment(); #ifdef LOG_PREEMPTION debuglog("Restoring sandbox: %lu, Stack %llu\n", current_sandbox->id, @@ -250,7 +252,7 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void double throughput = atomic_load(&sandbox_state_totals[SANDBOX_COMPLETE]) / seconds; uint32_t total_sandboxes_error = atomic_load(&sandbox_state_totals[SANDBOX_ERROR]); mem_log("throughput %f tid(%d) error request %u complete requests %u total request %u total_local_requests %u interrupts %u\n", - throughput, worker_thread_idx, total_sandboxes_error, atomic_load(&sandbox_state_totals[SANDBOX_COMPLETE]), + throughput, global_worker_thread_idx, total_sandboxes_error, atomic_load(&sandbox_state_totals[SANDBOX_COMPLETE]), atomic_load(&sandbox_state_totals[SANDBOX_ALLOCATED]), total_local_requests, interrupts); dump_log_to_file(); pthread_stop = true; diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c index 4ede81435..a7d7db850 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c @@ -26,15 +26,19 @@ extern struct perf_window * worker_perf_windows[1024]; thread_local struct perf_window perf_window_per_thread[1024]; struct sandbox* current_sandboxes[1024] = { NULL }; +extern uint32_t runtime_worker_group_size; extern FILE *sandbox_perf_log; thread_local bool pthread_stop = false; - +thread_local int dispatcher_id; /* context of the runtime thread before running sandboxes or to resume its "main". */ thread_local struct arch_context worker_thread_base_context; /* Used to index into global arguments and deadlines arrays */ -thread_local int worker_thread_idx; +thread_local int global_worker_thread_idx; + +/* Mark the worker index within the group */ +thread_local int group_worker_thread_idx; /* Used to track tenants' timeouts */ thread_local struct priority_queue *worker_thread_timeout_queue; @@ -50,7 +54,7 @@ void preallocate_memory() { } void perf_window_init() { - worker_perf_windows[worker_thread_idx] = perf_window_per_thread; + worker_perf_windows[global_worker_thread_idx] = perf_window_per_thread; tenant_database_foreach(tenant_perf_window_init, NULL, NULL); } @@ -66,8 +70,15 @@ worker_thread_main(void *argument) worker_thread_base_context.variant = ARCH_CONTEXT_VARIANT_RUNNING; /* Index was passed via argument */ - worker_thread_idx = *(int *)argument; + global_worker_thread_idx = *(int *)argument; + + /* Set dispatcher id for this worker */ + dispatcher_id = global_worker_thread_idx / runtime_worker_group_size; + + group_worker_thread_idx = global_worker_thread_idx - dispatcher_id * runtime_worker_group_size; + printf("global thread %d's dispatcher id is %d group size is %d group id is %d\n", global_worker_thread_idx, + dispatcher_id, runtime_worker_group_size, group_worker_thread_idx); /* Set my priority */ // runtime_set_pthread_prio(pthread_self(), 2); pthread_setschedprio(pthread_self(), -20); From d5f55f7398d13ccc276446b38a626107e956fb09 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 26 Sep 2023 11:32:55 -0600 Subject: [PATCH 049/198] fix bug: worker and listener thread both call push_to_rqueue() to enqueue a request to request typed queue that has a race condition cause the bug. Another bug is the spot that a popped sandbox from in the request typed queue was not reset to NULL, causing crash bug --- runtime/include/binary_search_tree.h | 85 ++++++++++++------------ runtime/include/request_typed_queue.h | 6 +- runtime/include/scheduler.h | 24 +++++-- runtime/src/listener_thread.c | 34 ++++++---- runtime/src/local_runqueue_binary_tree.c | 18 ++--- runtime/src/runtime.c | 10 ++- runtime/src/software_interrupt.c | 1 - 7 files changed, 105 insertions(+), 73 deletions(-) diff --git a/runtime/include/binary_search_tree.h b/runtime/include/binary_search_tree.h index 6c3de7988..abbe7beb3 100644 --- a/runtime/include/binary_search_tree.h +++ b/runtime/include/binary_search_tree.h @@ -24,7 +24,7 @@ struct TreeNodePool { }; struct binary_tree { - struct TreeNode *root; + struct TreeNode *root; struct TreeNodePool nodePool; binary_tree_get_priority_fn_t get_priority_fn; binary_tree_get_execution_cost_fn_t get_execution_cost_fn; @@ -43,8 +43,8 @@ void initNodePool(struct TreeNodePool *nodePool) { for (int i = 0; i < MAX_NODES - 1; ++i) { nodes[i].next = &nodes[i + 1]; // Set the next pointer of each node to the next node nodes[i].left = NULL; - nodes[i].right = NULL; - nodes[i].data = NULL; + nodes[i].right = NULL; + nodes[i].data = NULL; } nodes[MAX_NODES - 1].next = NULL; } @@ -85,19 +85,21 @@ struct TreeNode* newNode(struct binary_tree *binary_tree, void *data) { return new_node_t; } } + void getAvailableCapacity(struct binary_tree *binary_tree) { assert(binary_tree != NULL); - int size = 0; - struct TreeNode* start = binary_tree->nodePool.head; - while(start) { - size++; - start = start->next; - } + int size = 0; + struct TreeNode* start = binary_tree->nodePool.head; + while(start) { + size++; + start = start->next; + } - printf("available capacity of the queue is %d\n", size); + printf("available capacity of the queue is %d\n", size); } + // Return a node to the pool void deleteNode(struct binary_tree *binary_tree, struct TreeNode* node) { @@ -107,8 +109,8 @@ void deleteNode(struct binary_tree *binary_tree, struct TreeNode* node) { // Insert the node back to the head of the memory pool node->left = NULL; node->right = NULL; - node->next = binary_tree->nodePool.head; node->data = NULL; + node->next = binary_tree->nodePool.head; binary_tree->nodePool.head = node; } @@ -173,50 +175,50 @@ struct TreeNode* findMax(struct binary_tree *binary_tree, struct TreeNode *root) } // Function to delete a value from a binary search tree -struct TreeNode* delete(struct binary_tree *binary_tree, struct TreeNode* root, void *data, bool *deleted) { +struct TreeNode* delete_i(struct binary_tree *binary_tree, struct TreeNode* root, void *data, bool *deleted) { assert(binary_tree != NULL); if (root == NULL) { - *deleted = false; + *deleted = false; return NULL; } int64_t cmp_result = binary_tree->get_priority_fn(data) - binary_tree->get_priority_fn(root->data); if (cmp_result < 0) { - root->left = delete(binary_tree, root->left, data, deleted); + root->left = delete_i(binary_tree, root->left, data, deleted); } else if (cmp_result > 0) { - root->right = delete(binary_tree, root->right, data, deleted); + root->right = delete_i(binary_tree, root->right, data, deleted); } else { // cmp_result == 0 if (root->data == data) { - if (root->left == NULL) { - struct TreeNode* temp = root->right; - deleteNode(binary_tree, root); - *deleted = true; - return temp; - } else if (root->right == NULL) { - struct TreeNode* temp = root->left; - deleteNode(binary_tree, root); - *deleted = true; - return temp; - } else { - struct TreeNode* successor = root->right; - while (successor->left != NULL) { - successor = successor->left; - } - root->data = successor->data; - root->right = delete(binary_tree, root->right, successor->data, deleted); - return root; + if (root->left == NULL) { + struct TreeNode* temp = root->right; + deleteNode(binary_tree, root); + *deleted = true; + return temp; + } else if (root->right == NULL) { + struct TreeNode* temp = root->left; + deleteNode(binary_tree, root); + *deleted = true; + return temp; + } else { + struct TreeNode* successor = root->right; + while (successor->left != NULL) { + successor = successor->left; } + root->data = successor->data; + root->right = delete_i(binary_tree, root->right, successor->data, deleted); + return root; + } } else { - // Continue searching for the node with the same data pointer - if (root->left != NULL) { - root->left = delete(binary_tree, root->left, data, deleted); - } - - if (*deleted == false && root->right != NULL) { - root->right = delete(binary_tree, root->right, data, deleted); - } + // Continue searching for the node with the same data pointer + if (root->left != NULL) { + root->left = delete_i(binary_tree, root->left, data, deleted); + } + + if (*deleted == false && root->right != NULL) { + root->right = delete_i(binary_tree, root->right, data, deleted); + } } } return root; @@ -242,6 +244,7 @@ bool is_empty(struct binary_tree *binary_tree) { return binary_tree->root == NULL; } + void inorder(struct binary_tree *binary_tree, struct TreeNode* root) { assert(binary_tree != NULL); diff --git a/runtime/include/request_typed_queue.h b/runtime/include/request_typed_queue.h index ec121bcfc..458aa07a5 100644 --- a/runtime/include/request_typed_queue.h +++ b/runtime/include/request_typed_queue.h @@ -45,4 +45,8 @@ struct request_typed_queue { */ struct request_typed_queue * request_typed_queue_init(uint8_t type, uint32_t n_resas); -int push_to_rqueue(struct sandbox *sandbox, struct request_typed_queue *rtype, uint64_t tsc); +/* + * flag indicates this function is called by worker thread or listener thread. 1 means listener thread + * 2 means worker thread, this is only for debugging + */ +int push_to_rqueue(uint8_t dispatcher_id, struct sandbox *sandbox, struct request_typed_queue *rtype, uint64_t tsc, int flag); diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index 0f2dc47ae..3eaff4da0 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -329,10 +329,26 @@ scheduler_preemptive_sched(ucontext_t *interrupted_context) /* Delete current sandbox from local queue if dispatcher is DISPATCHER_SHINJUKU */ if (dispatcher == DISPATCHER_SHINJUKU) { - local_runqueue_delete(interrupted_sandbox); + local_runqueue_delete(interrupted_sandbox); + sandbox_preempt(interrupted_sandbox); + // Write back global at idx 0 + wasm_globals_set_i64(&interrupted_sandbox->globals, 0, sledge_abi__current_wasm_module_instance.abi.wasmg_0, + true); + arch_context_save_slow(&interrupted_sandbox->ctxt, &interrupted_context->uc_mcontext); + int req_type = interrupted_sandbox->route->request_type; + push_to_rqueue(dispatcher_id, interrupted_sandbox, request_type_queue[dispatcher_id][req_type - 1], __getcycles(), 2); + + struct sandbox *next = scheduler_get_next(); + /* next might be NULL because we delete the current sandbox from the runqueue */ + if (next) { + scheduler_preemptive_switch_to(interrupted_context, next); + } + return; } + struct sandbox *next = scheduler_get_next(); - /* Assumption: the current sandbox is on the runqueue, so the scheduler should always return something */ + + /* Assumption: the current sandbox is on the runqueue, so the scheduler should always return something */ assert(next != NULL); /* If current equals next, no switch is necessary, so resume execution */ @@ -354,10 +370,6 @@ scheduler_preemptive_sched(ucontext_t *interrupted_context) true); arch_context_save_slow(&interrupted_sandbox->ctxt, &interrupted_context->uc_mcontext); - if (dispatcher == DISPATCHER_SHINJUKU) { - int req_type = interrupted_sandbox->route->request_type; - push_to_rqueue(interrupted_sandbox, request_type_queue[dispatcher_id][req_type - 1], __getcycles()); - } scheduler_preemptive_switch_to(interrupted_context, next); } diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index bea88407b..25e8a7bc6 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -20,6 +20,7 @@ struct perf_window * worker_perf_windows[1024]; struct priority_queue * worker_queues[1024]; struct binary_tree * worker_binary_trees[1024]; +struct ps_list_head * worker_lists[1024]; extern _Atomic uint64_t worker_queuing_cost[1024]; //struct sandbox *urgent_request[1024] = { NULL }; @@ -588,7 +589,7 @@ void darc_shinjuku_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, memcpy(sandbox->rpc_request_body, msg, size); sandbox->rpc_request_body_size = size; - push_to_rqueue(sandbox, request_type_queue[dispatcher_thread_idx][req_type - 1], __getcycles()); + push_to_rqueue(dispatcher_thread_idx, sandbox, request_type_queue[dispatcher_thread_idx][req_type - 1], __getcycles(), 1); } @@ -642,6 +643,14 @@ struct sandbox * shinjuku_peek_selected_sandbox(int *selected_queue_idx) { if (request_type_queue[dispatcher_thread_idx][i]->rqueue_head > request_type_queue[dispatcher_thread_idx][i]->rqueue_tail) { //get the tail sandbox of the queue struct sandbox *sandbox = request_type_queue[dispatcher_thread_idx][i]->rqueue[request_type_queue[dispatcher_thread_idx][i]->rqueue_tail & (RQUEUE_LEN - 1)]; + /* When worker thread call push_to_rqueue(), it first increase head, but push sandbox + to rqueue a little bit, cause here if check success, but sandbox is NULL. In such + case, just continue to wait the sandbox is in the queue + */ + if (sandbox == NULL) { + continue; + } + uint64_t ts = request_type_queue[dispatcher_thread_idx][i]->tsqueue[request_type_queue[dispatcher_thread_idx][i]->rqueue_tail & (RQUEUE_LEN - 1)]; uint64_t dt = __getcycles() - ts; float priority = (float)dt / (float)sandbox->route->relative_deadline; @@ -659,6 +668,8 @@ struct sandbox * shinjuku_peek_selected_sandbox(int *selected_queue_idx) { void shinjuku_dequeue_selected_sandbox(int selected_queue_type) { assert(selected_queue_type >= 0 && selected_queue_type < MAX_REQUEST_TYPE); + /* set the array slot to NULL because the sandbox is popped out */ + request_type_queue[dispatcher_thread_idx][selected_queue_type]->rqueue[request_type_queue[dispatcher_thread_idx][selected_queue_type]->rqueue_tail & (RQUEUE_LEN - 1)] = NULL; request_type_queue[dispatcher_thread_idx][selected_queue_type]->rqueue_tail++; } @@ -708,18 +719,19 @@ void darc_dispatch() { void shinjuku_dispatch() { while (true) { - int selected_queue_type; + int selected_queue_type = -1; struct sandbox *sandbox = shinjuku_peek_selected_sandbox(&selected_queue_type); - + + if (!sandbox) return; // empty + + assert(selected_queue_type != -1); /* This sandbox was preempted by a worker thread, re-dispatch it to the same worker thread * no matter if it is free */ - if (sandbox && sandbox->global_worker_thread_idx != -1) { - assert(selected_queue_type != -1); - //printf("dispatch %p to worker %d\n", sandbox, sandbox->global_worker_thread_idx); + if (sandbox->global_worker_thread_idx != -1) { local_runqueue_add_index(sandbox->global_worker_thread_idx, sandbox); shinjuku_dequeue_selected_sandbox(selected_queue_type); - } else if (sandbox && sandbox->global_worker_thread_idx == -1) { + } else { if (free_workers[dispatcher_thread_idx] == 0) { /* No available workers, return */ return; @@ -735,7 +747,7 @@ void shinjuku_dispatch() { struct sandbox *current = current_sandboxes[worker_list[i]]; if (!current) continue; // TODO????? In case that worker thread hasn't call current_sandbox_set to set the current sandbox uint64_t duration = (__getcycles() - current->timestamp_of.last_state_change) / runtime_processor_speed_MHz; - if (duration >= 100 && current->state == SANDBOX_RUNNING_USER) { + if (duration >= 10 && current->state == SANDBOX_RUNNING_USER) { //preempt the current sandbox and put it back the typed queue, select a new one to send to it local_runqueue_add_index(worker_list[i], sandbox); //preempt worker @@ -746,10 +758,7 @@ void shinjuku_dispatch() { } } } - } else { - /* typed queues are empty, return */ - return; - } + } } } @@ -799,7 +808,6 @@ listener_thread_main(void *dummy) /* Index was passed via argument */ dispatcher_thread_idx = *(int *)dummy; - printf("listener thread, id %d\n", dispatcher_thread_idx); /* init typed queue */ typed_queue_init(); diff --git a/runtime/src/local_runqueue_binary_tree.c b/runtime/src/local_runqueue_binary_tree.c index ba28ba6d8..7e304eac4 100644 --- a/runtime/src/local_runqueue_binary_tree.c +++ b/runtime/src/local_runqueue_binary_tree.c @@ -42,7 +42,7 @@ void local_runqueue_binary_tree_add(struct sandbox *sandbox) { lock_node_t node_lock = {}; - lock_lock(&local_runqueue_binary_tree->lock, &node_lock); + lock_lock(&local_runqueue_binary_tree->lock, &node_lock); local_runqueue_binary_tree->root = insert(local_runqueue_binary_tree, local_runqueue_binary_tree->root, sandbox); lock_unlock(&local_runqueue_binary_tree->lock, &node_lock); } @@ -69,7 +69,7 @@ local_runqueue_binary_tree_delete(struct sandbox *sandbox) lock_node_t node_lock = {}; lock_lock(&local_runqueue_binary_tree->lock, &node_lock); bool deleted = false; - local_runqueue_binary_tree->root = delete(local_runqueue_binary_tree, local_runqueue_binary_tree->root, sandbox, &deleted); + local_runqueue_binary_tree->root = delete_i(local_runqueue_binary_tree, local_runqueue_binary_tree->root, sandbox, &deleted); lock_unlock(&local_runqueue_binary_tree->lock, &node_lock); if (deleted == false) panic("Tried to delete sandbox %lu from runqueue, but was not present\n", sandbox->id); } @@ -107,14 +107,14 @@ local_runqueue_binary_tree_try_add_index(int index, struct sandbox *sandbox, boo *need_interrupt = false; return 0; } else if (current_sandboxes[index] != NULL && sandbox_is_preemptable(current_sandboxes[index]) == true && - sandbox_get_priority(sandbox) < sandbox_get_priority(current_sandboxes[index])) { + sandbox_get_priority(sandbox) < sandbox_get_priority(current_sandboxes[index])) { *need_interrupt = true; return 0; } else { need_interrupt = false; uint64_t waiting_serving_time = 0; lock_node_t node_lock = {}; - lock_lock(&binary_tree->lock, &node_lock); + lock_lock(&binary_tree->lock, &node_lock); struct TreeNode* node = findMaxValueLessThan(binary_tree, binary_tree->root, sandbox, &waiting_serving_time, index); lock_unlock(&binary_tree->lock, &node_lock); return waiting_serving_time; @@ -134,11 +134,11 @@ local_runqueue_binary_tree_initialize() worker_binary_trees[global_worker_thread_idx] = local_runqueue_binary_tree; /* Register Function Pointers for Abstract Scheduling API */ struct local_runqueue_config config = { .add_fn = local_runqueue_binary_tree_add, - .add_fn_idx = local_runqueue_binary_tree_add_index, - .try_add_fn_idx = local_runqueue_binary_tree_try_add_index, - .is_empty_fn = local_runqueue_binary_tree_is_empty, - .delete_fn = local_runqueue_binary_tree_delete, - .get_next_fn = local_runqueue_binary_tree_get_next }; + .add_fn_idx = local_runqueue_binary_tree_add_index, + .try_add_fn_idx = local_runqueue_binary_tree_try_add_index, + .is_empty_fn = local_runqueue_binary_tree_is_empty, + .delete_fn = local_runqueue_binary_tree_delete, + .get_next_fn = local_runqueue_binary_tree_get_next }; local_runqueue_initialize(&config); } diff --git a/runtime/src/runtime.c b/runtime/src/runtime.c index 037e7897f..a9e7bc15b 100644 --- a/runtime/src/runtime.c +++ b/runtime/src/runtime.c @@ -30,7 +30,7 @@ /* Count of the total number of requests we've ever received. Never decrements as it is used to dispatch requests to workers with RR */ _Atomic uint64_t request_index; - +extern struct request_typed_queue *request_type_queue[MAX_DISPATCHER][MAX_REQUEST_TYPE]; pthread_t *runtime_worker_threads; pthread_t *runtime_listener_threads; int *runtime_worker_threads_argument; @@ -117,10 +117,16 @@ runtime_initialize(void) memset(runtime_worker_threads_deadline, UINT8_MAX, runtime_worker_threads_count * sizeof(uint64_t)); runtime_listener_threads = calloc(runtime_listener_threads_count, sizeof(pthread_t)); - assert(runtime_listener_threads != NULL); + assert(runtime_listener_threads != NULL); runtime_listener_threads_argument = calloc(runtime_listener_threads_count, sizeof(int)); assert(runtime_listener_threads_argument != NULL); + /* Initialize request typed queue */ + for (int i = 0; i < MAX_DISPATCHER; i++) { + for (int j = 0; j < MAX_REQUEST_TYPE; j++) { + request_type_queue[i][j] = NULL; + } + } http_total_init(); sandbox_total_initialize(); request_index_initialize(); diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index 1da517425..633ee383a 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -203,7 +203,6 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void assert(current_sandbox->state == SANDBOX_PREEMPTED); assert(current_sandbox->ctxt.variant == ARCH_CONTEXT_VARIANT_SLOW); - printf("sigusr1 received\n"); software_interrupt_counts_sigusr_increment(); #ifdef LOG_PREEMPTION debuglog("Restoring sandbox: %lu, Stack %llu\n", current_sandbox->id, From 817e5727231722cc09940659dc55c029858befa9 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 26 Sep 2023 11:35:35 -0600 Subject: [PATCH 050/198] 1. forgot committing request_typed_queue.c 2. update scripts --- runtime/src/request_typed_queue.c | 51 +++++++++++++++++++++++++++++++ runtime/tests/debug.sh | 4 ++- runtime/tests/fib.json | 41 +++++++++++++------------ runtime/tests/start.sh | 4 ++- 4 files changed, 78 insertions(+), 22 deletions(-) create mode 100644 runtime/src/request_typed_queue.c diff --git a/runtime/src/request_typed_queue.c b/runtime/src/request_typed_queue.c new file mode 100644 index 000000000..144d31d5e --- /dev/null +++ b/runtime/src/request_typed_queue.c @@ -0,0 +1,51 @@ +#include +#include +#include + +#include "panic.h" +#include "likely.h" +#include "request_typed_queue.h" + +struct request_typed_queue * +request_typed_queue_init(uint8_t type, uint32_t n_resas) { + struct request_typed_queue *queue = malloc(sizeof(struct request_typed_queue)); + queue->type = type; + queue->mean_ns = 0; + queue->deadline = 0; + queue->rqueue_tail = 0; + atomic_init(&queue->rqueue_head, 0); + queue->n_resas = n_resas; + for (unsigned int i = 0; i < n_resas; ++i) { + queue->res_workers[i] = i; + } + + queue->n_stealable = runtime_worker_group_size - n_resas; + int index = 0; + for (unsigned int i = n_resas; i < runtime_worker_group_size; i++) { + queue->stealable_workers[index] = i; + index++; + } + + memset(queue->rqueue, 0, RQUEUE_LEN * sizeof(struct sandbox*)); + + return queue; + +} + +int push_to_rqueue(uint8_t dispatcher_id, struct sandbox *sandbox, struct request_typed_queue *rtype, uint64_t tsc, int flag) { + assert(sandbox != NULL); + + uint32_t head = atomic_load(&rtype->rqueue_head); + + if (unlikely(head - rtype->rqueue_tail == RQUEUE_LEN)) { + panic("Dispatcher dropped request as type %hhu because queue is full\n", rtype->type); + return -1; + } else { + //PSP_DEBUG("Pushed one request to queue " << req_type_str[static_cast(rtype.type)]); + uint32_t previous_head = atomic_fetch_add(&rtype->rqueue_head, 1); + rtype->tsqueue[previous_head & (RQUEUE_LEN - 1)] = tsc; + rtype->rqueue[previous_head & (RQUEUE_LEN - 1)] = sandbox; + return 0; + } +} + diff --git a/runtime/tests/debug.sh b/runtime/tests/debug.sh index 53efa9bd3..f878e3e89 100755 --- a/runtime/tests/debug.sh +++ b/runtime/tests/debug.sh @@ -16,7 +16,9 @@ export SLEDGE_SANDBOX_PERF_LOG=$path/srsf.log export SLEDGE_NWORKERS=9 export SLEDGE_FIRST_WORKER_COREID=4 export SLEDGE_NLISTENERS=3 -export SLEDGE_DISPATCHER=DARC +export SLEDGE_WORKER_GROUP_SIZE=3 +#export SLEDGE_DISPATCHER=DARC +export SLEDGE_DISPATCHER=SHINJUKU export LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" #gdb --eval-command="handle SIGUSR1 nostop" \ # --eval-command="set pagination off" \ diff --git a/runtime/tests/fib.json b/runtime/tests/fib.json index c73167ac6..bbdbaa091 100644 --- a/runtime/tests/fib.json +++ b/runtime/tests/fib.json @@ -5,27 +5,28 @@ "replenishment-period-us": 0, "max-budget-us": 0, "routes": [ - { - "route": "/fib", - "request-type": 1, - "n-resas": 2, - "path": "fibonacci.wasm.so", - "admissions-percentile": 70, - "expected-execution-us": 5, - "relative-deadline-us": 50, - "http-resp-content-type": "text/plain" - }, - { - "route": "/fib2", - "request-type": 2, - "n-resas": 1, - "path": "fibonacci.wasm.so", - "admissions-percentile": 70, - "expected-execution-us": 798, - "relative-deadline-us": 7980, - "http-resp-content-type": "text/plain" - } + { + "route": "/fib", + "request-type": 1, + "n-resas": 2, + "path": "fibonacci.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 5, + "relative-deadline-us": 50, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib2", + "request-type": 2, + "n-resas": 1, + "path": "fibonacci.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 798, + "relative-deadline-us": 7980, + "http-resp-content-type": "text/plain" + } ] + } ] diff --git a/runtime/tests/start.sh b/runtime/tests/start.sh index e2da5d84c..f5839f956 100755 --- a/runtime/tests/start.sh +++ b/runtime/tests/start.sh @@ -28,7 +28,9 @@ export SLEDGE_NWORKERS=$worker_num export SLEDGE_NLISTENERS=$listener_num export SLEDGE_WORKER_GROUP_SIZE=3 export SLEDGE_SCHEDULER=EDF -export SLEDGE_DISPATCHER=DARC +#export SLEDGE_DISPATCHER=DARC +#export SLEDGE_DISPATCHER=SHINJUKU +export SLEDGE_DISPATCHER=EDF_INTERRUPT export SLEDGE_SANDBOX_PERF_LOG=$path/server.log #echo $SLEDGE_SANDBOX_PERF_LOG cd $project_path/runtime/bin From f3ff5baa84b1a7855876588c47b033dfd1951688 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 26 Sep 2023 14:54:46 -0600 Subject: [PATCH 051/198] add shinjuku_dispatch_different_core() but doesn't work due to different page mapping --- runtime/src/listener_thread.c | 96 ++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 42 deletions(-) diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 25e8a7bc6..60bb5bc07 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -633,7 +633,7 @@ void drain_queue(struct request_typed_queue *rtype) { } -/* Return selected sandbox and selected queue type */ +/* Return selected sandbox and selected queue type, not pop it out */ struct sandbox * shinjuku_peek_selected_sandbox(int *selected_queue_idx) { float highest_priority = 0; *selected_queue_idx = -1; @@ -673,6 +673,45 @@ void shinjuku_dequeue_selected_sandbox(int selected_queue_type) { request_type_queue[dispatcher_thread_idx][selected_queue_type]->rqueue_tail++; } +/* Return selected sandbox and pop it out */ +struct sandbox * shinjuku_select_sandbox() { + float highest_priority = 0; + int selected_queue_idx = -1; + struct sandbox *selected_sandbox = NULL; + + for (uint32_t i = 0; i < n_rtypes; ++i) { + if (request_type_queue[dispatcher_thread_idx][i]->rqueue_head > request_type_queue[dispatcher_thread_idx][i]->rqueue_tail) { + //get the tail sandbox of the queue + struct sandbox *sandbox = request_type_queue[dispatcher_thread_idx][i]->rqueue[request_type_queue[dispatcher_thread_idx][i]->rqueue_tail & (RQUEUE_LEN - 1)]; + /* When worker thread call push_to_rqueue(), it first increase head, but push sandbox + to rqueue a little bit, cause here if check success, but sandbox is NULL. In such + case, just continue to wait the sandbox is in the queue + */ + if (sandbox == NULL) { + continue; + } + + uint64_t ts = request_type_queue[dispatcher_thread_idx][i]->tsqueue[request_type_queue[dispatcher_thread_idx][i]->rqueue_tail & (RQUEUE_LEN - 1)]; + uint64_t dt = __getcycles() - ts; + float priority = (float)dt / (float)sandbox->route->relative_deadline; + if (priority > highest_priority) { + highest_priority = priority; + selected_queue_idx = i; + selected_sandbox = sandbox; + } + } + } + + if (selected_sandbox != NULL) { + /* set the array slot to NULL because the sandbox is popped out */ + request_type_queue[dispatcher_thread_idx][selected_queue_idx]->rqueue[request_type_queue[dispatcher_thread_idx][selected_queue_idx]->rqueue_tail & (RQUEUE_LEN - 1)] = NULL; + request_type_queue[dispatcher_thread_idx][selected_queue_idx]->rqueue_tail++; + } + + return selected_sandbox; + +} + void darc_dispatch() { for (uint32_t i = 0; i < n_rtypes; ++i) { // request_type_queue is a sorted queue, so the loop will dispatch packets from @@ -683,17 +722,16 @@ void darc_dispatch() { } } -/*void shinjuku_dispatch() { +void shinjuku_dispatch_different_core() { for (uint32_t i = 0; i < runtime_worker_group_size; ++i) { if ((1 << i) & free_workers[dispatcher_thread_idx]) { struct sandbox *sandbox = shinjuku_select_sandbox(); - if (sandbox) { - local_runqueue_add_index(worker_list[i], sandbox); - atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << i); - } else { - // queue is empty, exit loop - break; - } + if (sandbox == NULL) { + return; // queue empty + } + + local_runqueue_add_index(worker_list[i], sandbox); + atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << i); } else { // core is busy //check if the current sandbox is running longer than the specified time duration struct sandbox *current = current_sandboxes[worker_list[i]]; @@ -702,19 +740,16 @@ void darc_dispatch() { if (duration >= 10 && current->state == SANDBOX_RUNNING_USER) { //preempt the current sandbox and put it back the typed queue, select a new one to send to it struct sandbox *sandbox = shinjuku_select_sandbox(); - if (sandbox) { - local_runqueue_add_index(worker_list[i], sandbox); - //preempt worker - preempt_worker(worker_list[i]); - atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << i); - } else { - // queue is empty, exit loop - break; - } + if (sandbox == NULL) { + return; // queue empty + } + local_runqueue_add_index(worker_list[i], sandbox); + //preempt worker + preempt_worker(worker_list[i]); } } } -}*/ +} void shinjuku_dispatch() { @@ -762,29 +797,6 @@ void shinjuku_dispatch() { } } -void shinjuku_dispatch_test() { - while(true) { - int selected_queue_type = 0; - struct sandbox *sandbox = shinjuku_peek_selected_sandbox(&selected_queue_type); - if (sandbox) { - assert(sandbox->state == SANDBOX_INITIALIZED); - if (free_workers[dispatcher_thread_idx] == 0) { - return; - } - for (uint32_t i = 0; i < runtime_worker_group_size; ++i) { - if ((1 << i) & free_workers[dispatcher_thread_idx]) { - local_runqueue_add_index(worker_list[i], sandbox); - atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << i); - shinjuku_dequeue_selected_sandbox(selected_queue_type); - break; - } - } - } else { - return; - } - } -} - void dispatcher_send_response(void *req_handle, char* msg, size_t msg_len) { erpc_req_response_enqueue(dispatcher_thread_idx, req_handle, msg, msg_len, 1); } From 3bf745613846da67cf3a9f254c4d5827aac60196 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 26 Sep 2023 18:04:30 -0600 Subject: [PATCH 052/198] fix bug: load imbalancing among worker threads --- runtime/src/listener_thread.c | 81 +++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 60bb5bc07..f37417126 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -754,47 +754,52 @@ void shinjuku_dispatch_different_core() { void shinjuku_dispatch() { while (true) { - int selected_queue_type = -1; - struct sandbox *sandbox = shinjuku_peek_selected_sandbox(&selected_queue_type); - - if (!sandbox) return; // empty - - assert(selected_queue_type != -1); - /* This sandbox was preempted by a worker thread, re-dispatch it to the same worker thread - * no matter if it is free - */ - if (sandbox->global_worker_thread_idx != -1) { - local_runqueue_add_index(sandbox->global_worker_thread_idx, sandbox); - shinjuku_dequeue_selected_sandbox(selected_queue_type); - } else { - if (free_workers[dispatcher_thread_idx] == 0) { - /* No available workers, return */ - return; - } else { - for (uint32_t i = 0; i < runtime_worker_group_size; ++i) { - if ((1 << i) & free_workers[dispatcher_thread_idx]) { - local_runqueue_add_index(worker_list[i], sandbox); - atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << i); + // No available workers + if (free_workers[dispatcher_thread_idx] == 0) return; + + for (uint32_t i = 0; i < runtime_worker_group_size; ++i) { + /* core is idle */ + if ((1 << i) & free_workers[dispatcher_thread_idx]) { + int selected_queue_type = -1; + struct sandbox *sandbox = shinjuku_peek_selected_sandbox(&selected_queue_type); + if (!sandbox) return; // queue is empty + while (sandbox->global_worker_thread_idx != -1) { + local_runqueue_add_index(sandbox->global_worker_thread_idx, sandbox); + shinjuku_dequeue_selected_sandbox(selected_queue_type); + sandbox = shinjuku_peek_selected_sandbox(&selected_queue_type); + if (!sandbox) return; + } + + local_runqueue_add_index(worker_list[i], sandbox); + atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << i); + shinjuku_dequeue_selected_sandbox(selected_queue_type); + } else { // core is busy + //check if the current sandbox is running longer than the specified time duration + struct sandbox *current = current_sandboxes[worker_list[i]]; + if (!current) continue; //In case that worker thread hasn't call current_sandbox_set to set the current sandbox + uint64_t duration = (__getcycles() - current->timestamp_of.last_state_change) / runtime_processor_speed_MHz; + if (duration >= 10 && current->state == SANDBOX_RUNNING_USER) { + int selected_queue_type = -1; + struct sandbox *sandbox = shinjuku_peek_selected_sandbox(&selected_queue_type); + if (!sandbox) return; // queue is empty + + while (sandbox->global_worker_thread_idx != -1) { + local_runqueue_add_index(sandbox->global_worker_thread_idx, sandbox); shinjuku_dequeue_selected_sandbox(selected_queue_type); - break; - } else { // core is busy - //check if the current sandbox is running longer than the specified time duration - struct sandbox *current = current_sandboxes[worker_list[i]]; - if (!current) continue; // TODO????? In case that worker thread hasn't call current_sandbox_set to set the current sandbox - uint64_t duration = (__getcycles() - current->timestamp_of.last_state_change) / runtime_processor_speed_MHz; - if (duration >= 10 && current->state == SANDBOX_RUNNING_USER) { - //preempt the current sandbox and put it back the typed queue, select a new one to send to it - local_runqueue_add_index(worker_list[i], sandbox); - //preempt worker - preempt_worker(worker_list[i]); - shinjuku_dequeue_selected_sandbox(selected_queue_type); - break; - } + sandbox = shinjuku_peek_selected_sandbox(&selected_queue_type); + if (!sandbox) return; } - } + + //preempt the current sandbox and put it back the typed queue, select a new one to send to it + local_runqueue_add_index(worker_list[i], sandbox); + //preempt worker + preempt_worker(worker_list[i]); + shinjuku_dequeue_selected_sandbox(selected_queue_type); + } } - } - } + + } + } } void dispatcher_send_response(void *req_handle, char* msg, size_t msg_len) { From 1d56d5eb57d8f8c6f748d88e6d1b83cd8010de8e Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 27 Sep 2023 00:38:04 -0600 Subject: [PATCH 053/198] fix bug: check each worker's current task to see if it runs longer than 10us even total free workers is 0 --- runtime/src/listener_thread.c | 62 ++++++++++++++++------------------- 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index f37417126..93ba8804b 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -752,53 +752,47 @@ void shinjuku_dispatch_different_core() { } void shinjuku_dispatch() { - - while (true) { - // No available workers - if (free_workers[dispatcher_thread_idx] == 0) return; - - for (uint32_t i = 0; i < runtime_worker_group_size; ++i) { - /* core is idle */ - if ((1 << i) & free_workers[dispatcher_thread_idx]) { + for (uint32_t i = 0; i < runtime_worker_group_size; ++i) { + /* core is idle */ + if ((1 << i) & free_workers[dispatcher_thread_idx]) { + int selected_queue_type = -1; + struct sandbox *sandbox = shinjuku_peek_selected_sandbox(&selected_queue_type); + if (!sandbox) return; // queue is empty + while (sandbox->global_worker_thread_idx != -1) { + local_runqueue_add_index(sandbox->global_worker_thread_idx, sandbox); + shinjuku_dequeue_selected_sandbox(selected_queue_type); + sandbox = shinjuku_peek_selected_sandbox(&selected_queue_type); + if (!sandbox) return; + } + + local_runqueue_add_index(worker_list[i], sandbox); + atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << i); + shinjuku_dequeue_selected_sandbox(selected_queue_type); + } else { // core is busy + //check if the current sandbox is running longer than the specified time duration + struct sandbox *current = current_sandboxes[worker_list[i]]; + if (!current) continue; //In case that worker thread hasn't call current_sandbox_set to set the current sandbox + uint64_t duration = (__getcycles() - current->timestamp_of.last_state_change) / runtime_processor_speed_MHz; + if (duration >= 10 && current->state == SANDBOX_RUNNING_USER) { int selected_queue_type = -1; struct sandbox *sandbox = shinjuku_peek_selected_sandbox(&selected_queue_type); if (!sandbox) return; // queue is empty + while (sandbox->global_worker_thread_idx != -1) { local_runqueue_add_index(sandbox->global_worker_thread_idx, sandbox); shinjuku_dequeue_selected_sandbox(selected_queue_type); sandbox = shinjuku_peek_selected_sandbox(&selected_queue_type); if (!sandbox) return; } - + + //preempt the current sandbox and put it back the typed queue, select a new one to send to it local_runqueue_add_index(worker_list[i], sandbox); - atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << i); + //preempt worker + preempt_worker(worker_list[i]); shinjuku_dequeue_selected_sandbox(selected_queue_type); - } else { // core is busy - //check if the current sandbox is running longer than the specified time duration - struct sandbox *current = current_sandboxes[worker_list[i]]; - if (!current) continue; //In case that worker thread hasn't call current_sandbox_set to set the current sandbox - uint64_t duration = (__getcycles() - current->timestamp_of.last_state_change) / runtime_processor_speed_MHz; - if (duration >= 10 && current->state == SANDBOX_RUNNING_USER) { - int selected_queue_type = -1; - struct sandbox *sandbox = shinjuku_peek_selected_sandbox(&selected_queue_type); - if (!sandbox) return; // queue is empty - - while (sandbox->global_worker_thread_idx != -1) { - local_runqueue_add_index(sandbox->global_worker_thread_idx, sandbox); - shinjuku_dequeue_selected_sandbox(selected_queue_type); - sandbox = shinjuku_peek_selected_sandbox(&selected_queue_type); - if (!sandbox) return; - } - - //preempt the current sandbox and put it back the typed queue, select a new one to send to it - local_runqueue_add_index(worker_list[i], sandbox); - //preempt worker - preempt_worker(worker_list[i]); - shinjuku_dequeue_selected_sandbox(selected_queue_type); - } } - } + } } From ce1b58ed5285702c5c090ca8f379dc15d034654d Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 29 Sep 2023 00:02:07 -0600 Subject: [PATCH 054/198] 1. remove some http setting code, would cause crash. 2. Send failed response when sandbox running failed. 3. Update debug.sh to disable timer preemption. 4. Update meet_deadline_percentage.py to calcuate total interrupts --- runtime/include/sandbox_set_as_error.h | 9 +++-- runtime/include/sandbox_set_as_returned.h | 2 - runtime/src/current_sandbox.c | 3 +- runtime/src/listener_thread.c | 48 +++++++++-------------- runtime/tests/debug.sh | 5 ++- runtime/tests/meet_deadline_percentage.py | 4 ++ 6 files changed, 33 insertions(+), 38 deletions(-) diff --git a/runtime/include/sandbox_set_as_error.h b/runtime/include/sandbox_set_as_error.h index 34834932c..11ed58c3d 100644 --- a/runtime/include/sandbox_set_as_error.h +++ b/runtime/include/sandbox_set_as_error.h @@ -58,10 +58,11 @@ sandbox_set_as_error(struct sandbox *sandbox, sandbox_state_t last_state) admissions_control_subtract(sandbox->admissions_estimate); /* Return HTTP session to listener core to be written back to client */ - http_session_set_response_header(sandbox->http, 500); - sandbox->http->state = HTTP_SESSION_EXECUTION_COMPLETE; - http_session_send_response(sandbox->http, (void_star_cb)listener_thread_register_http_session); - sandbox->http = NULL; + //http_session_set_response_header(sandbox->http, 500); + + //sandbox->http->state = HTTP_SESSION_EXECUTION_COMPLETE; + //http_session_send_response(sandbox->http, (void_star_cb)listener_thread_register_http_session); + //sandbox->http = NULL; /* Terminal State Logging */ //sandbox_perf_log_print_entry(sandbox); diff --git a/runtime/include/sandbox_set_as_returned.h b/runtime/include/sandbox_set_as_returned.h index dfe0ed7bc..37dce98fd 100644 --- a/runtime/include/sandbox_set_as_returned.h +++ b/runtime/include/sandbox_set_as_returned.h @@ -54,8 +54,6 @@ sandbox_set_as_returned(struct sandbox *sandbox, sandbox_state_t last_state) sandbox_state_totals_increment(SANDBOX_RETURNED); sandbox_state_totals_decrement(last_state); - sandbox_send_response(sandbox, 0); - /* State Change Hooks */ sandbox_state_transition_from_hook(sandbox, last_state); sandbox_state_transition_to_hook(sandbox, SANDBOX_RETURNED); diff --git a/runtime/src/current_sandbox.c b/runtime/src/current_sandbox.c index fd062e8b3..d75994d39 100644 --- a/runtime/src/current_sandbox.c +++ b/runtime/src/current_sandbox.c @@ -54,15 +54,16 @@ current_sandbox_exit() switch (exiting_sandbox->state) { case SANDBOX_RETURNED: sandbox_exit_success(exiting_sandbox); + sandbox_send_response(exiting_sandbox, 0); break; case SANDBOX_RUNNING_SYS: sandbox_exit_error(exiting_sandbox); + sandbox_send_response(exiting_sandbox, 1); break; default: panic("Cooperatively switching from a sandbox in a non-terminal %s state\n", sandbox_state_stringify(exiting_sandbox->state)); } - scheduler_cooperative_sched(true); /* The scheduler should never switch back to completed sandboxes */ diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 93ba8804b..18c7cf1c2 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -39,15 +39,6 @@ _Atomic uint32_t free_workers[MAX_DISPATCHER] = {0}; // the index is the dispate // will be 111, then the free_workers[dispatcher_id] is 7 -/*thread_local struct request_typed_queue *request_type_queue[MAX_REQUEST_TYPE]; // the index is the request type - // We implicitly represent the request - // execution time as long or short based - // on the value of the request type. - // For example, the execution time of - // request with type 1 is shorter than request - // with type 2, that's reducing the sorting - // cost of the typed queue -*/ struct request_typed_queue *request_type_queue[MAX_DISPATCHER][MAX_REQUEST_TYPE]; thread_local uint32_t n_rtypes = 0; @@ -458,7 +449,6 @@ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, } uint8_t kMsgSize = 16; - //TODO: rpc_id is hardcode now struct tenant *tenant = tenant_database_find_by_port(port); assert(tenant != NULL); @@ -675,7 +665,7 @@ void shinjuku_dequeue_selected_sandbox(int selected_queue_type) { /* Return selected sandbox and pop it out */ struct sandbox * shinjuku_select_sandbox() { - float highest_priority = 0; + float highest_priority = -1; int selected_queue_idx = -1; struct sandbox *selected_sandbox = NULL; @@ -730,24 +720,24 @@ void shinjuku_dispatch_different_core() { return; // queue empty } - local_runqueue_add_index(worker_list[i], sandbox); - atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << i); + local_runqueue_add_index(worker_list[i], sandbox); + atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << i); } else { // core is busy - //check if the current sandbox is running longer than the specified time duration - struct sandbox *current = current_sandboxes[worker_list[i]]; - if (!current) continue; // In case that worker thread hasn't call current_sandbox_set to set the current sandbox - uint64_t duration = (__getcycles() - current->timestamp_of.last_state_change) / runtime_processor_speed_MHz; - if (duration >= 10 && current->state == SANDBOX_RUNNING_USER) { - //preempt the current sandbox and put it back the typed queue, select a new one to send to it - struct sandbox *sandbox = shinjuku_select_sandbox(); - if (sandbox == NULL) { - return; // queue empty - } - local_runqueue_add_index(worker_list[i], sandbox); - //preempt worker - preempt_worker(worker_list[i]); - } - } + //check if the current sandbox is running longer than the specified time duration + struct sandbox *current = current_sandboxes[worker_list[i]]; + if (!current) continue; // In case that worker thread hasn't call current_sandbox_set to set the current sandbox + uint64_t duration = (__getcycles() - current->timestamp_of.last_state_change) / runtime_processor_speed_MHz; + if (duration >= 10 && current->state == SANDBOX_RUNNING_USER) { + //preempt the current sandbox and put it back the typed queue, select a new one to send to it + struct sandbox *sandbox = shinjuku_select_sandbox(); + if (sandbox == NULL) { + return; // queue empty + } + local_runqueue_add_index(worker_list[i], sandbox); + //preempt worker + preempt_worker(worker_list[i]); + } + } } } @@ -773,7 +763,7 @@ void shinjuku_dispatch() { struct sandbox *current = current_sandboxes[worker_list[i]]; if (!current) continue; //In case that worker thread hasn't call current_sandbox_set to set the current sandbox uint64_t duration = (__getcycles() - current->timestamp_of.last_state_change) / runtime_processor_speed_MHz; - if (duration >= 10 && current->state == SANDBOX_RUNNING_USER) { + if (duration >= 50 && current->state == SANDBOX_RUNNING_USER) { int selected_queue_type = -1; struct sandbox *sandbox = shinjuku_peek_selected_sandbox(&selected_queue_type); if (!sandbox) return; // queue is empty diff --git a/runtime/tests/debug.sh b/runtime/tests/debug.sh index f878e3e89..ff739ca8e 100755 --- a/runtime/tests/debug.sh +++ b/runtime/tests/debug.sh @@ -11,7 +11,7 @@ declare project_path="$( path=`pwd` echo $project_path cd $project_path/runtime/bin -#export SLEDGE_DISABLE_PREEMPTION=true +export SLEDGE_DISABLE_PREEMPTION=true export SLEDGE_SANDBOX_PERF_LOG=$path/srsf.log export SLEDGE_NWORKERS=9 export SLEDGE_FIRST_WORKER_COREID=4 @@ -26,4 +26,5 @@ export LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" # --eval-command="run ../tests/fib.json" # ./sledgert -gdb ./sledgert +gdb --eval-command="handle all nostop" \ + ./sledgert diff --git a/runtime/tests/meet_deadline_percentage.py b/runtime/tests/meet_deadline_percentage.py index b831e09a7..0bc0e851b 100644 --- a/runtime/tests/meet_deadline_percentage.py +++ b/runtime/tests/meet_deadline_percentage.py @@ -54,6 +54,7 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): meet_deadline = 0 miss_deadline = 0 max_sc = 0 + total_interrupts = 0; fo = open(file_dir, "r+") for line in fo: line = line.strip() @@ -99,6 +100,8 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): #print("name:", name) if "throughput" in line: throughput = line.split(" ")[1] + interrupt = line.split(" ")[15] + total_interrupts += int(interrupt); ### calculate the execution time #if "memory" in line or "total_time" in line or "min" in line or "miss" in line or "meet" in line or "time " in line or "scheduling count" in line or "thread id" in line: # continue @@ -113,6 +116,7 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): print("total requests:", meet_deadline + miss_deadline) print("miss deadline percentage:", miss_deadline_percentage) print("throughput:", throughput) + print("total interrupts:", total_interrupts) for key,value in request_counter.items(): print(key, ":", str(value), "proportion:", (100*value)/(meet_deadline + miss_deadline)) From 298efe96a43ad356002d06b50fb0296cf9c1305b Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 29 Sep 2023 17:18:57 -0600 Subject: [PATCH 055/198] update debug.sh --- runtime/src/current_sandbox.c | 2 +- runtime/tests/debug.sh | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/runtime/src/current_sandbox.c b/runtime/src/current_sandbox.c index d75994d39..cc6d8ff08 100644 --- a/runtime/src/current_sandbox.c +++ b/runtime/src/current_sandbox.c @@ -57,8 +57,8 @@ current_sandbox_exit() sandbox_send_response(exiting_sandbox, 0); break; case SANDBOX_RUNNING_SYS: - sandbox_exit_error(exiting_sandbox); sandbox_send_response(exiting_sandbox, 1); + sandbox_exit_error(exiting_sandbox); break; default: panic("Cooperatively switching from a sandbox in a non-terminal %s state\n", diff --git a/runtime/tests/debug.sh b/runtime/tests/debug.sh index ff739ca8e..1dd5efd21 100755 --- a/runtime/tests/debug.sh +++ b/runtime/tests/debug.sh @@ -26,5 +26,6 @@ export LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" # --eval-command="run ../tests/fib.json" # ./sledgert -gdb --eval-command="handle all nostop" \ +gdb --eval-command="handle SIGUSR1 nostop" \ + --eval-command="handle SIGUSR1 noprint" \ ./sledgert From c4fa60ea22f4fba18a76609b962d9011608aa41e Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Sun, 1 Oct 2023 01:12:33 -0600 Subject: [PATCH 056/198] commit test_dequeue.cpp to tests folder --- runtime/tests/test_dequeue.cpp | 193 +++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 runtime/tests/test_dequeue.cpp diff --git a/runtime/tests/test_dequeue.cpp b/runtime/tests/test_dequeue.cpp new file mode 100644 index 000000000..aee4a85db --- /dev/null +++ b/runtime/tests/test_dequeue.cpp @@ -0,0 +1,193 @@ +// C++ implementation of De-queue using circular +// array +#include +using namespace std; + +// Maximum size of array or Dequeue +#define MAX 100 + +// A structure to represent a Deque +class Deque { + int arr[MAX]; + int front; + int rear; + int size; + +public: + Deque(int size) + { + front = -1; + rear = 0; + this->size = size; + } + + // Operations on Deque: + void insertfront(int key); + void insertrear(int key); + void deletefront(); + void deleterear(); + bool isFull(); + bool isEmpty(); + int getFront(); + int getRear(); +}; + +// Checks whether Deque is full or not. +bool Deque::isFull() +{ + return ((front == 0 && rear == size - 1) + || front == rear + 1); +} + +// Checks whether Deque is empty or not. +bool Deque::isEmpty() { return (front == -1); } + +// Inserts an element at front +void Deque::insertfront(int key) +{ + // check whether Deque if full or not + if (isFull()) { + cout << "Overflow\n" << endl; + return; + } + + // If queue is initially empty + if (front == -1) { + front = 0; + rear = 0; + } + + // front is at first position of queue + else if (front == 0) + front = size - 1; + + else // decrement front end by '1' + front = front - 1; + + // insert current element into Deque + arr[front] = key; +} + +// function to inset element at rear end +// of Deque. +void Deque ::insertrear(int key) +{ + if (isFull()) { + cout << " Overflow\n " << endl; + return; + } + + // If queue is initially empty + if (front == -1) { + front = 0; + rear = 0; + } + + // rear is at last position of queue + else if (rear == size - 1) + rear = 0; + + // increment rear end by '1' + else + rear = rear + 1; + + // insert current element into Deque + arr[rear] = key; +} + +// Deletes element at front end of Deque +void Deque ::deletefront() +{ + // check whether Deque is empty or not + if (isEmpty()) { + cout << "Queue Underflow\n" << endl; + return; + } + + // Deque has only one element + if (front == rear) { + front = -1; + rear = -1; + } + else + // back to initial position + if (front == size - 1) + front = 0; + + else // increment front by '1' to remove current + // front value from Deque + front = front + 1; +} + +// Delete element at rear end of Deque +void Deque::deleterear() +{ + if (isEmpty()) { + cout << " Underflow\n" << endl; + return; + } + + // Deque has only one element + if (front == rear) { + front = -1; + rear = -1; + } + else if (rear == 0) + rear = size - 1; + else + rear = rear - 1; +} + +// Returns front element of Deque +int Deque::getFront() +{ + // check whether Deque is empty or not + if (isEmpty()) { + cout << " Underflow\n" << endl; + return -1; + } + return arr[front]; +} + +// function return rear element of Deque +int Deque::getRear() +{ + // check whether Deque is empty or not + if (isEmpty() || rear < 0) { + cout << " Underflow\n" << endl; + return -1; + } + return arr[rear]; +} + +// Driver code +int main() +{ + Deque dq(5); + + // Function calls + cout << "Insert element at rear end : 5 \n"; + dq.insertrear(5); + + cout << "insert element at rear end : 10 \n"; + dq.insertrear(10); + + cout << "get rear element " + << " " << dq.getRear() << endl; + + dq.deleterear(); + cout << "After delete rear element new rear" + << " become " << dq.getRear() << endl; + + cout << "inserting element at front end \n"; + dq.insertfront(15); + + cout << "get front element " + << " " << dq.getFront() << endl; + + dq.deletefront(); + + cout << "After delete front element new " + << "front become " << dq.getFront() << endl; + return 0; +} From 64e433694125cacf42f9a0ca95d7b092d67baf3b Mon Sep 17 00:00:00 2001 From: xiaosuGW Date: Tue, 3 Oct 2023 23:21:16 -0600 Subject: [PATCH 057/198] 1. fix bug: sandbox_set_as_running_sys() failed with assert sandbox state not in RUNNING_USER because sandbox state is set to PREEMPTED, but it hasn't been context swithed out. 2. When preempt a sandbox, worker enqueue the preempted sandbox to its local preempted fifo queue, dispatcher thread will move all sandbox from worker's preempted queue to its typed queue, thus reducing lock for the typed queue --- runtime/include/local_preempted_fifo_queue.h | 7 ++ runtime/include/request_fifo_queue.h | 13 ++++ runtime/include/request_typed_queue.h | 2 +- runtime/include/sandbox_set_as_running_sys.h | 5 +- runtime/include/scheduler.h | 35 +++++---- runtime/src/listener_thread.c | 12 +++ runtime/src/local_preempted_fifo_queue.c | 81 ++++++++++++++++++++ runtime/src/request_typed_queue.c | 12 ++- runtime/src/worker_thread.c | 2 + 9 files changed, 143 insertions(+), 26 deletions(-) create mode 100644 runtime/include/local_preempted_fifo_queue.h create mode 100644 runtime/include/request_fifo_queue.h create mode 100644 runtime/src/local_preempted_fifo_queue.c diff --git a/runtime/include/local_preempted_fifo_queue.h b/runtime/include/local_preempted_fifo_queue.h new file mode 100644 index 000000000..9bd0e83ec --- /dev/null +++ b/runtime/include/local_preempted_fifo_queue.h @@ -0,0 +1,7 @@ +#pragma once + +#include "request_fifo_queue.h" + +void local_preempted_fifo_queue_init(); +struct sandbox * pop_worker_preempted_queue(int worker_id, struct request_fifo_queue * queue, uint64_t * tsc); +int push_to_preempted_queue(struct sandbox *sandbox, uint64_t tsc); diff --git a/runtime/include/request_fifo_queue.h b/runtime/include/request_fifo_queue.h new file mode 100644 index 000000000..3b4fbe088 --- /dev/null +++ b/runtime/include/request_fifo_queue.h @@ -0,0 +1,13 @@ +#pragma once +#include +#include + +#define RQUEUE_QUEUE_LEN 256 + +struct request_fifo_queue { + struct sandbox *rqueue[RQUEUE_QUEUE_LEN]; + unsigned int rqueue_tail; + unsigned int rqueue_head; + uint64_t tsqueue[RQUEUE_QUEUE_LEN]; +}; + diff --git a/runtime/include/request_typed_queue.h b/runtime/include/request_typed_queue.h index 458aa07a5..0b818b874 100644 --- a/runtime/include/request_typed_queue.h +++ b/runtime/include/request_typed_queue.h @@ -19,7 +19,7 @@ struct request_typed_queue { double ratio; struct sandbox *rqueue[RQUEUE_LEN]; unsigned int rqueue_tail; - _Atomic unsigned int rqueue_head; + unsigned int rqueue_head; uint64_t tsqueue[RQUEUE_LEN]; // Profiling variables diff --git a/runtime/include/sandbox_set_as_running_sys.h b/runtime/include/sandbox_set_as_running_sys.h index a77a69788..6f1a001a1 100644 --- a/runtime/include/sandbox_set_as_running_sys.h +++ b/runtime/include/sandbox_set_as_running_sys.h @@ -55,7 +55,10 @@ sandbox_set_as_running_sys(struct sandbox *sandbox, sandbox_state_t last_state) static inline void sandbox_syscall(struct sandbox *sandbox) { - assert(sandbox->state == SANDBOX_RUNNING_USER); + /* In SANDBOX_PREEMPTED state in case that call sandbox_preempt() first, but haven't done + * context switch to another sandbox + */ + assert(sandbox->state == SANDBOX_RUNNING_USER || sandbox->state == SANDBOX_PREEMPTED); sandbox_set_as_running_sys(sandbox, SANDBOX_RUNNING_USER); sandbox_process_scheduler_updates(sandbox); diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index 3eaff4da0..4c6aca68f 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -27,6 +27,7 @@ #include "sandbox_perf_log.h" #include "request_typed_queue.h" #include "listener_thread.h" +#include "local_preempted_fifo_queue.h" extern thread_local bool pthread_stop; extern uint32_t runtime_worker_group_size; @@ -327,28 +328,28 @@ scheduler_preemptive_sched(ucontext_t *interrupted_context) // printf ("Worker #%d interrupted sandbox #%lu\n", global_worker_thread_idx, interrupted_sandbox->id); scheduler_process_policy_specific_updates_on_interrupts(interrupted_sandbox); - /* Delete current sandbox from local queue if dispatcher is DISPATCHER_SHINJUKU */ - if (dispatcher == DISPATCHER_SHINJUKU) { - local_runqueue_delete(interrupted_sandbox); - sandbox_preempt(interrupted_sandbox); - // Write back global at idx 0 - wasm_globals_set_i64(&interrupted_sandbox->globals, 0, sledge_abi__current_wasm_module_instance.abi.wasmg_0, + /* Delete current sandbox from local queue if dispatcher is DISPATCHER_SHINJUKU */ + if (dispatcher == DISPATCHER_SHINJUKU) { + local_runqueue_delete(interrupted_sandbox); + sandbox_preempt(interrupted_sandbox); + // Write back global at idx 0 + wasm_globals_set_i64(&interrupted_sandbox->globals, 0, sledge_abi__current_wasm_module_instance.abi.wasmg_0, true); - arch_context_save_slow(&interrupted_sandbox->ctxt, &interrupted_context->uc_mcontext); - int req_type = interrupted_sandbox->route->request_type; - push_to_rqueue(dispatcher_id, interrupted_sandbox, request_type_queue[dispatcher_id][req_type - 1], __getcycles(), 2); - - struct sandbox *next = scheduler_get_next(); - /* next might be NULL because we delete the current sandbox from the runqueue */ - if (next) { - scheduler_preemptive_switch_to(interrupted_context, next); + arch_context_save_slow(&interrupted_sandbox->ctxt, &interrupted_context->uc_mcontext); + int ret = push_to_preempted_queue(interrupted_sandbox, __getcycles()); + assert(ret != -1); + + struct sandbox *next = scheduler_get_next(); + /* next might be NULL because we delete the current sandbox from the runqueue */ + if (next) { + scheduler_preemptive_switch_to(interrupted_context, next); + } + return; } - return; - } struct sandbox *next = scheduler_get_next(); - /* Assumption: the current sandbox is on the runqueue, so the scheduler should always return something */ + /* Assumption: the current sandbox is on the runqueue, so the scheduler should always return something */ assert(next != NULL); /* If current equals next, no switch is necessary, so resume execution */ diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 18c7cf1c2..a93031afb 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -16,11 +16,13 @@ #include "http_session_perf_log.h" #include "sandbox_set_as_runnable.h" #include "request_typed_queue.h" +#include "local_preempted_fifo_queue.h" struct perf_window * worker_perf_windows[1024]; struct priority_queue * worker_queues[1024]; struct binary_tree * worker_binary_trees[1024]; struct ps_list_head * worker_lists[1024]; +struct request_fifo_queue * worker_preempted_queue[1024]; extern _Atomic uint64_t worker_queuing_cost[1024]; //struct sandbox *urgent_request[1024] = { NULL }; @@ -743,6 +745,16 @@ void shinjuku_dispatch_different_core() { void shinjuku_dispatch() { for (uint32_t i = 0; i < runtime_worker_group_size; ++i) { + /* move all preempted sandboxes from worker to dispatcher's typed queue */ + struct request_fifo_queue * preempted_queue = worker_preempted_queue[worker_list[i]]; + assert(preempted_queue != NULL); + uint64_t tsc = 0; + struct sandbox * preempted_sandbox = pop_worker_preempted_queue(worker_list[i], preempted_queue, &tsc); + while(preempted_sandbox != NULL) { + uint8_t req_type = preempted_sandbox->route->request_type; + push_to_rqueue(dispatcher_thread_idx, preempted_sandbox, request_type_queue[dispatcher_thread_idx][req_type - 1], tsc, 1); + preempted_sandbox = pop_worker_preempted_queue(worker_list[i], preempted_queue, &tsc); + } /* core is idle */ if ((1 << i) & free_workers[dispatcher_thread_idx]) { int selected_queue_type = -1; diff --git a/runtime/src/local_preempted_fifo_queue.c b/runtime/src/local_preempted_fifo_queue.c new file mode 100644 index 000000000..57bf05da0 --- /dev/null +++ b/runtime/src/local_preempted_fifo_queue.c @@ -0,0 +1,81 @@ +#include +#include +#include + +#include "panic.h" +#include "likely.h" +#include "request_fifo_queue.h" + +extern thread_local int global_worker_thread_idx; +extern struct request_fifo_queue * worker_preempted_queue[1024]; +thread_local static struct request_fifo_queue * local_preempted_queue = NULL; + +/* + * n_resas the number of reserved workers. Leaving the last n_resas workers as the reserved workers + */ +struct request_fifo_queue * request_fifo_queue_init() { + struct request_fifo_queue * queue = (struct request_fifo_queue*) malloc(sizeof(struct request_fifo_queue)); + + assert(queue != NULL); + + queue->rqueue_tail = 0; + queue->rqueue_head = 0; + memset(queue->rqueue, 0, RQUEUE_QUEUE_LEN * sizeof(struct sandbox*)); + return queue; +} + +int push_to_queue(struct request_fifo_queue * queue, struct sandbox *sandbox, uint64_t tsc) { + assert(sandbox != NULL); + assert(queue != NULL); + + uint32_t head = queue->rqueue_head; + + if (unlikely(head - queue->rqueue_tail == RQUEUE_QUEUE_LEN)) { + panic("request fifo queue is full\n"); + return -1; + } else { + queue->tsqueue[head & (RQUEUE_QUEUE_LEN - 1)] = tsc; + queue->rqueue[head & (RQUEUE_QUEUE_LEN - 1)] = sandbox; + queue->rqueue_head++; + return 0; + } + +} + +/* called by worker thread */ +int push_to_preempted_queue(struct sandbox *sandbox, uint64_t tsc) { + assert(sandbox != NULL); + return push_to_queue(local_preempted_queue, sandbox, tsc); +} + +/* + * pop one item from the tail of the queue + * tsc is the timestamp of the popped sandbox, only be set when popped sandbox is not NULL + */ +struct sandbox * pop_queue(struct request_fifo_queue * queue, uint64_t * tsc) { + assert(queue != NULL); + + struct sandbox *popped_sandbox = NULL; + *tsc = 0; + + if (queue->rqueue_head > queue->rqueue_tail) { + popped_sandbox = queue->rqueue[queue->rqueue_tail & (RQUEUE_QUEUE_LEN - 1)]; + *tsc = queue->tsqueue[queue->rqueue_tail & (RQUEUE_QUEUE_LEN - 1)]; + queue->rqueue_tail++; + } + + return popped_sandbox; +} + +/* called by dispatcher thread */ +struct sandbox * pop_worker_preempted_queue(int worker_id, struct request_fifo_queue * queue, uint64_t * tsc) { + struct request_fifo_queue * preempted_queue = worker_preempted_queue[worker_id]; + assert(preempted_queue != NULL); + + return pop_queue(preempted_queue, tsc); +} + +void local_preempted_fifo_queue_init() { + local_preempted_queue = request_fifo_queue_init(); + worker_preempted_queue[global_worker_thread_idx] = local_preempted_queue; +} diff --git a/runtime/src/request_typed_queue.c b/runtime/src/request_typed_queue.c index 144d31d5e..60a18b9b0 100644 --- a/runtime/src/request_typed_queue.c +++ b/runtime/src/request_typed_queue.c @@ -1,5 +1,4 @@ #include -#include #include #include "panic.h" @@ -13,7 +12,7 @@ request_typed_queue_init(uint8_t type, uint32_t n_resas) { queue->mean_ns = 0; queue->deadline = 0; queue->rqueue_tail = 0; - atomic_init(&queue->rqueue_head, 0); + queue->rqueue_head = 0; queue->n_resas = n_resas; for (unsigned int i = 0; i < n_resas; ++i) { queue->res_workers[i] = i; @@ -35,16 +34,15 @@ request_typed_queue_init(uint8_t type, uint32_t n_resas) { int push_to_rqueue(uint8_t dispatcher_id, struct sandbox *sandbox, struct request_typed_queue *rtype, uint64_t tsc, int flag) { assert(sandbox != NULL); - uint32_t head = atomic_load(&rtype->rqueue_head); + uint32_t head = rtype->rqueue_head; if (unlikely(head - rtype->rqueue_tail == RQUEUE_LEN)) { panic("Dispatcher dropped request as type %hhu because queue is full\n", rtype->type); return -1; } else { - //PSP_DEBUG("Pushed one request to queue " << req_type_str[static_cast(rtype.type)]); - uint32_t previous_head = atomic_fetch_add(&rtype->rqueue_head, 1); - rtype->tsqueue[previous_head & (RQUEUE_LEN - 1)] = tsc; - rtype->rqueue[previous_head & (RQUEUE_LEN - 1)] = sandbox; + rtype->tsqueue[head & (RQUEUE_LEN - 1)] = tsc; + rtype->rqueue[head & (RQUEUE_LEN - 1)] = sandbox; + rtype->rqueue_head++; return 0; } } diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c index a7d7db850..6950584e4 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c @@ -18,6 +18,7 @@ #include "worker_thread.h" #include "tenant_functions.h" #include "priority_queue.h" +#include "local_preempted_fifo_queue.h" /*************************** * Worker Thread State * @@ -87,6 +88,7 @@ worker_thread_main(void *argument) perf_window_init(); scheduler_runqueue_initialize(); + local_preempted_fifo_queue_init(); /* Initialize memory logging, set 100M memory for logging */ mem_log_init2(1024*1024*1024, sandbox_perf_log); From 18289df3738cc076972adc78961d2c852a04071e Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 4 Oct 2023 18:17:39 -0600 Subject: [PATCH 058/198] fix bug: for shinjuku algo, when context switch to another sandbox, the previous one was deleted from the local runqueue, but still will re-exeucted by the current context switch after the signal handler returned --- runtime/include/local_runqueue.h | 3 ++ runtime/include/sandbox_set_as_running_user.h | 1 + runtime/include/sandbox_types.h | 6 ++- runtime/include/scheduler.h | 44 +++++++++++-------- runtime/src/current_sandbox.c | 2 + runtime/src/listener_thread.c | 4 +- runtime/src/local_preempted_fifo_queue.c | 1 + runtime/src/local_runqueue.c | 7 +++ runtime/src/local_runqueue_binary_tree.c | 30 ++++++++++--- runtime/src/software_interrupt.c | 2 - 10 files changed, 69 insertions(+), 31 deletions(-) diff --git a/runtime/include/local_runqueue.h b/runtime/include/local_runqueue.h index ba986f2c6..9456480de 100644 --- a/runtime/include/local_runqueue.h +++ b/runtime/include/local_runqueue.h @@ -11,6 +11,7 @@ typedef uint64_t (*local_runqueue_try_add_fn_t_idx)(int index, struct sandbox *, typedef bool (*local_runqueue_is_empty_fn_t)(void); typedef void (*local_runqueue_delete_fn_t)(struct sandbox *sandbox); typedef struct sandbox *(*local_runqueue_get_next_fn_t)(); +typedef int (*local_runqueue_get_height_fn_t)(); struct local_runqueue_config { local_runqueue_add_fn_t add_fn; @@ -19,6 +20,7 @@ struct local_runqueue_config { local_runqueue_is_empty_fn_t is_empty_fn; local_runqueue_delete_fn_t delete_fn; local_runqueue_get_next_fn_t get_next_fn; + local_runqueue_get_height_fn_t get_height_fn; }; void local_runqueue_add(struct sandbox *); @@ -28,3 +30,4 @@ void local_runqueue_delete(struct sandbox *); bool local_runqueue_is_empty(); struct sandbox *local_runqueue_get_next(); void local_runqueue_initialize(struct local_runqueue_config *config); +int local_runqueue_get_height(); diff --git a/runtime/include/sandbox_set_as_running_user.h b/runtime/include/sandbox_set_as_running_user.h index 3d784fc6b..b81680718 100644 --- a/runtime/include/sandbox_set_as_running_user.h +++ b/runtime/include/sandbox_set_as_running_user.h @@ -25,6 +25,7 @@ sandbox_set_as_running_user(struct sandbox *sandbox, sandbox_state_t last_state) break; } case SANDBOX_PREEMPTED: { + sandbox->start_ts_running_user = now; break; } default: { diff --git a/runtime/include/sandbox_types.h b/runtime/include/sandbox_types.h index 8b97220ee..848463aab 100644 --- a/runtime/include/sandbox_types.h +++ b/runtime/include/sandbox_types.h @@ -83,7 +83,9 @@ struct sandbox { int context_switch_to; /* 1 means context switch to base, 2 means context swtich to next sandbox */ uint64_t ret[5]; uint64_t estimated_cost; /* estimated execution cost */ - int global_worker_thread_idx; /* which thread in a global view processes this sandbox. + int global_worker_thread_idx; /* which thread in a global view processes this sandbox. pause and restore the sandbox must be done in the same thread */ - int group_worker_thread_idx; /* what's the thread index in the group */ + int group_worker_thread_idx; /* what's the thread index in the group */ + uint64_t start_ts_running_user; /* the start timestamp to run user, it will be updated when resume to run user */ + } PAGE_ALIGNED; diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index 4c6aca68f..3e20910bc 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -29,6 +29,7 @@ #include "listener_thread.h" #include "local_preempted_fifo_queue.h" +extern thread_local uint32_t interrupts; extern thread_local bool pthread_stop; extern uint32_t runtime_worker_group_size; extern _Atomic uint32_t free_workers[10]; @@ -330,21 +331,30 @@ scheduler_preemptive_sched(ucontext_t *interrupted_context) /* Delete current sandbox from local queue if dispatcher is DISPATCHER_SHINJUKU */ if (dispatcher == DISPATCHER_SHINJUKU) { - local_runqueue_delete(interrupted_sandbox); - sandbox_preempt(interrupted_sandbox); - // Write back global at idx 0 - wasm_globals_set_i64(&interrupted_sandbox->globals, 0, sledge_abi__current_wasm_module_instance.abi.wasmg_0, + uint64_t duration = (__getcycles() - interrupted_sandbox->start_ts_running_user) / runtime_processor_speed_MHz; + if (duration >= 50 && local_runqueue_get_height() >= 1) { + local_runqueue_delete(interrupted_sandbox); + sandbox_preempt(interrupted_sandbox); + // Write back global at idx 0 + wasm_globals_set_i64(&interrupted_sandbox->globals, 0, sledge_abi__current_wasm_module_instance.abi.wasmg_0, true); - arch_context_save_slow(&interrupted_sandbox->ctxt, &interrupted_context->uc_mcontext); - int ret = push_to_preempted_queue(interrupted_sandbox, __getcycles()); - assert(ret != -1); - - struct sandbox *next = scheduler_get_next(); - /* next might be NULL because we delete the current sandbox from the runqueue */ - if (next) { - scheduler_preemptive_switch_to(interrupted_context, next); - } - return; + arch_context_save_slow(&interrupted_sandbox->ctxt, &interrupted_context->uc_mcontext); + int ret = push_to_preempted_queue(interrupted_sandbox, __getcycles()); + assert(ret != -1); + + interrupts++; + struct sandbox *next = scheduler_get_next(); + assert(next != NULL); + scheduler_preemptive_switch_to(interrupted_context, next); + } else { + /* current sandbox shouldn't be interrupted becuase it runs less than 50us, or it is the only sandbox in the + local runqueue, so return directly, the current context isn't switched and will resume when single handler + returns + */ + sandbox_interrupt_return(interrupted_sandbox, SANDBOX_RUNNING_USER); + return; + } + return; } struct sandbox *next = scheduler_get_next(); @@ -371,6 +381,7 @@ scheduler_preemptive_sched(ucontext_t *interrupted_context) true); arch_context_save_slow(&interrupted_sandbox->ctxt, &interrupted_context->uc_mcontext); + interrupts++; scheduler_preemptive_switch_to(interrupted_context, next); } @@ -416,7 +427,6 @@ scheduler_switch_to_base_context(struct arch_context *current_context) arch_context_switch(current_context, &worker_thread_base_context); } - /* The idle_loop is executed by the base_context. This should not be called directly */ static inline void scheduler_idle_loop() @@ -538,12 +548,10 @@ scheduler_cooperative_sched(bool add_to_cleanup_queue) int virtual_id = global_worker_thread_idx - dispatcher_id * runtime_worker_group_size; atomic_fetch_or(&free_workers[dispatcher_id], 1 << virtual_id); } - //printf("finish one request\n"); - scheduler_switch_to_base_context(exiting_context); + scheduler_switch_to_base_context(exiting_context); } } - static inline bool scheduler_worker_would_preempt(int worker_idx) { diff --git a/runtime/src/current_sandbox.c b/runtime/src/current_sandbox.c index cc6d8ff08..ac8e48040 100644 --- a/runtime/src/current_sandbox.c +++ b/runtime/src/current_sandbox.c @@ -140,6 +140,8 @@ current_sandbox_init() /* Initialize sandbox globals. Needs to run in user state */ module_initialize_globals(current_module); + /* set start_ts_running_user for sandbox before it starts running */ + sandbox->start_ts_running_user = __getcycles(); return sandbox; err: diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index a93031afb..9ad27a11a 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -774,8 +774,8 @@ void shinjuku_dispatch() { //check if the current sandbox is running longer than the specified time duration struct sandbox *current = current_sandboxes[worker_list[i]]; if (!current) continue; //In case that worker thread hasn't call current_sandbox_set to set the current sandbox - uint64_t duration = (__getcycles() - current->timestamp_of.last_state_change) / runtime_processor_speed_MHz; - if (duration >= 50 && current->state == SANDBOX_RUNNING_USER) { + uint64_t duration = (__getcycles() - current->start_ts_running_user) / runtime_processor_speed_MHz; + if (duration >= 50 && (current->state == SANDBOX_RUNNING_USER || current->state == SANDBOX_RUNNING_SYS)) { int selected_queue_type = -1; struct sandbox *sandbox = shinjuku_peek_selected_sandbox(&selected_queue_type); if (!sandbox) return; // queue is empty diff --git a/runtime/src/local_preempted_fifo_queue.c b/runtime/src/local_preempted_fifo_queue.c index 57bf05da0..0c346ef27 100644 --- a/runtime/src/local_preempted_fifo_queue.c +++ b/runtime/src/local_preempted_fifo_queue.c @@ -61,6 +61,7 @@ struct sandbox * pop_queue(struct request_fifo_queue * queue, uint64_t * tsc) { if (queue->rqueue_head > queue->rqueue_tail) { popped_sandbox = queue->rqueue[queue->rqueue_tail & (RQUEUE_QUEUE_LEN - 1)]; *tsc = queue->tsqueue[queue->rqueue_tail & (RQUEUE_QUEUE_LEN - 1)]; + queue->rqueue[queue->rqueue_tail & (RQUEUE_QUEUE_LEN - 1)] = NULL; queue->rqueue_tail++; } diff --git a/runtime/src/local_runqueue.c b/runtime/src/local_runqueue.c index 73dce85e3..ff283c5ff 100644 --- a/runtime/src/local_runqueue.c +++ b/runtime/src/local_runqueue.c @@ -76,6 +76,13 @@ local_runqueue_is_empty() return local_runqueue.is_empty_fn(); } +/** + * Get height if run queue is a binary search tree + */ + +int local_runqueue_get_height() { + return local_runqueue.get_height_fn(); +} /** * Get next sandbox from run queue, where next is defined by * @returns sandbox (or NULL?) diff --git a/runtime/src/local_runqueue_binary_tree.c b/runtime/src/local_runqueue_binary_tree.c index 7e304eac4..67ef39a6a 100644 --- a/runtime/src/local_runqueue_binary_tree.c +++ b/runtime/src/local_runqueue_binary_tree.c @@ -41,8 +41,10 @@ local_runqueue_binary_tree_is_empty() void local_runqueue_binary_tree_add(struct sandbox *sandbox) { + assert(sandbox != NULL); + lock_node_t node_lock = {}; - lock_lock(&local_runqueue_binary_tree->lock, &node_lock); + lock_lock(&local_runqueue_binary_tree->lock, &node_lock); local_runqueue_binary_tree->root = insert(local_runqueue_binary_tree, local_runqueue_binary_tree->root, sandbox); lock_unlock(&local_runqueue_binary_tree->lock, &node_lock); } @@ -50,6 +52,8 @@ local_runqueue_binary_tree_add(struct sandbox *sandbox) void local_runqueue_binary_tree_add_index(int index, struct sandbox *sandbox) { + assert(sandbox != NULL); + struct binary_tree *binary_tree = worker_binary_trees[index]; lock_node_t node_lock = {}; lock_lock(&binary_tree->lock, &node_lock); @@ -71,7 +75,12 @@ local_runqueue_binary_tree_delete(struct sandbox *sandbox) bool deleted = false; local_runqueue_binary_tree->root = delete_i(local_runqueue_binary_tree, local_runqueue_binary_tree->root, sandbox, &deleted); lock_unlock(&local_runqueue_binary_tree->lock, &node_lock); - if (deleted == false) panic("Tried to delete sandbox %lu from runqueue, but was not present\n", sandbox->id); + if (deleted == false) { + panic("Tried to delete sandbox %lu state %d from runqueue %p, but was not present\n", + sandbox->id, sandbox->state, local_runqueue_binary_tree); + } + + } /** @@ -122,6 +131,11 @@ local_runqueue_binary_tree_try_add_index(int index, struct sandbox *sandbox, boo } +int local_runqueue_binary_tree_get_height() { + assert (local_runqueue_binary_tree != NULL); + return findHeight(local_runqueue_binary_tree->root); +} + /** * Registers the PS variant with the polymorphic interface */ @@ -134,11 +148,13 @@ local_runqueue_binary_tree_initialize() worker_binary_trees[global_worker_thread_idx] = local_runqueue_binary_tree; /* Register Function Pointers for Abstract Scheduling API */ struct local_runqueue_config config = { .add_fn = local_runqueue_binary_tree_add, - .add_fn_idx = local_runqueue_binary_tree_add_index, - .try_add_fn_idx = local_runqueue_binary_tree_try_add_index, - .is_empty_fn = local_runqueue_binary_tree_is_empty, - .delete_fn = local_runqueue_binary_tree_delete, - .get_next_fn = local_runqueue_binary_tree_get_next }; + .add_fn_idx = local_runqueue_binary_tree_add_index, + .try_add_fn_idx = local_runqueue_binary_tree_try_add_index, + .is_empty_fn = local_runqueue_binary_tree_is_empty, + .delete_fn = local_runqueue_binary_tree_delete, + .get_next_fn = local_runqueue_binary_tree_get_next, + .get_height_fn = local_runqueue_binary_tree_get_height + }; local_runqueue_initialize(&config); } diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index 633ee383a..0a1db8901 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -182,8 +182,6 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void /* Global tenant promotions */ global_timeout_queue_process_promotions(); } - interrupts++; - //printf("preempt\n"); scheduler_preemptive_sched(interrupted_context); } else { /* We transition the sandbox to an interrupted state to exclude time propagating signals and From 2e40c66c57217ef61683ebe6b172a7d647f1fa97 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 4 Oct 2023 18:17:39 -0600 Subject: [PATCH 059/198] fix bug: for shinjuku algo, when it receives a sigalarm signal, the signal handler will do context switch to another sandbox. It first delete the sandbox from the local runqueue and get the next sandbox, howerver, sometimes, there is no more sandbox in the local runqueue, so the code just return and cause the bug that after sigal handler returns, the removed sandbox will be resumed immedaitely, when it finished, it try to remove itself from the local runqueue and couldn't find it. --- runtime/include/local_runqueue.h | 3 ++ runtime/include/sandbox_set_as_running_user.h | 1 + runtime/include/sandbox_types.h | 6 ++- runtime/include/scheduler.h | 44 +++++++++++-------- runtime/src/current_sandbox.c | 2 + runtime/src/listener_thread.c | 4 +- runtime/src/local_preempted_fifo_queue.c | 1 + runtime/src/local_runqueue.c | 7 +++ runtime/src/local_runqueue_binary_tree.c | 30 ++++++++++--- runtime/src/software_interrupt.c | 2 - 10 files changed, 69 insertions(+), 31 deletions(-) diff --git a/runtime/include/local_runqueue.h b/runtime/include/local_runqueue.h index ba986f2c6..9456480de 100644 --- a/runtime/include/local_runqueue.h +++ b/runtime/include/local_runqueue.h @@ -11,6 +11,7 @@ typedef uint64_t (*local_runqueue_try_add_fn_t_idx)(int index, struct sandbox *, typedef bool (*local_runqueue_is_empty_fn_t)(void); typedef void (*local_runqueue_delete_fn_t)(struct sandbox *sandbox); typedef struct sandbox *(*local_runqueue_get_next_fn_t)(); +typedef int (*local_runqueue_get_height_fn_t)(); struct local_runqueue_config { local_runqueue_add_fn_t add_fn; @@ -19,6 +20,7 @@ struct local_runqueue_config { local_runqueue_is_empty_fn_t is_empty_fn; local_runqueue_delete_fn_t delete_fn; local_runqueue_get_next_fn_t get_next_fn; + local_runqueue_get_height_fn_t get_height_fn; }; void local_runqueue_add(struct sandbox *); @@ -28,3 +30,4 @@ void local_runqueue_delete(struct sandbox *); bool local_runqueue_is_empty(); struct sandbox *local_runqueue_get_next(); void local_runqueue_initialize(struct local_runqueue_config *config); +int local_runqueue_get_height(); diff --git a/runtime/include/sandbox_set_as_running_user.h b/runtime/include/sandbox_set_as_running_user.h index 3d784fc6b..b81680718 100644 --- a/runtime/include/sandbox_set_as_running_user.h +++ b/runtime/include/sandbox_set_as_running_user.h @@ -25,6 +25,7 @@ sandbox_set_as_running_user(struct sandbox *sandbox, sandbox_state_t last_state) break; } case SANDBOX_PREEMPTED: { + sandbox->start_ts_running_user = now; break; } default: { diff --git a/runtime/include/sandbox_types.h b/runtime/include/sandbox_types.h index 8b97220ee..848463aab 100644 --- a/runtime/include/sandbox_types.h +++ b/runtime/include/sandbox_types.h @@ -83,7 +83,9 @@ struct sandbox { int context_switch_to; /* 1 means context switch to base, 2 means context swtich to next sandbox */ uint64_t ret[5]; uint64_t estimated_cost; /* estimated execution cost */ - int global_worker_thread_idx; /* which thread in a global view processes this sandbox. + int global_worker_thread_idx; /* which thread in a global view processes this sandbox. pause and restore the sandbox must be done in the same thread */ - int group_worker_thread_idx; /* what's the thread index in the group */ + int group_worker_thread_idx; /* what's the thread index in the group */ + uint64_t start_ts_running_user; /* the start timestamp to run user, it will be updated when resume to run user */ + } PAGE_ALIGNED; diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index 4c6aca68f..3e20910bc 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -29,6 +29,7 @@ #include "listener_thread.h" #include "local_preempted_fifo_queue.h" +extern thread_local uint32_t interrupts; extern thread_local bool pthread_stop; extern uint32_t runtime_worker_group_size; extern _Atomic uint32_t free_workers[10]; @@ -330,21 +331,30 @@ scheduler_preemptive_sched(ucontext_t *interrupted_context) /* Delete current sandbox from local queue if dispatcher is DISPATCHER_SHINJUKU */ if (dispatcher == DISPATCHER_SHINJUKU) { - local_runqueue_delete(interrupted_sandbox); - sandbox_preempt(interrupted_sandbox); - // Write back global at idx 0 - wasm_globals_set_i64(&interrupted_sandbox->globals, 0, sledge_abi__current_wasm_module_instance.abi.wasmg_0, + uint64_t duration = (__getcycles() - interrupted_sandbox->start_ts_running_user) / runtime_processor_speed_MHz; + if (duration >= 50 && local_runqueue_get_height() >= 1) { + local_runqueue_delete(interrupted_sandbox); + sandbox_preempt(interrupted_sandbox); + // Write back global at idx 0 + wasm_globals_set_i64(&interrupted_sandbox->globals, 0, sledge_abi__current_wasm_module_instance.abi.wasmg_0, true); - arch_context_save_slow(&interrupted_sandbox->ctxt, &interrupted_context->uc_mcontext); - int ret = push_to_preempted_queue(interrupted_sandbox, __getcycles()); - assert(ret != -1); - - struct sandbox *next = scheduler_get_next(); - /* next might be NULL because we delete the current sandbox from the runqueue */ - if (next) { - scheduler_preemptive_switch_to(interrupted_context, next); - } - return; + arch_context_save_slow(&interrupted_sandbox->ctxt, &interrupted_context->uc_mcontext); + int ret = push_to_preempted_queue(interrupted_sandbox, __getcycles()); + assert(ret != -1); + + interrupts++; + struct sandbox *next = scheduler_get_next(); + assert(next != NULL); + scheduler_preemptive_switch_to(interrupted_context, next); + } else { + /* current sandbox shouldn't be interrupted becuase it runs less than 50us, or it is the only sandbox in the + local runqueue, so return directly, the current context isn't switched and will resume when single handler + returns + */ + sandbox_interrupt_return(interrupted_sandbox, SANDBOX_RUNNING_USER); + return; + } + return; } struct sandbox *next = scheduler_get_next(); @@ -371,6 +381,7 @@ scheduler_preemptive_sched(ucontext_t *interrupted_context) true); arch_context_save_slow(&interrupted_sandbox->ctxt, &interrupted_context->uc_mcontext); + interrupts++; scheduler_preemptive_switch_to(interrupted_context, next); } @@ -416,7 +427,6 @@ scheduler_switch_to_base_context(struct arch_context *current_context) arch_context_switch(current_context, &worker_thread_base_context); } - /* The idle_loop is executed by the base_context. This should not be called directly */ static inline void scheduler_idle_loop() @@ -538,12 +548,10 @@ scheduler_cooperative_sched(bool add_to_cleanup_queue) int virtual_id = global_worker_thread_idx - dispatcher_id * runtime_worker_group_size; atomic_fetch_or(&free_workers[dispatcher_id], 1 << virtual_id); } - //printf("finish one request\n"); - scheduler_switch_to_base_context(exiting_context); + scheduler_switch_to_base_context(exiting_context); } } - static inline bool scheduler_worker_would_preempt(int worker_idx) { diff --git a/runtime/src/current_sandbox.c b/runtime/src/current_sandbox.c index cc6d8ff08..ac8e48040 100644 --- a/runtime/src/current_sandbox.c +++ b/runtime/src/current_sandbox.c @@ -140,6 +140,8 @@ current_sandbox_init() /* Initialize sandbox globals. Needs to run in user state */ module_initialize_globals(current_module); + /* set start_ts_running_user for sandbox before it starts running */ + sandbox->start_ts_running_user = __getcycles(); return sandbox; err: diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index a93031afb..9ad27a11a 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -774,8 +774,8 @@ void shinjuku_dispatch() { //check if the current sandbox is running longer than the specified time duration struct sandbox *current = current_sandboxes[worker_list[i]]; if (!current) continue; //In case that worker thread hasn't call current_sandbox_set to set the current sandbox - uint64_t duration = (__getcycles() - current->timestamp_of.last_state_change) / runtime_processor_speed_MHz; - if (duration >= 50 && current->state == SANDBOX_RUNNING_USER) { + uint64_t duration = (__getcycles() - current->start_ts_running_user) / runtime_processor_speed_MHz; + if (duration >= 50 && (current->state == SANDBOX_RUNNING_USER || current->state == SANDBOX_RUNNING_SYS)) { int selected_queue_type = -1; struct sandbox *sandbox = shinjuku_peek_selected_sandbox(&selected_queue_type); if (!sandbox) return; // queue is empty diff --git a/runtime/src/local_preempted_fifo_queue.c b/runtime/src/local_preempted_fifo_queue.c index 57bf05da0..0c346ef27 100644 --- a/runtime/src/local_preempted_fifo_queue.c +++ b/runtime/src/local_preempted_fifo_queue.c @@ -61,6 +61,7 @@ struct sandbox * pop_queue(struct request_fifo_queue * queue, uint64_t * tsc) { if (queue->rqueue_head > queue->rqueue_tail) { popped_sandbox = queue->rqueue[queue->rqueue_tail & (RQUEUE_QUEUE_LEN - 1)]; *tsc = queue->tsqueue[queue->rqueue_tail & (RQUEUE_QUEUE_LEN - 1)]; + queue->rqueue[queue->rqueue_tail & (RQUEUE_QUEUE_LEN - 1)] = NULL; queue->rqueue_tail++; } diff --git a/runtime/src/local_runqueue.c b/runtime/src/local_runqueue.c index 73dce85e3..ff283c5ff 100644 --- a/runtime/src/local_runqueue.c +++ b/runtime/src/local_runqueue.c @@ -76,6 +76,13 @@ local_runqueue_is_empty() return local_runqueue.is_empty_fn(); } +/** + * Get height if run queue is a binary search tree + */ + +int local_runqueue_get_height() { + return local_runqueue.get_height_fn(); +} /** * Get next sandbox from run queue, where next is defined by * @returns sandbox (or NULL?) diff --git a/runtime/src/local_runqueue_binary_tree.c b/runtime/src/local_runqueue_binary_tree.c index 7e304eac4..67ef39a6a 100644 --- a/runtime/src/local_runqueue_binary_tree.c +++ b/runtime/src/local_runqueue_binary_tree.c @@ -41,8 +41,10 @@ local_runqueue_binary_tree_is_empty() void local_runqueue_binary_tree_add(struct sandbox *sandbox) { + assert(sandbox != NULL); + lock_node_t node_lock = {}; - lock_lock(&local_runqueue_binary_tree->lock, &node_lock); + lock_lock(&local_runqueue_binary_tree->lock, &node_lock); local_runqueue_binary_tree->root = insert(local_runqueue_binary_tree, local_runqueue_binary_tree->root, sandbox); lock_unlock(&local_runqueue_binary_tree->lock, &node_lock); } @@ -50,6 +52,8 @@ local_runqueue_binary_tree_add(struct sandbox *sandbox) void local_runqueue_binary_tree_add_index(int index, struct sandbox *sandbox) { + assert(sandbox != NULL); + struct binary_tree *binary_tree = worker_binary_trees[index]; lock_node_t node_lock = {}; lock_lock(&binary_tree->lock, &node_lock); @@ -71,7 +75,12 @@ local_runqueue_binary_tree_delete(struct sandbox *sandbox) bool deleted = false; local_runqueue_binary_tree->root = delete_i(local_runqueue_binary_tree, local_runqueue_binary_tree->root, sandbox, &deleted); lock_unlock(&local_runqueue_binary_tree->lock, &node_lock); - if (deleted == false) panic("Tried to delete sandbox %lu from runqueue, but was not present\n", sandbox->id); + if (deleted == false) { + panic("Tried to delete sandbox %lu state %d from runqueue %p, but was not present\n", + sandbox->id, sandbox->state, local_runqueue_binary_tree); + } + + } /** @@ -122,6 +131,11 @@ local_runqueue_binary_tree_try_add_index(int index, struct sandbox *sandbox, boo } +int local_runqueue_binary_tree_get_height() { + assert (local_runqueue_binary_tree != NULL); + return findHeight(local_runqueue_binary_tree->root); +} + /** * Registers the PS variant with the polymorphic interface */ @@ -134,11 +148,13 @@ local_runqueue_binary_tree_initialize() worker_binary_trees[global_worker_thread_idx] = local_runqueue_binary_tree; /* Register Function Pointers for Abstract Scheduling API */ struct local_runqueue_config config = { .add_fn = local_runqueue_binary_tree_add, - .add_fn_idx = local_runqueue_binary_tree_add_index, - .try_add_fn_idx = local_runqueue_binary_tree_try_add_index, - .is_empty_fn = local_runqueue_binary_tree_is_empty, - .delete_fn = local_runqueue_binary_tree_delete, - .get_next_fn = local_runqueue_binary_tree_get_next }; + .add_fn_idx = local_runqueue_binary_tree_add_index, + .try_add_fn_idx = local_runqueue_binary_tree_try_add_index, + .is_empty_fn = local_runqueue_binary_tree_is_empty, + .delete_fn = local_runqueue_binary_tree_delete, + .get_next_fn = local_runqueue_binary_tree_get_next, + .get_height_fn = local_runqueue_binary_tree_get_height + }; local_runqueue_initialize(&config); } diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index 633ee383a..0a1db8901 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -182,8 +182,6 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void /* Global tenant promotions */ global_timeout_queue_process_promotions(); } - interrupts++; - //printf("preempt\n"); scheduler_preemptive_sched(interrupted_context); } else { /* We transition the sandbox to an interrupted state to exclude time propagating signals and From 421bb5cf743d390fba1eb5aa9613c8973aca441f Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 5 Oct 2023 00:05:01 -0600 Subject: [PATCH 060/198] 1. recover wrong change for assert failure at sandbox->state == SANDBOX_RUNNING_USER in sandbox_set_as_running_sys(). 2. update meet_deadline_percentage.py --- runtime/include/sandbox_set_as_running_sys.h | 5 +---- runtime/tests/meet_deadline_percentage.py | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/runtime/include/sandbox_set_as_running_sys.h b/runtime/include/sandbox_set_as_running_sys.h index 6f1a001a1..a77a69788 100644 --- a/runtime/include/sandbox_set_as_running_sys.h +++ b/runtime/include/sandbox_set_as_running_sys.h @@ -55,10 +55,7 @@ sandbox_set_as_running_sys(struct sandbox *sandbox, sandbox_state_t last_state) static inline void sandbox_syscall(struct sandbox *sandbox) { - /* In SANDBOX_PREEMPTED state in case that call sandbox_preempt() first, but haven't done - * context switch to another sandbox - */ - assert(sandbox->state == SANDBOX_RUNNING_USER || sandbox->state == SANDBOX_PREEMPTED); + assert(sandbox->state == SANDBOX_RUNNING_USER); sandbox_set_as_running_sys(sandbox, SANDBOX_RUNNING_USER); sandbox_process_scheduler_updates(sandbox); diff --git a/runtime/tests/meet_deadline_percentage.py b/runtime/tests/meet_deadline_percentage.py index 0bc0e851b..c7dddbd41 100644 --- a/runtime/tests/meet_deadline_percentage.py +++ b/runtime/tests/meet_deadline_percentage.py @@ -123,7 +123,7 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): for key,value in total_time_dist.items(): a = np.array(value) p = np.percentile(a, int(percentage)) - print(key + " " + percentage + " percentage is:" + str(p) + " mean is:" + str(np.mean(value)) + " max latency is:" + str(max_latency_dist[key])) + print(key + " " + percentage + " percentile is:" + str(p) + " mean is:" + str(np.mean(value)) + " max latency is:" + str(max_latency_dist[key])) #total_cpu_times = 0 #for key,value in meet_deadline_dist.items(): # total_cpu_times += value * fun_execution_time[key] From 98f92363f14d58f912c5bd9da665520bf5a21d05 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 5 Oct 2023 00:53:51 -0600 Subject: [PATCH 061/198] recover global typed queue to one dimensional array because now only the dispatcher thread will put requests to it, workers won't do it --- runtime/include/request_typed_queue.h | 6 +-- runtime/include/scheduler.h | 1 - runtime/include/tenant_functions.h | 5 +-- runtime/src/listener_thread.c | 54 +++++++++++---------------- runtime/src/request_typed_queue.c | 2 +- runtime/src/runtime.c | 8 +--- 6 files changed, 26 insertions(+), 50 deletions(-) diff --git a/runtime/include/request_typed_queue.h b/runtime/include/request_typed_queue.h index 0b818b874..b9b6f76c3 100644 --- a/runtime/include/request_typed_queue.h +++ b/runtime/include/request_typed_queue.h @@ -45,8 +45,4 @@ struct request_typed_queue { */ struct request_typed_queue * request_typed_queue_init(uint8_t type, uint32_t n_resas); -/* - * flag indicates this function is called by worker thread or listener thread. 1 means listener thread - * 2 means worker thread, this is only for debugging - */ -int push_to_rqueue(uint8_t dispatcher_id, struct sandbox *sandbox, struct request_typed_queue *rtype, uint64_t tsc, int flag); +int push_to_rqueue(struct sandbox *sandbox, struct request_typed_queue *rtype, uint64_t tsc); diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index 3e20910bc..3c88b8a10 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -34,7 +34,6 @@ extern thread_local bool pthread_stop; extern uint32_t runtime_worker_group_size; extern _Atomic uint32_t free_workers[10]; extern thread_local int dispatcher_id; -extern struct request_typed_queue *request_type_queue[MAX_DISPATCHER][MAX_REQUEST_TYPE]; /** * This scheduler provides for cooperative and preemptive multitasking in a OS process's userspace. * diff --git a/runtime/include/tenant_functions.h b/runtime/include/tenant_functions.h index ec46d9d9d..71efbdf08 100644 --- a/runtime/include/tenant_functions.h +++ b/runtime/include/tenant_functions.h @@ -17,9 +17,8 @@ #include "memlogging.h" extern thread_local uint32_t n_rtypes; -//extern thread_local struct request_typed_queue *request_type_queue[10]; +extern thread_local struct request_typed_queue *request_type_queue[MAX_REQUEST_TYPE]; extern thread_local uint8_t dispatcher_thread_idx; -extern struct request_typed_queue *request_type_queue[MAX_DISPATCHER][MAX_REQUEST_TYPE]; extern thread_local struct perf_window perf_window_per_thread[1024]; extern thread_local int global_worker_thread_idx; @@ -192,7 +191,7 @@ tenant_perf_window_init(struct tenant *tenant, void *arg1, void *arg2) { static inline void tenant_request_typed_queue_init(struct tenant *tenant, void *arg1, void *arg2) { for(int i = 0; i < tenant->routes_len; i++) { - request_type_queue[dispatcher_thread_idx][tenant->routes_config[i].request_type - 1] = + request_type_queue[tenant->routes_config[i].request_type - 1] = request_typed_queue_init(tenant->routes_config[i].request_type, tenant->routes_config[i].n_resas); } n_rtypes = tenant->routes_len; diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 9ad27a11a..c9e1fbe41 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -41,7 +41,7 @@ _Atomic uint32_t free_workers[MAX_DISPATCHER] = {0}; // the index is the dispate // will be 111, then the free_workers[dispatcher_id] is 7 -struct request_typed_queue *request_type_queue[MAX_DISPATCHER][MAX_REQUEST_TYPE]; +thread_local struct request_typed_queue *request_type_queue[MAX_REQUEST_TYPE]; thread_local uint32_t n_rtypes = 0; @@ -581,7 +581,7 @@ void darc_shinjuku_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, memcpy(sandbox->rpc_request_body, msg, size); sandbox->rpc_request_body_size = size; - push_to_rqueue(dispatcher_thread_idx, sandbox, request_type_queue[dispatcher_thread_idx][req_type - 1], __getcycles(), 1); + push_to_rqueue(sandbox, request_type_queue[req_type - 1], __getcycles()); } @@ -632,18 +632,12 @@ struct sandbox * shinjuku_peek_selected_sandbox(int *selected_queue_idx) { struct sandbox *selected_sandbox = NULL; for (uint32_t i = 0; i < n_rtypes; ++i) { - if (request_type_queue[dispatcher_thread_idx][i]->rqueue_head > request_type_queue[dispatcher_thread_idx][i]->rqueue_tail) { - //get the tail sandbox of the queue - struct sandbox *sandbox = request_type_queue[dispatcher_thread_idx][i]->rqueue[request_type_queue[dispatcher_thread_idx][i]->rqueue_tail & (RQUEUE_LEN - 1)]; - /* When worker thread call push_to_rqueue(), it first increase head, but push sandbox - to rqueue a little bit, cause here if check success, but sandbox is NULL. In such - case, just continue to wait the sandbox is in the queue - */ - if (sandbox == NULL) { - continue; - } - - uint64_t ts = request_type_queue[dispatcher_thread_idx][i]->tsqueue[request_type_queue[dispatcher_thread_idx][i]->rqueue_tail & (RQUEUE_LEN - 1)]; + if (request_type_queue[i]->rqueue_head > request_type_queue[i]->rqueue_tail) { + //get the tail sandbox of the queue + struct sandbox *sandbox = request_type_queue[i]->rqueue[request_type_queue[i]->rqueue_tail & (RQUEUE_LEN - 1)]; + assert(sandbox != NULL); + + uint64_t ts = request_type_queue[i]->tsqueue[request_type_queue[i]->rqueue_tail & (RQUEUE_LEN - 1)]; uint64_t dt = __getcycles() - ts; float priority = (float)dt / (float)sandbox->route->relative_deadline; if (priority > highest_priority) { @@ -661,8 +655,8 @@ struct sandbox * shinjuku_peek_selected_sandbox(int *selected_queue_idx) { void shinjuku_dequeue_selected_sandbox(int selected_queue_type) { assert(selected_queue_type >= 0 && selected_queue_type < MAX_REQUEST_TYPE); /* set the array slot to NULL because the sandbox is popped out */ - request_type_queue[dispatcher_thread_idx][selected_queue_type]->rqueue[request_type_queue[dispatcher_thread_idx][selected_queue_type]->rqueue_tail & (RQUEUE_LEN - 1)] = NULL; - request_type_queue[dispatcher_thread_idx][selected_queue_type]->rqueue_tail++; + request_type_queue[selected_queue_type]->rqueue[request_type_queue[selected_queue_type]->rqueue_tail & (RQUEUE_LEN - 1)] = NULL; + request_type_queue[selected_queue_type]->rqueue_tail++; } /* Return selected sandbox and pop it out */ @@ -672,18 +666,12 @@ struct sandbox * shinjuku_select_sandbox() { struct sandbox *selected_sandbox = NULL; for (uint32_t i = 0; i < n_rtypes; ++i) { - if (request_type_queue[dispatcher_thread_idx][i]->rqueue_head > request_type_queue[dispatcher_thread_idx][i]->rqueue_tail) { - //get the tail sandbox of the queue - struct sandbox *sandbox = request_type_queue[dispatcher_thread_idx][i]->rqueue[request_type_queue[dispatcher_thread_idx][i]->rqueue_tail & (RQUEUE_LEN - 1)]; - /* When worker thread call push_to_rqueue(), it first increase head, but push sandbox - to rqueue a little bit, cause here if check success, but sandbox is NULL. In such - case, just continue to wait the sandbox is in the queue - */ - if (sandbox == NULL) { - continue; - } - - uint64_t ts = request_type_queue[dispatcher_thread_idx][i]->tsqueue[request_type_queue[dispatcher_thread_idx][i]->rqueue_tail & (RQUEUE_LEN - 1)]; + if (request_type_queue[i]->rqueue_head > request_type_queue[i]->rqueue_tail) { + //get the tail sandbox of the queue + struct sandbox *sandbox = request_type_queue[i]->rqueue[request_type_queue[i]->rqueue_tail & (RQUEUE_LEN - 1)]; + assert(sandbox != NULL); + + uint64_t ts = request_type_queue[i]->tsqueue[request_type_queue[i]->rqueue_tail & (RQUEUE_LEN - 1)]; uint64_t dt = __getcycles() - ts; float priority = (float)dt / (float)sandbox->route->relative_deadline; if (priority > highest_priority) { @@ -696,8 +684,8 @@ struct sandbox * shinjuku_select_sandbox() { if (selected_sandbox != NULL) { /* set the array slot to NULL because the sandbox is popped out */ - request_type_queue[dispatcher_thread_idx][selected_queue_idx]->rqueue[request_type_queue[dispatcher_thread_idx][selected_queue_idx]->rqueue_tail & (RQUEUE_LEN - 1)] = NULL; - request_type_queue[dispatcher_thread_idx][selected_queue_idx]->rqueue_tail++; + request_type_queue[selected_queue_idx]->rqueue[request_type_queue[selected_queue_idx]->rqueue_tail & (RQUEUE_LEN - 1)] = NULL; + request_type_queue[selected_queue_idx]->rqueue_tail++; } return selected_sandbox; @@ -708,8 +696,8 @@ void darc_dispatch() { for (uint32_t i = 0; i < n_rtypes; ++i) { // request_type_queue is a sorted queue, so the loop will dispatch packets from // the earliest deadline to least earliest deadline - if (request_type_queue[dispatcher_thread_idx][i]->rqueue_head > request_type_queue[dispatcher_thread_idx][i]->rqueue_tail) { - drain_queue(request_type_queue[dispatcher_thread_idx][i]); + if (request_type_queue[i]->rqueue_head > request_type_queue[i]->rqueue_tail) { + drain_queue(request_type_queue[i]); } } } @@ -752,7 +740,7 @@ void shinjuku_dispatch() { struct sandbox * preempted_sandbox = pop_worker_preempted_queue(worker_list[i], preempted_queue, &tsc); while(preempted_sandbox != NULL) { uint8_t req_type = preempted_sandbox->route->request_type; - push_to_rqueue(dispatcher_thread_idx, preempted_sandbox, request_type_queue[dispatcher_thread_idx][req_type - 1], tsc, 1); + push_to_rqueue(preempted_sandbox, request_type_queue[req_type - 1], tsc); preempted_sandbox = pop_worker_preempted_queue(worker_list[i], preempted_queue, &tsc); } /* core is idle */ diff --git a/runtime/src/request_typed_queue.c b/runtime/src/request_typed_queue.c index 60a18b9b0..00135cf65 100644 --- a/runtime/src/request_typed_queue.c +++ b/runtime/src/request_typed_queue.c @@ -31,7 +31,7 @@ request_typed_queue_init(uint8_t type, uint32_t n_resas) { } -int push_to_rqueue(uint8_t dispatcher_id, struct sandbox *sandbox, struct request_typed_queue *rtype, uint64_t tsc, int flag) { +int push_to_rqueue(struct sandbox *sandbox, struct request_typed_queue *rtype, uint64_t tsc) { assert(sandbox != NULL); uint32_t head = rtype->rqueue_head; diff --git a/runtime/src/runtime.c b/runtime/src/runtime.c index a9e7bc15b..cf1122274 100644 --- a/runtime/src/runtime.c +++ b/runtime/src/runtime.c @@ -117,16 +117,10 @@ runtime_initialize(void) memset(runtime_worker_threads_deadline, UINT8_MAX, runtime_worker_threads_count * sizeof(uint64_t)); runtime_listener_threads = calloc(runtime_listener_threads_count, sizeof(pthread_t)); - assert(runtime_listener_threads != NULL); + assert(runtime_listener_threads != NULL); runtime_listener_threads_argument = calloc(runtime_listener_threads_count, sizeof(int)); assert(runtime_listener_threads_argument != NULL); - /* Initialize request typed queue */ - for (int i = 0; i < MAX_DISPATCHER; i++) { - for (int j = 0; j < MAX_REQUEST_TYPE; j++) { - request_type_queue[i][j] = NULL; - } - } http_total_init(); sandbox_total_initialize(); request_index_initialize(); From 7c36a5cb1abbad9fa8fc10c10d814ef3bee08aa9 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 5 Oct 2023 14:13:14 -0600 Subject: [PATCH 062/198] replace global typed queue with global typed deque which allows to insert delete in both side --- runtime/include/erpc_handler.h | 3 +- runtime/include/http_router.h | 18 ++- runtime/include/request_typed_deque.h | 26 ++++ runtime/include/tenant_functions.h | 4 + runtime/src/listener_thread.c | 126 ++++++++++++------ runtime/src/request_typed_deque.c | 178 ++++++++++++++++++++++++++ runtime/src/runtime.c | 1 - 7 files changed, 311 insertions(+), 45 deletions(-) create mode 100644 runtime/include/request_typed_deque.h create mode 100644 runtime/src/request_typed_deque.c diff --git a/runtime/include/erpc_handler.h b/runtime/include/erpc_handler.h index c753fd9b9..7442ea10c 100644 --- a/runtime/include/erpc_handler.h +++ b/runtime/include/erpc_handler.h @@ -2,4 +2,5 @@ #include void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); -void darc_shinjuku_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); +void darc_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); +void shinjuku_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); diff --git a/runtime/include/http_router.h b/runtime/include/http_router.h index 332fa7950..cdca6647e 100644 --- a/runtime/include/http_router.h +++ b/runtime/include/http_router.h @@ -47,14 +47,18 @@ http_router_add_route(http_router_t *router, struct route_config *config, struct /* Register RPC request handler */ if (dispatcher == DISPATCHER_EDF_INTERRUPT) { - if (erpc_register_req_func(config->request_type, edf_interrupt_req_handler, 0) != 0) { - panic("register erpc function for EDF_INTERRUPT dispatcher failed\n"); - } - } else if (dispatcher == DISPATCHER_DARC || dispatcher == DISPATCHER_SHINJUKU) { - if (erpc_register_req_func(config->request_type, darc_shinjuku_req_handler, 0) != 0) { - panic("register erpc function for DARC dispatcher failed\n"); + if (erpc_register_req_func(config->request_type, edf_interrupt_req_handler, 0) != 0) { + panic("register erpc function for EDF_INTERRUPT dispatcher failed\n"); + } + } else if (dispatcher == DISPATCHER_DARC) { + if (erpc_register_req_func(config->request_type, darc_req_handler, 0) != 0) { + panic("register erpc function for DARC dispatcher failed\n"); + } + } else if (dispatcher == DISPATCHER_SHINJUKU) { + if (erpc_register_req_func(config->request_type, shinjuku_req_handler, 0) != 0) { + panic("register erpc function for Shinjuku dispatcher failed\n"); + } } - } /* Admissions Control */ uint64_t expected_execution = (uint64_t)config->expected_execution_us * runtime_processor_speed_MHz; diff --git a/runtime/include/request_typed_deque.h b/runtime/include/request_typed_deque.h new file mode 100644 index 000000000..289938b61 --- /dev/null +++ b/runtime/include/request_typed_deque.h @@ -0,0 +1,26 @@ +#pragma once +#include +#include +#include + +#define RDEQUE_LEN 4096 + +struct request_typed_deque { + uint8_t type; + uint64_t deadline; + struct sandbox *rqueue[RDEQUE_LEN]; + int front; + int rear; + int size; + uint64_t tsqueue[RDEQUE_LEN]; +}; + +struct request_typed_deque * request_typed_deque_init(uint8_t type, int size); +bool isFull(struct request_typed_deque * queue); +bool isEmpty(struct request_typed_deque * queue); +void insertfront(struct request_typed_deque * queue, struct sandbox * sandbox, uint64_t ts); +void insertrear(struct request_typed_deque * queue, struct sandbox * sandbox, uint64_t ts); +void deletefront(struct request_typed_deque * queue); +void deleterear(struct request_typed_deque * queue); +struct sandbox * getFront(struct request_typed_deque * queue, uint64_t * ts); +struct sandbox * getRear(struct request_typed_deque * queue, uint64_t * ts); diff --git a/runtime/include/tenant_functions.h b/runtime/include/tenant_functions.h index 71efbdf08..f4e02c19d 100644 --- a/runtime/include/tenant_functions.h +++ b/runtime/include/tenant_functions.h @@ -14,10 +14,12 @@ #include "priority_queue.h" #include "sandbox_functions.h" #include "request_typed_queue.h" +#include "request_typed_deque.h" #include "memlogging.h" extern thread_local uint32_t n_rtypes; extern thread_local struct request_typed_queue *request_type_queue[MAX_REQUEST_TYPE]; +extern thread_local struct request_typed_deque *request_type_deque[MAX_REQUEST_TYPE]; extern thread_local uint8_t dispatcher_thread_idx; extern thread_local struct perf_window perf_window_per_thread[1024]; extern thread_local int global_worker_thread_idx; @@ -193,6 +195,8 @@ tenant_request_typed_queue_init(struct tenant *tenant, void *arg1, void *arg2) { for(int i = 0; i < tenant->routes_len; i++) { request_type_queue[tenant->routes_config[i].request_type - 1] = request_typed_queue_init(tenant->routes_config[i].request_type, tenant->routes_config[i].n_resas); + request_type_deque[tenant->routes_config[i].request_type - 1] = + request_typed_deque_init(tenant->routes_config[i].request_type, 4096); } n_rtypes = tenant->routes_len; } diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index c9e1fbe41..315f278b6 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -16,6 +16,7 @@ #include "http_session_perf_log.h" #include "sandbox_set_as_runnable.h" #include "request_typed_queue.h" +#include "request_typed_deque.h" #include "local_preempted_fifo_queue.h" struct perf_window * worker_perf_windows[1024]; @@ -42,6 +43,7 @@ _Atomic uint32_t free_workers[MAX_DISPATCHER] = {0}; // the index is the dispate thread_local struct request_typed_queue *request_type_queue[MAX_REQUEST_TYPE]; +thread_local struct request_typed_deque *request_type_deque[MAX_REQUEST_TYPE]; thread_local uint32_t n_rtypes = 0; @@ -535,7 +537,7 @@ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, * @param msg the payload of the rpc request. It is the input parameter fot the function * @param size the size of the msg */ -void darc_shinjuku_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { +void darc_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { if (first_request_comming == false){ t_start = time(NULL); first_request_comming = true; @@ -585,6 +587,62 @@ void darc_shinjuku_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, } +/** + * @brief Request routing function + * @param req_handle used by eRPC internal, it is used to send out the response packet + * @param req_type the type of the request. Each function has a unique reqest type id + * @param msg the payload of the rpc request. It is the input parameter fot the function + * @param size the size of the msg + */ +void shinjuku_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { + if (first_request_comming == false){ + t_start = time(NULL); + first_request_comming = true; + } + + uint8_t kMsgSize = 16; + //TODO: rpc_id is hardcode now + + struct tenant *tenant = tenant_database_find_by_port(port); + assert(tenant != NULL); + struct route *route = http_router_match_request_type(&tenant->router, req_type); + if (route == NULL) { + debuglog("Did not match any routes\n"); + dispatcher_send_response(req_handle, DIPATCH_ROUNTE_ERROR, strlen(DIPATCH_ROUNTE_ERROR)); + return; + } + + /* + * Perform admissions control. + * If 0, workload was rejected, so close with 429 "Too Many Requests" and continue + * TODO: Consider providing a Retry-After header + */ + uint64_t work_admitted = admissions_control_decide(route->admissions_info.estimate); + if (work_admitted == 0) { + dispatcher_send_response(req_handle, WORK_ADMITTED_ERROR, strlen(WORK_ADMITTED_ERROR)); + return; + } + + /* Allocate a Sandbox */ + //session->state = HTTP_SESSION_EXECUTING; + struct sandbox *sandbox = sandbox_alloc(route->module, NULL, route, tenant, work_admitted, req_handle, dispatcher_thread_idx); + if (unlikely(sandbox == NULL)) { + debuglog("Failed to allocate sandbox\n"); + dispatcher_send_response(req_handle, SANDBOX_ALLOCATION_ERROR, strlen(SANDBOX_ALLOCATION_ERROR)); + return; + } + + /* copy the received data since it will be released by erpc */ + sandbox->rpc_request_body = malloc(size); + if (!sandbox->rpc_request_body) { + panic("malloc request body failed\n"); + } + + memcpy(sandbox->rpc_request_body, msg, size); + sandbox->rpc_request_body_size = size; + insertrear(request_type_deque[req_type -1], sandbox, __getcycles()); +} + void drain_queue(struct request_typed_queue *rtype) { assert(rtype != NULL); /* queue is not empty and there is free workers */ @@ -632,20 +690,20 @@ struct sandbox * shinjuku_peek_selected_sandbox(int *selected_queue_idx) { struct sandbox *selected_sandbox = NULL; for (uint32_t i = 0; i < n_rtypes; ++i) { - if (request_type_queue[i]->rqueue_head > request_type_queue[i]->rqueue_tail) { - //get the tail sandbox of the queue - struct sandbox *sandbox = request_type_queue[i]->rqueue[request_type_queue[i]->rqueue_tail & (RQUEUE_LEN - 1)]; - assert(sandbox != NULL); - - uint64_t ts = request_type_queue[i]->tsqueue[request_type_queue[i]->rqueue_tail & (RQUEUE_LEN - 1)]; - uint64_t dt = __getcycles() - ts; - float priority = (float)dt / (float)sandbox->route->relative_deadline; - if (priority > highest_priority) { - highest_priority = priority; - *selected_queue_idx = i; - selected_sandbox = sandbox; - } - } + if (isEmpty(request_type_deque[i])) + continue; + uint64_t ts = 0; + /* get the front sandbox of the deque */ + struct sandbox *sandbox = getFront(request_type_deque[i], &ts); + assert(sandbox != NULL); + uint64_t dt = __getcycles() - ts; + float priority = (float)dt / (float)sandbox->route->relative_deadline; + if (priority > highest_priority) { + highest_priority = priority; + *selected_queue_idx = i; + selected_sandbox = sandbox; + } + } return selected_sandbox; @@ -654,9 +712,7 @@ struct sandbox * shinjuku_peek_selected_sandbox(int *selected_queue_idx) { void shinjuku_dequeue_selected_sandbox(int selected_queue_type) { assert(selected_queue_type >= 0 && selected_queue_type < MAX_REQUEST_TYPE); - /* set the array slot to NULL because the sandbox is popped out */ - request_type_queue[selected_queue_type]->rqueue[request_type_queue[selected_queue_type]->rqueue_tail & (RQUEUE_LEN - 1)] = NULL; - request_type_queue[selected_queue_type]->rqueue_tail++; + deletefront(request_type_deque[selected_queue_type]); } /* Return selected sandbox and pop it out */ @@ -666,26 +722,23 @@ struct sandbox * shinjuku_select_sandbox() { struct sandbox *selected_sandbox = NULL; for (uint32_t i = 0; i < n_rtypes; ++i) { - if (request_type_queue[i]->rqueue_head > request_type_queue[i]->rqueue_tail) { - //get the tail sandbox of the queue - struct sandbox *sandbox = request_type_queue[i]->rqueue[request_type_queue[i]->rqueue_tail & (RQUEUE_LEN - 1)]; - assert(sandbox != NULL); - - uint64_t ts = request_type_queue[i]->tsqueue[request_type_queue[i]->rqueue_tail & (RQUEUE_LEN - 1)]; - uint64_t dt = __getcycles() - ts; - float priority = (float)dt / (float)sandbox->route->relative_deadline; - if (priority > highest_priority) { - highest_priority = priority; - selected_queue_idx = i; - selected_sandbox = sandbox; - } - } + if (isEmpty(request_type_deque[i])) + continue; + uint64_t ts = 0; + /* get the front sandbox of the deque */ + struct sandbox *sandbox = getFront(request_type_deque[i], &ts); + assert(sandbox != NULL); + uint64_t dt = __getcycles() - ts; + float priority = (float)dt / (float)sandbox->route->relative_deadline; + if (priority > highest_priority) { + highest_priority = priority; + selected_queue_idx = i; + selected_sandbox = sandbox; + } } if (selected_sandbox != NULL) { - /* set the array slot to NULL because the sandbox is popped out */ - request_type_queue[selected_queue_idx]->rqueue[request_type_queue[selected_queue_idx]->rqueue_tail & (RQUEUE_LEN - 1)] = NULL; - request_type_queue[selected_queue_idx]->rqueue_tail++; + deletefront(request_type_deque[selected_queue_idx]); } return selected_sandbox; @@ -740,7 +793,8 @@ void shinjuku_dispatch() { struct sandbox * preempted_sandbox = pop_worker_preempted_queue(worker_list[i], preempted_queue, &tsc); while(preempted_sandbox != NULL) { uint8_t req_type = preempted_sandbox->route->request_type; - push_to_rqueue(preempted_sandbox, request_type_queue[req_type - 1], tsc); + insertfront(request_type_deque[req_type - 1], preempted_sandbox, tsc); + //insertrear(request_type_deque[req_type - 1], preempted_sandbox, tsc); preempted_sandbox = pop_worker_preempted_queue(worker_list[i], preempted_queue, &tsc); } /* core is idle */ diff --git a/runtime/src/request_typed_deque.c b/runtime/src/request_typed_deque.c new file mode 100644 index 000000000..a270f2bf6 --- /dev/null +++ b/runtime/src/request_typed_deque.c @@ -0,0 +1,178 @@ +#include +#include + +#include "panic.h" +#include "likely.h" +#include "request_typed_deque.h" + +struct request_typed_deque * +request_typed_deque_init(uint8_t type, int size) { + struct request_typed_deque *deque = malloc(sizeof(struct request_typed_deque)); + assert(deque != NULL); + assert(size <= RDEQUE_LEN); + + deque->type = type; + deque->front = -1; + deque->rear = 0; + deque->size = size; + deque->deadline = 0; + + memset(deque->rqueue, 0, RDEQUE_LEN * sizeof(struct sandbox*)); + + return deque; + +} + +// Checks whether request_typed_deque is full or not. +bool isFull(struct request_typed_deque * queue) +{ + assert(queue != NULL); + return ((queue->front == 0 && queue->rear == queue->size - 1) + || queue->front == queue->rear + 1); +} + +// Checks whether request_typed_deque is empty or not. +bool isEmpty(struct request_typed_deque * queue) { + + assert(queue != NULL); + return (queue->front == -1); +} + +// Inserts an element at front +void insertfront(struct request_typed_deque * queue, struct sandbox * sandbox, uint64_t ts) +{ + assert(queue != NULL); + // check whether request_typed_deque if full or not + if (isFull(queue)) { + panic("Request typed deque overflow\n"); + } + + // If queue is initially empty + if (queue->front == -1) { + queue->front = 0; + queue->rear = 0; + } + + // front is at first position of queue + else if (queue->front == 0) + queue->front = queue->size - 1; + + else // decrement front end by '1' + queue->front = queue->front - 1; + + // insert current element into request_typed_deque + queue->rqueue[queue->front] = sandbox; + queue->tsqueue[queue->front] = ts; +} + +// function to inset element at rear end +// of request_typed_deque. +void insertrear(struct request_typed_deque * queue, struct sandbox * sandbox, uint64_t ts) +{ + assert(queue != NULL); + + if (isFull(queue)) { + panic("Request typed deque overflow\n"); + return; + } + + // If queue is initially empty + if (queue->front == -1) { + queue->front = 0; + queue->rear = 0; + } + + // rear is at last position of queue + else if (queue->rear == queue->size - 1) + queue->rear = 0; + + // increment rear end by '1' + else + queue->rear = queue->rear + 1; + + // insert current element into request_typed_deque + queue->rqueue[queue->rear] = sandbox; + queue->tsqueue[queue->rear] = ts; +} + +// Deletes element at front end of request_typed_deque +void deletefront(struct request_typed_deque * queue) +{ + assert(queue != NULL); + + // check whether request_typed_deque is empty or not + if (isEmpty(queue)) { + printf("Queue Underflow\n"); + return; + } + + /* reset the front item to NULL */ + queue->rqueue[queue->front] = NULL; + + // request_typed_deque has only one element + if (queue->front == queue->rear) { + queue->front = -1; + queue->rear = -1; + } else { + // back to initial position + if (queue->front == queue->size - 1) { + queue->front = 0; + } else {// increment front by '1' to remove current + // front value from request_typed_deque + queue->front = queue->front + 1; + } + } +} + + +// Delete element at rear end of request_typed_deque +void deleterear(struct request_typed_deque * queue) +{ + assert(queue != NULL); + if (isEmpty(queue)) { + printf(" Underflow\n"); + return; + } + + /* reset the front item to NULL */ + queue->rqueue[queue->rear] = NULL; + + // request_typed_deque has only one element + if (queue->front == queue->rear) { + queue->front = -1; + queue->rear = -1; + } + else if (queue->rear == 0) + queue->rear = queue->size - 1; + else + queue->rear = queue->rear - 1; +} + +// Returns front element of request_typed_deque +struct sandbox * getFront(struct request_typed_deque * queue, uint64_t * ts) +{ + assert(queue != NULL); + *ts = 0; + // check whether request_typed_deque is empty or not + if (isEmpty(queue)) { + printf(" Underflow\n"); + return NULL; + } + *ts = queue->tsqueue[queue->front]; + return queue->rqueue[queue->front]; +} + +// function return rear element of request_typed_deque +struct sandbox * getRear(struct request_typed_deque * queue, uint64_t * ts) +{ + assert(queue != NULL); + *ts = 0; + // check whether request_typed_deque is empty or not + if (isEmpty(queue) || queue->rear < 0) { + printf(" Underflow\n"); + return NULL; + } + *ts = queue->tsqueue[queue->rear]; + return queue->rqueue[queue->rear]; +} + diff --git a/runtime/src/runtime.c b/runtime/src/runtime.c index cf1122274..c124461cc 100644 --- a/runtime/src/runtime.c +++ b/runtime/src/runtime.c @@ -30,7 +30,6 @@ /* Count of the total number of requests we've ever received. Never decrements as it is used to dispatch requests to workers with RR */ _Atomic uint64_t request_index; -extern struct request_typed_queue *request_type_queue[MAX_DISPATCHER][MAX_REQUEST_TYPE]; pthread_t *runtime_worker_threads; pthread_t *runtime_listener_threads; int *runtime_worker_threads_argument; From 473da70ff732be5387ed923e12a56541330ed86c Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 6 Oct 2023 00:39:06 -0600 Subject: [PATCH 063/198] fix bug: set sandbox->start_ts_running_user after sandbox_return which sets sandbox to running_user state and be preempted imediately because sandbox->start_ts_running_user is 0 --- runtime/src/current_sandbox.c | 13 +++++-- runtime/src/listener_thread.c | 73 +++++++++++++++++++---------------- runtime/src/sandbox.c | 6 +-- 3 files changed, 51 insertions(+), 41 deletions(-) diff --git a/runtime/src/current_sandbox.c b/runtime/src/current_sandbox.c index ac8e48040..e6079e4db 100644 --- a/runtime/src/current_sandbox.c +++ b/runtime/src/current_sandbox.c @@ -135,13 +135,18 @@ current_sandbox_init() sledge_abi__current_wasm_module_instance.wasi_context = sandbox->wasi_context; assert(sandbox->wasi_context != NULL); + /* Set start_ts_running_user for sandbox before it starts running + This setting must be done before sandbox_return() because after sandbox_return(), + state becomes running_user, which can be interrupted, howerver, if start_ts_running_user + wasn't set, then shinjuku will interrupt the sandbox immediately because start_ts_running_user + is 0, and the specified time interval to interrupt the sandbox is less than the big value + */ + sandbox->start_ts_running_user = __getcycles(); sandbox_return(sandbox); - - /* Initialize sandbox globals. Needs to run in user state */ + + /* Initialize sandbox globals. Needs to run in user state */ module_initialize_globals(current_module); - /* set start_ts_running_user for sandbox before it starts running */ - sandbox->start_ts_running_user = __getcycles(); return sandbox; err: diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 315f278b6..34b94e2d2 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -756,32 +756,43 @@ void darc_dispatch() { } void shinjuku_dispatch_different_core() { - for (uint32_t i = 0; i < runtime_worker_group_size; ++i) { - if ((1 << i) & free_workers[dispatcher_thread_idx]) { - struct sandbox *sandbox = shinjuku_select_sandbox(); - if (sandbox == NULL) { - return; // queue empty + for (uint32_t i = 0; i < runtime_worker_group_size; ++i) { + /* move all preempted sandboxes from worker to dispatcher's typed queue */ + struct request_fifo_queue * preempted_queue = worker_preempted_queue[worker_list[i]]; + assert(preempted_queue != NULL); + uint64_t tsc = 0; + struct sandbox * preempted_sandbox = pop_worker_preempted_queue(worker_list[i], preempted_queue, &tsc); + while(preempted_sandbox != NULL) { + uint8_t req_type = preempted_sandbox->route->request_type; + insertfront(request_type_deque[req_type - 1], preempted_sandbox, tsc); + preempted_sandbox = pop_worker_preempted_queue(worker_list[i], preempted_queue, &tsc); + } + + /* core is idle */ + if ((1 << i) & free_workers[dispatcher_thread_idx]) { + struct sandbox *sandbox = shinjuku_select_sandbox(); + if (!sandbox) return; // queue is empty + + local_runqueue_add_index(worker_list[i], sandbox); + atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << i); + } else { // core is busy + //check if the current sandbox is running longer than the specified time duration + struct sandbox *current = current_sandboxes[worker_list[i]]; + if (!current) continue; //In case that worker thread hasn't call current_sandbox_set to set the current sandbox + uint64_t duration = (__getcycles() - current->start_ts_running_user) / runtime_processor_speed_MHz; + if (duration >= 400 && (current->state == SANDBOX_RUNNING_USER || current->state == SANDBOX_RUNNING_SYS)) { + struct sandbox *sandbox = shinjuku_select_sandbox(); + if (!sandbox) return; // queue is empty + + //preempt the current sandbox and put it back the typed queue, select a new one to send to it + local_runqueue_add_index(worker_list[i], sandbox); + //preempt worker + preempt_worker(worker_list[i]); } + } + + } - local_runqueue_add_index(worker_list[i], sandbox); - atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << i); - } else { // core is busy - //check if the current sandbox is running longer than the specified time duration - struct sandbox *current = current_sandboxes[worker_list[i]]; - if (!current) continue; // In case that worker thread hasn't call current_sandbox_set to set the current sandbox - uint64_t duration = (__getcycles() - current->timestamp_of.last_state_change) / runtime_processor_speed_MHz; - if (duration >= 10 && current->state == SANDBOX_RUNNING_USER) { - //preempt the current sandbox and put it back the typed queue, select a new one to send to it - struct sandbox *sandbox = shinjuku_select_sandbox(); - if (sandbox == NULL) { - return; // queue empty - } - local_runqueue_add_index(worker_list[i], sandbox); - //preempt worker - preempt_worker(worker_list[i]); - } - } - } } void shinjuku_dispatch() { @@ -799,33 +810,28 @@ void shinjuku_dispatch() { } /* core is idle */ if ((1 << i) & free_workers[dispatcher_thread_idx]) { - int selected_queue_type = -1; - struct sandbox *sandbox = shinjuku_peek_selected_sandbox(&selected_queue_type); + struct sandbox *sandbox = shinjuku_select_sandbox(); if (!sandbox) return; // queue is empty while (sandbox->global_worker_thread_idx != -1) { local_runqueue_add_index(sandbox->global_worker_thread_idx, sandbox); - shinjuku_dequeue_selected_sandbox(selected_queue_type); - sandbox = shinjuku_peek_selected_sandbox(&selected_queue_type); + sandbox = shinjuku_select_sandbox(); if (!sandbox) return; } local_runqueue_add_index(worker_list[i], sandbox); atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << i); - shinjuku_dequeue_selected_sandbox(selected_queue_type); } else { // core is busy //check if the current sandbox is running longer than the specified time duration struct sandbox *current = current_sandboxes[worker_list[i]]; if (!current) continue; //In case that worker thread hasn't call current_sandbox_set to set the current sandbox uint64_t duration = (__getcycles() - current->start_ts_running_user) / runtime_processor_speed_MHz; if (duration >= 50 && (current->state == SANDBOX_RUNNING_USER || current->state == SANDBOX_RUNNING_SYS)) { - int selected_queue_type = -1; - struct sandbox *sandbox = shinjuku_peek_selected_sandbox(&selected_queue_type); + struct sandbox *sandbox = shinjuku_select_sandbox(); if (!sandbox) return; // queue is empty while (sandbox->global_worker_thread_idx != -1) { local_runqueue_add_index(sandbox->global_worker_thread_idx, sandbox); - shinjuku_dequeue_selected_sandbox(selected_queue_type); - sandbox = shinjuku_peek_selected_sandbox(&selected_queue_type); + sandbox = shinjuku_select_sandbox(); if (!sandbox) return; } @@ -833,7 +839,6 @@ void shinjuku_dispatch() { local_runqueue_add_index(worker_list[i], sandbox); //preempt worker preempt_worker(worker_list[i]); - shinjuku_dequeue_selected_sandbox(selected_queue_type); } } diff --git a/runtime/src/sandbox.c b/runtime/src/sandbox.c index 25dd675c3..176421bf8 100644 --- a/runtime/src/sandbox.c +++ b/runtime/src/sandbox.c @@ -107,11 +107,11 @@ sandbox_init_response_body(struct sandbox *sandbox) */ int sandbox_prepare_execution_environment(struct sandbox *sandbox) -{ +{ assert(sandbox != NULL); - sandbox->global_worker_thread_idx = global_worker_thread_idx; - sandbox->group_worker_thread_idx = group_worker_thread_idx; + sandbox->global_worker_thread_idx = global_worker_thread_idx; + sandbox->group_worker_thread_idx = group_worker_thread_idx; char *error_message = ""; From 7434fd923ce42b340a12734cf3f6bd903571def1 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 6 Oct 2023 12:12:26 -0600 Subject: [PATCH 064/198] replace binary-search-tree local runqueue with circular-queue for shinjuku, no lock --- runtime/include/local_runqueue.h | 3 +++ runtime/include/scheduler.h | 13 +++++++++---- runtime/src/listener_thread.c | 3 ++- runtime/src/local_runqueue.c | 7 +++++++ runtime/src/local_runqueue_binary_tree.c | 2 -- runtime/src/main.c | 6 +++--- runtime/src/worker_thread.c | 8 ++++---- 7 files changed, 28 insertions(+), 14 deletions(-) diff --git a/runtime/include/local_runqueue.h b/runtime/include/local_runqueue.h index 9456480de..fc035a8cf 100644 --- a/runtime/include/local_runqueue.h +++ b/runtime/include/local_runqueue.h @@ -12,6 +12,7 @@ typedef bool (*local_runqueue_is_empty_fn_t)(void); typedef void (*local_runqueue_delete_fn_t)(struct sandbox *sandbox); typedef struct sandbox *(*local_runqueue_get_next_fn_t)(); typedef int (*local_runqueue_get_height_fn_t)(); +typedef int (*local_runqueue_get_length_fn_t)(); struct local_runqueue_config { local_runqueue_add_fn_t add_fn; @@ -21,6 +22,7 @@ struct local_runqueue_config { local_runqueue_delete_fn_t delete_fn; local_runqueue_get_next_fn_t get_next_fn; local_runqueue_get_height_fn_t get_height_fn; + local_runqueue_get_length_fn_t get_length_fn; }; void local_runqueue_add(struct sandbox *); @@ -31,3 +33,4 @@ bool local_runqueue_is_empty(); struct sandbox *local_runqueue_get_next(); void local_runqueue_initialize(struct local_runqueue_config *config); int local_runqueue_get_height(); +int local_runqueue_get_length(); diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index 3c88b8a10..205caf1cc 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -12,6 +12,7 @@ #include "local_runqueue.h" #include "local_runqueue_minheap.h" #include "local_runqueue_binary_tree.h" +#include "local_runqueue_circular_queue.h" #include "local_runqueue_list.h" #include "local_cleanup_queue.h" #include "local_runqueue_mtds.h" @@ -131,7 +132,7 @@ scheduler_edf_get_next() local->timestamp_of.last_state_change = now; /* end by xiaosu */ sandbox_prepare_execution_environment(local); - //printf("sandbox state %d\n", local->state); + //printf("sandbox state %d\n", local->state); assert(local->state == SANDBOX_INITIALIZED); sandbox_set_as_runnable(local, SANDBOX_INITIALIZED); } @@ -212,8 +213,12 @@ scheduler_runqueue_initialize() local_runqueue_mtds_initialize(); break; case SCHEDULER_EDF: - //local_runqueue_minheap_initialize(); - local_runqueue_binary_tree_initialize(); + if (dispatcher == DISPATCHER_SHINJUKU) { + local_runqueue_circular_queue_initialize(); + } else { + //local_runqueue_minheap_initialize(); + local_runqueue_binary_tree_initialize(); + } break; case SCHEDULER_FIFO: local_runqueue_list_initialize(); @@ -331,7 +336,7 @@ scheduler_preemptive_sched(ucontext_t *interrupted_context) /* Delete current sandbox from local queue if dispatcher is DISPATCHER_SHINJUKU */ if (dispatcher == DISPATCHER_SHINJUKU) { uint64_t duration = (__getcycles() - interrupted_sandbox->start_ts_running_user) / runtime_processor_speed_MHz; - if (duration >= 50 && local_runqueue_get_height() >= 1) { + if (duration >= 50 && local_runqueue_get_length() > 1) { local_runqueue_delete(interrupted_sandbox); sandbox_preempt(interrupted_sandbox); // Write back global at idx 0 diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 34b94e2d2..247cf32b8 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -22,6 +22,7 @@ struct perf_window * worker_perf_windows[1024]; struct priority_queue * worker_queues[1024]; struct binary_tree * worker_binary_trees[1024]; +struct request_fifo_queue * worker_circular_queue[1024]; struct ps_list_head * worker_lists[1024]; struct request_fifo_queue * worker_preempted_queue[1024]; @@ -780,7 +781,7 @@ void shinjuku_dispatch_different_core() { struct sandbox *current = current_sandboxes[worker_list[i]]; if (!current) continue; //In case that worker thread hasn't call current_sandbox_set to set the current sandbox uint64_t duration = (__getcycles() - current->start_ts_running_user) / runtime_processor_speed_MHz; - if (duration >= 400 && (current->state == SANDBOX_RUNNING_USER || current->state == SANDBOX_RUNNING_SYS)) { + if (duration >= 50 && (current->state == SANDBOX_RUNNING_USER || current->state == SANDBOX_RUNNING_SYS)) { struct sandbox *sandbox = shinjuku_select_sandbox(); if (!sandbox) return; // queue is empty diff --git a/runtime/src/local_runqueue.c b/runtime/src/local_runqueue.c index ff283c5ff..a8ab8f524 100644 --- a/runtime/src/local_runqueue.c +++ b/runtime/src/local_runqueue.c @@ -83,6 +83,13 @@ local_runqueue_is_empty() int local_runqueue_get_height() { return local_runqueue.get_height_fn(); } + +/** + * Get total count of items in the queue + */ +int local_runqueue_get_length() { + return local_runqueue.get_length_fn(); +} /** * Get next sandbox from run queue, where next is defined by * @returns sandbox (or NULL?) diff --git a/runtime/src/local_runqueue_binary_tree.c b/runtime/src/local_runqueue_binary_tree.c index 67ef39a6a..2dd62a964 100644 --- a/runtime/src/local_runqueue_binary_tree.c +++ b/runtime/src/local_runqueue_binary_tree.c @@ -14,8 +14,6 @@ #include "runtime.h" extern thread_local int global_worker_thread_idx; -extern struct perf_window * worker_perf_windows[1024]; /* index is thread id, each queue's perf windows, each queue can - have multiple perf windows */ extern struct sandbox* current_sandboxes[1024]; extern struct binary_tree *worker_binary_trees[1024]; thread_local static struct binary_tree *local_runqueue_binary_tree = NULL; diff --git a/runtime/src/main.c b/runtime/src/main.c index 52f143b8a..c1f92b71d 100644 --- a/runtime/src/main.c +++ b/runtime/src/main.c @@ -262,10 +262,10 @@ runtime_configure() } else if (strcmp(dispatcher_policy, "EDF_INTERRUPT") == 0) { dispatcher = DISPATCHER_EDF_INTERRUPT; } else if (strcmp(dispatcher_policy, "SHINJUKU") == 0) { - dispatcher = DISPATCHER_SHINJUKU; - } else { + dispatcher = DISPATCHER_SHINJUKU; + } else { panic("Invalid dispatcher policy: %s. Must be {EDF_INTERRUPT|DARC|SHINJUKU\n", dispatcher_policy); - } + } pretty_print_key_value("Dispatcher Policy", "%s\n", dispatcher_print(dispatcher)); /* Sigalrm Handler Technique */ diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c index 6950584e4..3c1cfddcc 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c @@ -73,12 +73,12 @@ worker_thread_main(void *argument) /* Index was passed via argument */ global_worker_thread_idx = *(int *)argument; - /* Set dispatcher id for this worker */ - dispatcher_id = global_worker_thread_idx / runtime_worker_group_size; + /* Set dispatcher id for this worker */ + dispatcher_id = global_worker_thread_idx / runtime_worker_group_size; - group_worker_thread_idx = global_worker_thread_idx - dispatcher_id * runtime_worker_group_size; + group_worker_thread_idx = global_worker_thread_idx - dispatcher_id * runtime_worker_group_size; - printf("global thread %d's dispatcher id is %d group size is %d group id is %d\n", global_worker_thread_idx, + printf("global thread %d's dispatcher id is %d group size is %d group id is %d\n", global_worker_thread_idx, dispatcher_id, runtime_worker_group_size, group_worker_thread_idx); /* Set my priority */ // runtime_set_pthread_prio(pthread_self(), 2); From 5a182bbda743e78d30df264d3dce85820307f649 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 6 Oct 2023 12:39:43 -0600 Subject: [PATCH 065/198] replace binary-search-tree local runqueue with circular-queue for DARC, no lock --- runtime/include/scheduler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index 205caf1cc..ad32dd346 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -213,7 +213,7 @@ scheduler_runqueue_initialize() local_runqueue_mtds_initialize(); break; case SCHEDULER_EDF: - if (dispatcher == DISPATCHER_SHINJUKU) { + if (dispatcher == DISPATCHER_SHINJUKU || dispatcher == DISPATCHER_DARC) { local_runqueue_circular_queue_initialize(); } else { //local_runqueue_minheap_initialize(); From f1cb62a038c11ba8bbc8a096eadab31b354409fc Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Sat, 7 Oct 2023 01:34:10 -0600 Subject: [PATCH 066/198] optimize edf-selected-interrupt algo: Before context switch to other sandbox, check if its remaining slack is equal or less than 0, if it is, do not interrupt it --- runtime/include/http_router.h | 1 + runtime/include/route.h | 3 +- runtime/include/route_config.h | 1 + runtime/include/route_config_parse.h | 2 + runtime/include/sandbox_set_as_preempted.h | 2 + runtime/include/sandbox_set_as_running_user.h | 2 + runtime/include/sandbox_types.h | 3 + runtime/include/scheduler.h | 6 +- runtime/src/admissions_info.c | 2 +- runtime/src/current_sandbox.c | 2 + runtime/src/listener_thread.c | 89 ++++++++++--------- runtime/src/local_runqueue_binary_tree.c | 34 ++++++- runtime/src/sandbox.c | 4 +- runtime/src/software_interrupt.c | 2 + 14 files changed, 100 insertions(+), 53 deletions(-) diff --git a/runtime/include/http_router.h b/runtime/include/http_router.h index cdca6647e..8bbe7cba2 100644 --- a/runtime/include/http_router.h +++ b/runtime/include/http_router.h @@ -39,6 +39,7 @@ http_router_add_route(http_router_t *router, struct route_config *config, struct .relative_deadline_us = config->relative_deadline_us, .relative_deadline = (uint64_t)config->relative_deadline_us * runtime_processor_speed_MHz, + .expected_execution_cycle = config->expected_execution_cycle, .response_content_type = config->http_resp_content_type }; route_latency_init(&route.latency); diff --git a/runtime/include/route.h b/runtime/include/route.h index 374a230ee..3fffc087f 100644 --- a/runtime/include/route.h +++ b/runtime/include/route.h @@ -11,12 +11,13 @@ /* Assumption: entrypoint is always _start. This should be enhanced later */ struct route { char *route; - uint8_t request_type; + uint8_t request_type; struct http_route_total metrics; struct module *module; /* HTTP State */ uint32_t relative_deadline_us; uint64_t relative_deadline; /* cycles */ + uint64_t expected_execution_cycle; /* in cycles */ char *response_content_type; struct admissions_info admissions_info; struct perf_window latency; diff --git a/runtime/include/route_config.h b/runtime/include/route_config.h index 43bf0926a..337389f63 100644 --- a/runtime/include/route_config.h +++ b/runtime/include/route_config.h @@ -28,6 +28,7 @@ struct route_config { char *path; uint8_t admissions_percentile; uint32_t expected_execution_us; + uint64_t expected_execution_cycle; /* exepected exectuion in cycle */ uint32_t relative_deadline_us; char *http_resp_content_type; }; diff --git a/runtime/include/route_config_parse.h b/runtime/include/route_config_parse.h index 11f0a2c10..522f3dbc3 100644 --- a/runtime/include/route_config_parse.h +++ b/runtime/include/route_config_parse.h @@ -99,6 +99,8 @@ route_config_parse(struct route_config *config, const char *json_buf, jsmntok_t route_config_json_keys[route_config_member_expected_execution_us], &config->expected_execution_us); if (rc < 0) return -1; + config->expected_execution_cycle = (uint64_t)config->expected_execution_us * runtime_processor_speed_MHz; + assert(config->expected_execution_cycle != 0); } else if (strcmp(key, route_config_json_keys[route_config_member_relative_deadline_us]) == 0) { if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1; if (route_config_set_key_once(did_set, route_config_member_relative_deadline_us) == -1) diff --git a/runtime/include/sandbox_set_as_preempted.h b/runtime/include/sandbox_set_as_preempted.h index 3d30c93f1..d0025fbc1 100644 --- a/runtime/include/sandbox_set_as_preempted.h +++ b/runtime/include/sandbox_set_as_preempted.h @@ -48,6 +48,8 @@ sandbox_set_as_preempted(struct sandbox *sandbox, sandbox_state_t last_state) /* State Change Hooks */ sandbox_state_transition_from_hook(sandbox, last_state); sandbox_state_transition_to_hook(sandbox, SANDBOX_PREEMPTED); + /* Update TS when sandbox was preempted */ + sandbox->srsf_stop_running_ts = now; } static inline void diff --git a/runtime/include/sandbox_set_as_running_user.h b/runtime/include/sandbox_set_as_running_user.h index b81680718..1c730e2ae 100644 --- a/runtime/include/sandbox_set_as_running_user.h +++ b/runtime/include/sandbox_set_as_running_user.h @@ -26,6 +26,8 @@ sandbox_set_as_running_user(struct sandbox *sandbox, sandbox_state_t last_state) } case SANDBOX_PREEMPTED: { sandbox->start_ts_running_user = now; + /* Sandbox resumes, update its RS */ + sandbox->srsf_remaining_slack = sandbox->srsf_remaining_slack - (__getcycles() - sandbox->srsf_stop_running_ts); break; } default: { diff --git a/runtime/include/sandbox_types.h b/runtime/include/sandbox_types.h index 848463aab..e2df70892 100644 --- a/runtime/include/sandbox_types.h +++ b/runtime/include/sandbox_types.h @@ -87,5 +87,8 @@ struct sandbox { pause and restore the sandbox must be done in the same thread */ int group_worker_thread_idx; /* what's the thread index in the group */ uint64_t start_ts_running_user; /* the start timestamp to run user, it will be updated when resume to run user */ + /* For SRSF */ + uint64_t srsf_stop_running_ts; /* record the timestamp of stopping running of this sandbox, in cycles */ + int64_t srsf_remaining_slack; } PAGE_ALIGNED; diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index ad32dd346..c43b4f98b 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -269,6 +269,7 @@ scheduler_preemptive_switch_to(ucontext_t *interrupted_context, struct sandbox * { /* Switch to next sandbox */ switch (next->ctxt.variant) { + /* This sandbox is a new sandbox */ case ARCH_CONTEXT_VARIANT_FAST: { assert(next->state == SANDBOX_RUNNABLE); arch_context_restore_fast(&interrupted_context->uc_mcontext, &next->ctxt); @@ -276,6 +277,7 @@ scheduler_preemptive_switch_to(ucontext_t *interrupted_context, struct sandbox * sandbox_set_as_running_sys(next, SANDBOX_RUNNABLE); break; } + /* This sandbox is a preempted sandbox */ case ARCH_CONTEXT_VARIANT_SLOW: { assert(next->state == SANDBOX_PREEMPTED); arch_context_restore_slow(&interrupted_context->uc_mcontext, &next->ctxt); @@ -366,8 +368,8 @@ scheduler_preemptive_sched(ucontext_t *interrupted_context) /* Assumption: the current sandbox is on the runqueue, so the scheduler should always return something */ assert(next != NULL); - /* If current equals next, no switch is necessary, so resume execution */ - if (interrupted_sandbox == next) { + /* If current equals next, no switch is necessary, or its RS <= 0, just resume execution */ + if (interrupted_sandbox == next || interrupted_sandbox->srsf_remaining_slack <= 0) { sandbox_interrupt_return(interrupted_sandbox, SANDBOX_RUNNING_USER); return; } diff --git a/runtime/src/admissions_info.c b/runtime/src/admissions_info.c index 76f3be164..77c3417aa 100644 --- a/runtime/src/admissions_info.c +++ b/runtime/src/admissions_info.c @@ -29,8 +29,8 @@ admissions_info_initialize(struct admissions_info *admissions_info, uint8_t perc #ifdef LOG_ADMISSIONS_CONTROL debuglog("Percentile: %u\n", admissions_info->percentile); debuglog("Control Index: %d\n", admissions_info->control_index); -//#endif #endif +//#endif } void perf_window_per_thread_update(struct admissions_info *admissions_info, uint64_t execution_duration) { diff --git a/runtime/src/current_sandbox.c b/runtime/src/current_sandbox.c index e6079e4db..07c02de65 100644 --- a/runtime/src/current_sandbox.c +++ b/runtime/src/current_sandbox.c @@ -195,6 +195,8 @@ current_sandbox_start(void) int rc = sigsetjmp(sandbox->ctxt.start_buf, 1); if (rc == 0) { struct module *current_module = sandbox_get_module(sandbox); + /* Sandbox starts running, update its RS */ + sandbox->srsf_remaining_slack = sandbox->srsf_remaining_slack - (__getcycles() - sandbox->srsf_stop_running_ts); sandbox->return_value = module_entrypoint(current_module); } else { current_sandbox_wasm_trap_handler(rc); diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 247cf32b8..2cc36e4db 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -448,15 +448,15 @@ on_client_socket_epoll_event(struct epoll_event *evt) */ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { - if (first_request_comming == false){ + if (first_request_comming == false){ t_start = time(NULL); first_request_comming = true; } - uint8_t kMsgSize = 16; + uint8_t kMsgSize = 16; - struct tenant *tenant = tenant_database_find_by_port(port); - assert(tenant != NULL); + struct tenant *tenant = tenant_database_find_by_port(port); + assert(tenant != NULL); struct route *route = http_router_match_request_type(&tenant->router, req_type); if (route == NULL) { debuglog("Did not match any routes\n"); @@ -484,51 +484,52 @@ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, return; } - /* copy the received data since it will be released by erpc */ - sandbox->rpc_request_body = malloc(size); - if (!sandbox->rpc_request_body) { - panic("malloc request body failed\n"); - } + /* copy the received data since it will be released by erpc */ + sandbox->rpc_request_body = malloc(size); + if (!sandbox->rpc_request_body) { + panic("malloc request body failed\n"); + } - memcpy(sandbox->rpc_request_body, msg, size); - sandbox->rpc_request_body_size = size; + memcpy(sandbox->rpc_request_body, msg, size); + sandbox->rpc_request_body_size = size; - uint64_t min_waiting_serving_time = UINT64_MAX; - int thread_id = 0; - int candidate_thread_with_interrupt = -1; + uint64_t min_waiting_serving_time = UINT64_MAX; + int thread_id = 0; /* This thread can server the request by waiting for a while */ + int candidate_thread_with_interrupt = -1; /* This thread can server the request immediately by interrupting + the current one */ - for (uint32_t i = worker_start_id; i < worker_end_id; i++) { - bool need_interrupt; - uint64_t waiting_serving_time = local_runqueue_try_add_index(i, sandbox, &need_interrupt); - /* The local queue is empty, the worker is idle, can be served this request immediately - * without interrupting - */ - if (waiting_serving_time == 0 && need_interrupt == false) { - local_runqueue_add_index(i, sandbox); - return; - } else if (waiting_serving_time == 0 && need_interrupt == true) {//The worker can serve the request immediately + for (uint32_t i = worker_start_id; i < worker_end_id; i++) { + bool need_interrupt; + uint64_t waiting_serving_time = local_runqueue_try_add_index(i, sandbox, &need_interrupt); + /* The local queue is empty, the worker is idle, can be served this request immediately + * without interrupting + */ + if (waiting_serving_time == 0 && need_interrupt == false) { + local_runqueue_add_index(i, sandbox); + return; + } else if (waiting_serving_time == 0 && need_interrupt == true) {//The worker can serve the request immediately // by interrupting the current one - /* We already have a candidate thread, continue to find a - * better thread without needing interrupt - */ - if (candidate_thread_with_interrupt != -1) { - continue; - } else { - candidate_thread_with_interrupt = i; - } - } else if (min_waiting_serving_time > waiting_serving_time) { - min_waiting_serving_time = waiting_serving_time; - thread_id = i; - } - } + /* We already have a candidate thread, continue to find a + * better thread without needing interrupt + */ + if (candidate_thread_with_interrupt != -1) { + continue; + } else { + candidate_thread_with_interrupt = i; + } + } else if (min_waiting_serving_time > waiting_serving_time) { + min_waiting_serving_time = waiting_serving_time; + thread_id = i; + } + } - if (candidate_thread_with_interrupt != -1) { - //urgent_request[candidate_thread_with_interrupt] = sandbox; - local_runqueue_add_index(candidate_thread_with_interrupt, sandbox); - preempt_worker(candidate_thread_with_interrupt); - } else { - local_runqueue_add_index(thread_id, sandbox); - } + if (candidate_thread_with_interrupt != -1) { + //urgent_request[candidate_thread_with_interrupt] = sandbox; + local_runqueue_add_index(candidate_thread_with_interrupt, sandbox); + preempt_worker(candidate_thread_with_interrupt); + } else { + local_runqueue_add_index(thread_id, sandbox); + } } /** diff --git a/runtime/src/local_runqueue_binary_tree.c b/runtime/src/local_runqueue_binary_tree.c index 2dd62a964..888edd978 100644 --- a/runtime/src/local_runqueue_binary_tree.c +++ b/runtime/src/local_runqueue_binary_tree.c @@ -57,6 +57,27 @@ local_runqueue_binary_tree_add_index(int index, struct sandbox *sandbox) lock_lock(&binary_tree->lock, &node_lock); binary_tree->root = insert(binary_tree, binary_tree->root, sandbox); lock_unlock(&binary_tree->lock, &node_lock); + + /* Set estimated exeuction time for the sandbox */ + uint32_t uid = sandbox->route->admissions_info.uid; + uint64_t estimated_execute_cost = perf_window_get_percentile(&worker_perf_windows[index][uid], + sandbox->route->admissions_info.percentile, + sandbox->route->admissions_info.control_index); + /* Use expected execution time in the configuration file as the esitmated execution time + if estimated_execute_cost is 0 + */ + if (estimated_execute_cost == 0) { + estimated_execute_cost = sandbox->route->expected_execution_cycle; + } + sandbox->estimated_cost = estimated_execute_cost; + /* Record TS and calcuate RS. SRSF algo: + 1. When reqeust arrives to the queue, record TS and calcuate RS. RS = deadline - execution time + 2. When request starts running, update RS + 3. When request stops, update TS + 4. When request resumes, update RS + */ + sandbox->srsf_stop_running_ts = __getcycles(); + sandbox->srsf_remaining_slack = sandbox->route->relative_deadline - sandbox->estimated_cost; } /** @@ -111,17 +132,24 @@ local_runqueue_binary_tree_try_add_index(int index, struct sandbox *sandbox, boo { struct binary_tree *binary_tree = worker_binary_trees[index]; if (is_empty(binary_tree)) { + /* The worker is idle */ *need_interrupt = false; return 0; - } else if (current_sandboxes[index] != NULL && sandbox_is_preemptable(current_sandboxes[index]) == true && - sandbox_get_priority(sandbox) < sandbox_get_priority(current_sandboxes[index])) { + } else if (current_sandboxes[index] != NULL && + current_sandboxes[index]->srsf_remaining_slack > 0 && + sandbox_is_preemptable(current_sandboxes[index]) == true && + sandbox_get_priority(sandbox) < sandbox_get_priority(current_sandboxes[index])) { + /* The new one has a higher priority than the current one, need to interrupt the current one */ *need_interrupt = true; return 0; } else { + /* Current sandbox cannot be interrupted because its priority is higher or its RS is 0, just find + a right location to add the new sandbox to the tree + */ need_interrupt = false; uint64_t waiting_serving_time = 0; lock_node_t node_lock = {}; - lock_lock(&binary_tree->lock, &node_lock); + lock_lock(&binary_tree->lock, &node_lock); struct TreeNode* node = findMaxValueLessThan(binary_tree, binary_tree->root, sandbox, &waiting_serving_time, index); lock_unlock(&binary_tree->lock, &node_lock); return waiting_serving_time; diff --git a/runtime/src/sandbox.c b/runtime/src/sandbox.c index 176421bf8..5f1dbf993 100644 --- a/runtime/src/sandbox.c +++ b/runtime/src/sandbox.c @@ -181,8 +181,8 @@ sandbox_init(struct sandbox *sandbox, struct module *module, struct http_session sandbox->cursor = 0; sandbox->absolute_deadline = sandbox->timestamp_of.allocation + sandbox->route->relative_deadline; - sandbox->global_worker_thread_idx = -1; - sandbox->group_worker_thread_idx = -1; + sandbox->global_worker_thread_idx = -1; + sandbox->group_worker_thread_idx = -1; /* * Admissions Control State diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index 0a1db8901..6e52080fb 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -177,6 +177,8 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void } } else if (current_sandbox_is_preemptable()) { /* Preemptable, so run scheduler. The scheduler handles outgoing state changes */ + /* sandbox_interrupt means the sandbox stopped, but might be resume very soon. If + deciding preempt the sandbox for a while, then will call sandbox_preempt */ sandbox_interrupt(current_sandbox); if (scheduler == SCHEDULER_MTDS && signal_info->si_code == SI_KERNEL) { /* Global tenant promotions */ From 13c2a942b2d1e96efeed5544c2ab6a1a85f35ebb Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Sat, 7 Oct 2023 01:34:51 -0600 Subject: [PATCH 067/198] forgot submit local_runqueue_circular_queue.h and local_runqueue_circular_queue.c --- .../include/local_runqueue_circular_queue.h | 4 + runtime/src/local_runqueue_circular_queue.c | 118 ++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 runtime/include/local_runqueue_circular_queue.h create mode 100644 runtime/src/local_runqueue_circular_queue.c diff --git a/runtime/include/local_runqueue_circular_queue.h b/runtime/include/local_runqueue_circular_queue.h new file mode 100644 index 000000000..15a27f3dc --- /dev/null +++ b/runtime/include/local_runqueue_circular_queue.h @@ -0,0 +1,4 @@ +#pragma once + +void local_runqueue_circular_queue_initialize(); + diff --git a/runtime/src/local_runqueue_circular_queue.c b/runtime/src/local_runqueue_circular_queue.c new file mode 100644 index 000000000..b2a94dc38 --- /dev/null +++ b/runtime/src/local_runqueue_circular_queue.c @@ -0,0 +1,118 @@ +#include +#include +#include +#include + +#include "local_runqueue.h" +#include "panic.h" +#include "likely.h" +#include "request_fifo_queue.h" + +extern thread_local int global_worker_thread_idx; +extern struct request_fifo_queue * worker_circular_queue[1024]; +thread_local static struct request_fifo_queue * local_runqueue_circular_queue = NULL; + +/* Add item to the head of the queue */ +void +local_runqueue_circular_queue_add(struct sandbox *sandbox) { + assert(sandbox != NULL); + assert(local_runqueue_circular_queue != NULL); + + uint32_t head = local_runqueue_circular_queue->rqueue_head; + + if (unlikely(head - local_runqueue_circular_queue->rqueue_tail == RQUEUE_QUEUE_LEN)) { + panic("local circular runqueue is full\n"); + } else { + local_runqueue_circular_queue->rqueue[head & (RQUEUE_QUEUE_LEN - 1)] = sandbox; + local_runqueue_circular_queue->rqueue_head++; + } + +} + +/* Called by diaptcher thread to add a new sandbox to the local runqueue */ +void +local_runqueue_circular_queue_add_index(int index, struct sandbox *sandbox){ + assert(sandbox != NULL); + + struct request_fifo_queue * local_runqueue = worker_circular_queue[index]; + assert(local_runqueue != NULL); + uint32_t head = local_runqueue->rqueue_head; + + if (unlikely(head - local_runqueue->rqueue_tail == RQUEUE_QUEUE_LEN)) { + panic("local circular runqueue is full\n"); + } else { + local_runqueue->rqueue[head & (RQUEUE_QUEUE_LEN - 1)] = sandbox; + local_runqueue->rqueue_head++; + } +} + +bool +local_runqueue_circular_queue_is_empty() { + assert(local_runqueue_circular_queue != NULL); + return (local_runqueue_circular_queue->rqueue_head == local_runqueue_circular_queue->rqueue_tail); +} + +/* Called by worker thread to delete item from the tail of the queue, the to be deleted sandbox must be in the tail */ +void +local_runqueue_circular_queue_delete(struct sandbox *sandbox) { + assert(sandbox != 0); + assert(local_runqueue_circular_queue != NULL); + assert(local_runqueue_circular_queue->rqueue[local_runqueue_circular_queue->rqueue_tail & (RQUEUE_QUEUE_LEN - 1)] + == sandbox); + + local_runqueue_circular_queue->rqueue[local_runqueue_circular_queue->rqueue_tail & (RQUEUE_QUEUE_LEN - 1)] + = NULL; + + local_runqueue_circular_queue->rqueue_tail++; +} + +/* Called by worker thread to get item from the tail of the queue */ +struct sandbox * local_runqueue_circular_queue_get_next() { + assert(local_runqueue_circular_queue != NULL); + if (local_runqueue_circular_queue->rqueue_head > local_runqueue_circular_queue->rqueue_tail) { + struct sandbox *sandbox = + local_runqueue_circular_queue->rqueue[local_runqueue_circular_queue->rqueue_tail & (RQUEUE_QUEUE_LEN - 1)]; + assert(sandbox != NULL); + return sandbox; + } else { + return NULL; + } +} + +int +local_runqueue_circular_queue_get_length() { + assert(local_runqueue_circular_queue != NULL); + return (local_runqueue_circular_queue->rqueue_head - local_runqueue_circular_queue->rqueue_tail); +} + +/** + * Registers the PS variant with the polymorphic interface + */ +void +local_runqueue_circular_queue_initialize() +{ + /* Initialize local state */ + local_runqueue_circular_queue = (struct request_fifo_queue*) malloc(sizeof(struct request_fifo_queue)); + + assert(local_runqueue_circular_queue != NULL); + + local_runqueue_circular_queue->rqueue_tail = 0; + local_runqueue_circular_queue->rqueue_head = 0; + memset(local_runqueue_circular_queue->rqueue, 0, RQUEUE_QUEUE_LEN * sizeof(struct sandbox*)); + + worker_circular_queue[global_worker_thread_idx] = local_runqueue_circular_queue; + + + /* Register Function Pointers for Abstract Scheduling API */ + struct local_runqueue_config config = { .add_fn = local_runqueue_circular_queue_add, + .add_fn_idx = local_runqueue_circular_queue_add_index, + .is_empty_fn = local_runqueue_circular_queue_is_empty, + .delete_fn = local_runqueue_circular_queue_delete, + .get_next_fn = local_runqueue_circular_queue_get_next, + .get_length_fn = local_runqueue_circular_queue_get_length + }; + + local_runqueue_initialize(&config); +} + + From 1226a52f0f11907dde9494736e2da0de5225b5a3 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Sat, 7 Oct 2023 01:35:17 -0600 Subject: [PATCH 068/198] update meet_deadline_percentage.py --- runtime/tests/meet_deadline_percentage.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/runtime/tests/meet_deadline_percentage.py b/runtime/tests/meet_deadline_percentage.py index c7dddbd41..b975f6bf0 100644 --- a/runtime/tests/meet_deadline_percentage.py +++ b/runtime/tests/meet_deadline_percentage.py @@ -125,12 +125,13 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): p = np.percentile(a, int(percentage)) print(key + " " + percentage + " percentile is:" + str(p) + " mean is:" + str(np.mean(value)) + " max latency is:" + str(max_latency_dist[key])) #total_cpu_times = 0 - #for key,value in meet_deadline_dist.items(): + for key,value in meet_deadline_dist.items(): # total_cpu_times += value * fun_execution_time[key] - # miss_value = miss_deadline_dist[key] - # total_request = miss_value + value - # miss_rate = (miss_value * 100) / total_request - # + miss_value = miss_deadline_dist[key] + total_request = miss_value + value + miss_rate = (miss_value * 100) / total_request + + print(key + " miss deadline rate:" + str(miss_rate)); # print(func_name_dict[key] + " miss deadline rate:" + str(miss_rate) + " miss count is:" + str(miss_value) + " total request:" + str(total_request)) #print("effective total cpu times:", total_cpu_times) #for key,value in real_time_workload_times_dist.items(): From 592a844bdf7d00d9cb103c15f1bcd1bca65c0e5c Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Mon, 9 Oct 2023 17:26:43 -0600 Subject: [PATCH 069/198] format code --- runtime/include/scheduler.h | 2 +- runtime/src/listener_thread.c | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index c43b4f98b..81fbe71bf 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -338,7 +338,7 @@ scheduler_preemptive_sched(ucontext_t *interrupted_context) /* Delete current sandbox from local queue if dispatcher is DISPATCHER_SHINJUKU */ if (dispatcher == DISPATCHER_SHINJUKU) { uint64_t duration = (__getcycles() - interrupted_sandbox->start_ts_running_user) / runtime_processor_speed_MHz; - if (duration >= 50 && local_runqueue_get_length() > 1) { + if (duration >= 20 && local_runqueue_get_length() > 1) { local_runqueue_delete(interrupted_sandbox); sandbox_preempt(interrupted_sandbox); // Write back global at idx 0 diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 2cc36e4db..e3e4164dc 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -782,7 +782,7 @@ void shinjuku_dispatch_different_core() { struct sandbox *current = current_sandboxes[worker_list[i]]; if (!current) continue; //In case that worker thread hasn't call current_sandbox_set to set the current sandbox uint64_t duration = (__getcycles() - current->start_ts_running_user) / runtime_processor_speed_MHz; - if (duration >= 50 && (current->state == SANDBOX_RUNNING_USER || current->state == SANDBOX_RUNNING_SYS)) { + if (duration >= 7 && (current->state == SANDBOX_RUNNING_USER || current->state == SANDBOX_RUNNING_SYS)) { struct sandbox *sandbox = shinjuku_select_sandbox(); if (!sandbox) return; // queue is empty @@ -827,7 +827,7 @@ void shinjuku_dispatch() { struct sandbox *current = current_sandboxes[worker_list[i]]; if (!current) continue; //In case that worker thread hasn't call current_sandbox_set to set the current sandbox uint64_t duration = (__getcycles() - current->start_ts_running_user) / runtime_processor_speed_MHz; - if (duration >= 50 && (current->state == SANDBOX_RUNNING_USER || current->state == SANDBOX_RUNNING_SYS)) { + if (duration >= 20 && (current->state == SANDBOX_RUNNING_USER || current->state == SANDBOX_RUNNING_SYS)) { struct sandbox *sandbox = shinjuku_select_sandbox(); if (!sandbox) return; // queue is empty @@ -900,22 +900,22 @@ listener_thread_main(void *dummy) erpc_start(NULL, dispatcher_thread_idx, NULL, 0); if (dispatcher == DISPATCHER_EDF_INTERRUPT) { - printf("edf_interrupt....\n"); + printf("edf_interrupt....\n"); while (!pthread_stop) { erpc_run_event_loop(dispatcher_thread_idx, 1000); } } else if (dispatcher == DISPATCHER_DARC) { - printf("darc....\n"); + printf("darc....\n"); while (!pthread_stop) { erpc_run_event_loop_once(dispatcher_thread_idx); // get a group of packets from the NIC and enqueue them to the typed queue darc_dispatch(); //dispatch packets } } else if (dispatcher == DISPATCHER_SHINJUKU) { - printf("shinjuku....\n"); + printf("shinjuku....\n"); while (!pthread_stop) { - erpc_run_event_loop_once(dispatcher_thread_idx); // get a group of packets from the NIC and enqueue them to the typed queue - shinjuku_dispatch(); //dispatch packets - } + erpc_run_event_loop_once(dispatcher_thread_idx); // get a group of packets from the NIC and enqueue them to the typed queue + shinjuku_dispatch(); //dispatch packets + } } /* won't go to the following implementaion */ From d9ccc50ce3e54b65d3c4c7660c0a9cfb83a153ca Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 13 Oct 2023 00:09:50 -0600 Subject: [PATCH 070/198] solved variant TSC issue across CPU cores for shinjuku --- runtime/include/request_typed_deque.h | 2 ++ runtime/include/sandbox_set_as_error.h | 2 +- runtime/include/sandbox_set_as_running_user.h | 1 - runtime/include/sandbox_types.h | 2 +- runtime/include/scheduler.h | 7 +++---- runtime/src/arch_context.c | 2 +- runtime/src/current_sandbox.c | 11 ++--------- runtime/src/listener_thread.c | 19 ++++++++++++++----- runtime/src/request_typed_deque.c | 10 ++++++++++ runtime/src/software_interrupt.c | 9 +++++++-- 10 files changed, 41 insertions(+), 24 deletions(-) diff --git a/runtime/include/request_typed_deque.h b/runtime/include/request_typed_deque.h index 289938b61..29390b331 100644 --- a/runtime/include/request_typed_deque.h +++ b/runtime/include/request_typed_deque.h @@ -12,12 +12,14 @@ struct request_typed_deque { int front; int rear; int size; + int length; uint64_t tsqueue[RDEQUE_LEN]; }; struct request_typed_deque * request_typed_deque_init(uint8_t type, int size); bool isFull(struct request_typed_deque * queue); bool isEmpty(struct request_typed_deque * queue); +int getLength(struct request_typed_deque * queue); void insertfront(struct request_typed_deque * queue, struct sandbox * sandbox, uint64_t ts); void insertrear(struct request_typed_deque * queue, struct sandbox * sandbox, uint64_t ts); void deletefront(struct request_typed_deque * queue); diff --git a/runtime/include/sandbox_set_as_error.h b/runtime/include/sandbox_set_as_error.h index 11ed58c3d..63e2682e2 100644 --- a/runtime/include/sandbox_set_as_error.h +++ b/runtime/include/sandbox_set_as_error.h @@ -58,7 +58,7 @@ sandbox_set_as_error(struct sandbox *sandbox, sandbox_state_t last_state) admissions_control_subtract(sandbox->admissions_estimate); /* Return HTTP session to listener core to be written back to client */ - //http_session_set_response_header(sandbox->http, 500); + //http_session_set_response_header(sandbox->http, 500); //sandbox->http->state = HTTP_SESSION_EXECUTION_COMPLETE; //http_session_send_response(sandbox->http, (void_star_cb)listener_thread_register_http_session); diff --git a/runtime/include/sandbox_set_as_running_user.h b/runtime/include/sandbox_set_as_running_user.h index 1c730e2ae..5f0469efc 100644 --- a/runtime/include/sandbox_set_as_running_user.h +++ b/runtime/include/sandbox_set_as_running_user.h @@ -25,7 +25,6 @@ sandbox_set_as_running_user(struct sandbox *sandbox, sandbox_state_t last_state) break; } case SANDBOX_PREEMPTED: { - sandbox->start_ts_running_user = now; /* Sandbox resumes, update its RS */ sandbox->srsf_remaining_slack = sandbox->srsf_remaining_slack - (__getcycles() - sandbox->srsf_stop_running_ts); break; diff --git a/runtime/include/sandbox_types.h b/runtime/include/sandbox_types.h index e2df70892..2158a3b95 100644 --- a/runtime/include/sandbox_types.h +++ b/runtime/include/sandbox_types.h @@ -86,7 +86,7 @@ struct sandbox { int global_worker_thread_idx; /* which thread in a global view processes this sandbox. pause and restore the sandbox must be done in the same thread */ int group_worker_thread_idx; /* what's the thread index in the group */ - uint64_t start_ts_running_user; /* the start timestamp to run user, it will be updated when resume to run user */ + uint64_t start_ts; /* the start timestamp when dispatcher assign this sandbox to a worker */ /* For SRSF */ uint64_t srsf_stop_running_ts; /* record the timestamp of stopping running of this sandbox, in cycles */ int64_t srsf_remaining_slack; diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index 81fbe71bf..91cbe763c 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -337,8 +337,7 @@ scheduler_preemptive_sched(ucontext_t *interrupted_context) /* Delete current sandbox from local queue if dispatcher is DISPATCHER_SHINJUKU */ if (dispatcher == DISPATCHER_SHINJUKU) { - uint64_t duration = (__getcycles() - interrupted_sandbox->start_ts_running_user) / runtime_processor_speed_MHz; - if (duration >= 20 && local_runqueue_get_length() > 1) { + if (local_runqueue_get_length() > 1) { local_runqueue_delete(interrupted_sandbox); sandbox_preempt(interrupted_sandbox); // Write back global at idx 0 @@ -353,8 +352,8 @@ scheduler_preemptive_sched(ucontext_t *interrupted_context) assert(next != NULL); scheduler_preemptive_switch_to(interrupted_context, next); } else { - /* current sandbox shouldn't be interrupted becuase it runs less than 50us, or it is the only sandbox in the - local runqueue, so return directly, the current context isn't switched and will resume when single handler + /* current sandbox shouldn't be interrupted becuase it is the only request in the local queue + so return directly, the current context isn't switched and will resume when single handler returns */ sandbox_interrupt_return(interrupted_sandbox, SANDBOX_RUNNING_USER); diff --git a/runtime/src/arch_context.c b/runtime/src/arch_context.c index 1fd5df02e..cdc6db11b 100644 --- a/runtime/src/arch_context.c +++ b/runtime/src/arch_context.c @@ -15,6 +15,6 @@ noreturn void __attribute__((noinline)) arch_context_restore_preempted(void) { pthread_t tid = pthread_self(); - pthread_kill(tid, SIGUSR1); + pthread_kill(tid, SIGUSR1); panic("Unexpectedly reached code after sending self SIGUSR1\n"); } diff --git a/runtime/src/current_sandbox.c b/runtime/src/current_sandbox.c index 07c02de65..31f66e51b 100644 --- a/runtime/src/current_sandbox.c +++ b/runtime/src/current_sandbox.c @@ -54,10 +54,10 @@ current_sandbox_exit() switch (exiting_sandbox->state) { case SANDBOX_RETURNED: sandbox_exit_success(exiting_sandbox); - sandbox_send_response(exiting_sandbox, 0); + sandbox_send_response(exiting_sandbox, 0); break; case SANDBOX_RUNNING_SYS: - sandbox_send_response(exiting_sandbox, 1); + sandbox_send_response(exiting_sandbox, 1); sandbox_exit_error(exiting_sandbox); break; default: @@ -135,13 +135,6 @@ current_sandbox_init() sledge_abi__current_wasm_module_instance.wasi_context = sandbox->wasi_context; assert(sandbox->wasi_context != NULL); - /* Set start_ts_running_user for sandbox before it starts running - This setting must be done before sandbox_return() because after sandbox_return(), - state becomes running_user, which can be interrupted, howerver, if start_ts_running_user - wasn't set, then shinjuku will interrupt the sandbox immediately because start_ts_running_user - is 0, and the specified time interval to interrupt the sandbox is less than the big value - */ - sandbox->start_ts_running_user = __getcycles(); sandbox_return(sandbox); /* Initialize sandbox globals. Needs to run in user state */ diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index e3e4164dc..76b46166a 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -34,6 +34,7 @@ extern _Atomic uint64_t request_index; extern uint32_t runtime_worker_group_size; extern struct sandbox* current_sandboxes[1024]; +thread_local uint32_t dispatcher_try_interrupts = 0; thread_local uint32_t worker_start_id; thread_local uint32_t worker_end_id; thread_local uint32_t worker_list[MAX_WORKERS]; // record the worker's true id(0 - N workers - 1). worker_list[0] - worker_list[2] @@ -527,6 +528,7 @@ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, //urgent_request[candidate_thread_with_interrupt] = sandbox; local_runqueue_add_index(candidate_thread_with_interrupt, sandbox); preempt_worker(candidate_thread_with_interrupt); + dispatcher_try_interrupts++; } else { local_runqueue_add_index(thread_id, sandbox); } @@ -775,19 +777,21 @@ void shinjuku_dispatch_different_core() { struct sandbox *sandbox = shinjuku_select_sandbox(); if (!sandbox) return; // queue is empty + sandbox->start_ts = __getcycles(); local_runqueue_add_index(worker_list[i], sandbox); atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << i); } else { // core is busy //check if the current sandbox is running longer than the specified time duration struct sandbox *current = current_sandboxes[worker_list[i]]; if (!current) continue; //In case that worker thread hasn't call current_sandbox_set to set the current sandbox - uint64_t duration = (__getcycles() - current->start_ts_running_user) / runtime_processor_speed_MHz; + uint64_t duration = (__getcycles() - current->start_ts) / runtime_processor_speed_MHz; if (duration >= 7 && (current->state == SANDBOX_RUNNING_USER || current->state == SANDBOX_RUNNING_SYS)) { struct sandbox *sandbox = shinjuku_select_sandbox(); if (!sandbox) return; // queue is empty //preempt the current sandbox and put it back the typed queue, select a new one to send to it - local_runqueue_add_index(worker_list[i], sandbox); + sandbox->start_ts = __getcycles(); + local_runqueue_add_index(worker_list[i], sandbox); //preempt worker preempt_worker(worker_list[i]); } @@ -815,32 +819,37 @@ void shinjuku_dispatch() { struct sandbox *sandbox = shinjuku_select_sandbox(); if (!sandbox) return; // queue is empty while (sandbox->global_worker_thread_idx != -1) { + sandbox->start_ts = __getcycles(); local_runqueue_add_index(sandbox->global_worker_thread_idx, sandbox); sandbox = shinjuku_select_sandbox(); if (!sandbox) return; } - + + sandbox->start_ts = __getcycles(); local_runqueue_add_index(worker_list[i], sandbox); atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << i); } else { // core is busy //check if the current sandbox is running longer than the specified time duration struct sandbox *current = current_sandboxes[worker_list[i]]; if (!current) continue; //In case that worker thread hasn't call current_sandbox_set to set the current sandbox - uint64_t duration = (__getcycles() - current->start_ts_running_user) / runtime_processor_speed_MHz; - if (duration >= 20 && (current->state == SANDBOX_RUNNING_USER || current->state == SANDBOX_RUNNING_SYS)) { + uint64_t duration = (__getcycles() - current->start_ts) / runtime_processor_speed_MHz; + if (duration >= 25 && (current->state == SANDBOX_RUNNING_USER || current->state == SANDBOX_RUNNING_SYS)) { struct sandbox *sandbox = shinjuku_select_sandbox(); if (!sandbox) return; // queue is empty while (sandbox->global_worker_thread_idx != -1) { + sandbox->start_ts = __getcycles(); local_runqueue_add_index(sandbox->global_worker_thread_idx, sandbox); sandbox = shinjuku_select_sandbox(); if (!sandbox) return; } //preempt the current sandbox and put it back the typed queue, select a new one to send to it + sandbox->start_ts = __getcycles(); local_runqueue_add_index(worker_list[i], sandbox); //preempt worker preempt_worker(worker_list[i]); + dispatcher_try_interrupts++; } } diff --git a/runtime/src/request_typed_deque.c b/runtime/src/request_typed_deque.c index a270f2bf6..a8e576ab9 100644 --- a/runtime/src/request_typed_deque.c +++ b/runtime/src/request_typed_deque.c @@ -15,6 +15,7 @@ request_typed_deque_init(uint8_t type, int size) { deque->front = -1; deque->rear = 0; deque->size = size; + deque->length = 0; deque->deadline = 0; memset(deque->rqueue, 0, RDEQUE_LEN * sizeof(struct sandbox*)); @@ -63,6 +64,7 @@ void insertfront(struct request_typed_deque * queue, struct sandbox * sandbox, u // insert current element into request_typed_deque queue->rqueue[queue->front] = sandbox; queue->tsqueue[queue->front] = ts; + queue->length++; } // function to inset element at rear end @@ -93,6 +95,7 @@ void insertrear(struct request_typed_deque * queue, struct sandbox * sandbox, ui // insert current element into request_typed_deque queue->rqueue[queue->rear] = sandbox; queue->tsqueue[queue->rear] = ts; + queue->length++; } // Deletes element at front end of request_typed_deque @@ -122,6 +125,7 @@ void deletefront(struct request_typed_deque * queue) queue->front = queue->front + 1; } } + queue->length--; } @@ -146,6 +150,12 @@ void deleterear(struct request_typed_deque * queue) queue->rear = queue->size - 1; else queue->rear = queue->rear - 1; + queue->length--; +} + +int getLength(struct request_typed_deque * queue) { + assert(queue != NULL); + return queue->length; } // Returns front element of request_typed_deque diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index 6e52080fb..31fe598ac 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -27,7 +27,10 @@ #include "memlogging.h" #include "tenant_functions.h" +extern thread_local uint32_t dispatcher_try_interrupts; thread_local uint32_t interrupts = 0; +thread_local uint32_t preemptable_interrupts = 0; + extern struct sandbox* current_sandboxes[1024]; extern time_t t_start; extern thread_local int global_worker_thread_idx; @@ -176,6 +179,7 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void global_timeout_queue_process_promotions(); } } else if (current_sandbox_is_preemptable()) { + preemptable_interrupts++; /* Preemptable, so run scheduler. The scheduler handles outgoing state changes */ /* sandbox_interrupt means the sandbox stopped, but might be resume very soon. If deciding preempt the sandbox for a while, then will call sandbox_preempt */ @@ -242,6 +246,7 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void if (is_listener) { pthread_stop = true; + printf("try preempts:%u\n", dispatcher_try_interrupts); break; } @@ -250,9 +255,9 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void double seconds = difftime(t_end, t_start); double throughput = atomic_load(&sandbox_state_totals[SANDBOX_COMPLETE]) / seconds; uint32_t total_sandboxes_error = atomic_load(&sandbox_state_totals[SANDBOX_ERROR]); - mem_log("throughput %f tid(%d) error request %u complete requests %u total request %u total_local_requests %u interrupts %u\n", + mem_log("throughput %f tid(%d) error request %u complete requests %u total request %u total_local_requests %u interrupts %u p-interrupts %u\n", throughput, global_worker_thread_idx, total_sandboxes_error, atomic_load(&sandbox_state_totals[SANDBOX_COMPLETE]), - atomic_load(&sandbox_state_totals[SANDBOX_ALLOCATED]), total_local_requests, interrupts); + atomic_load(&sandbox_state_totals[SANDBOX_ALLOCATED]), total_local_requests, interrupts, preemptable_interrupts); dump_log_to_file(); pthread_stop = true; break; From fff7d9b88f937edef58e3830bd6e2dd620627554 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 13 Oct 2023 00:11:28 -0600 Subject: [PATCH 071/198] update and upload scripts --- runtime/tests/meet_deadline_percentage.py | 30 +++++ runtime/tests/parse_batch.py | 153 ++++++++++++++++++++++ runtime/tests/start_test.sh | 52 ++++++++ 3 files changed, 235 insertions(+) create mode 100644 runtime/tests/parse_batch.py create mode 100755 runtime/tests/start_test.sh diff --git a/runtime/tests/meet_deadline_percentage.py b/runtime/tests/meet_deadline_percentage.py index b975f6bf0..09bea486a 100644 --- a/runtime/tests/meet_deadline_percentage.py +++ b/runtime/tests/meet_deadline_percentage.py @@ -39,6 +39,8 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): #### request_counter = defaultdict(def_value) total_time_dist = defaultdict(list) + total_time_list = [] + total_slow_down = [] total_workload_dist = defaultdict(def_value) total_real_time_workload_dist = defaultdict(def_value) real_time_workload_times_dist = defaultdict(list) @@ -67,6 +69,11 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): request_counter[name] += 1 total_time = int(line.split(" ")[4]) total_time_dist[name].append(total_time) + if name == "fib": + total_slow_down.append(round((float(total_time) / 50), 2)) + else: + total_slow_down.append(round((float(total_time) / 7980), 2)) + total_time_list.append(total_time) thread_times[tid].append(total_time) if total_time > max_latency_dist[name]: max_latency_dist[name] = total_time @@ -88,6 +95,11 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): max_latency_dist[name] = total_time request_counter[name] += 1 total_time_dist[name].append(total_time) + total_time_list.append(total_time) + if name == "fib": + total_slow_down.append(round((float(total_time) / 50), 2)) + else: + total_slow_down.append(round((float(total_time) / 7980), 2)) thread_times[tid].append(total_time) miss_deadline_dist[name] += 1 exe_time = line.split(" ")[5] @@ -143,6 +155,24 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): print(len(value)) print(len(queuing_times[key])) print(len(total_time_dist[key])) + total_time_array = np.array(total_time_list) + p_99 = np.percentile(total_time_array, 99) + p_99_9 = np.percentile(total_time_array, 99.9) + p_99_99 = np.percentile(total_time_array, 99.99) + print("99 percentile latency is ", p_99) + print("99.9 percentile latency is ", p_99_9) + print("99.99 percentile latency is ", p_99_99) + total_time_slow_down = np.array(total_slow_down) + p_99_slow_down = np.percentile(total_time_slow_down, 99) + p_99_9_slow_down = np.percentile(total_time_slow_down, 99.9) + p_99_99_slow_down = np.percentile(total_time_slow_down, 99.99) + print("99 percentile slow down is ", p_99_slow_down) + print("99.9 percentile slow down is ", p_99_9_slow_down) + print("99.99 percentile slow down is ", p_99_99_slow_down) + js_latency = json.dumps(total_time_list) + f_latency = open("total_time_list.txt", 'w') + f_latency.write(js_latency) + f_latency.close() js = json.dumps(total_time_dist) f = open("total_time.txt", 'w') f.write(js) diff --git a/runtime/tests/parse_batch.py b/runtime/tests/parse_batch.py new file mode 100644 index 000000000..5dd73ce46 --- /dev/null +++ b/runtime/tests/parse_batch.py @@ -0,0 +1,153 @@ +import re +import os +import sys +from collections import defaultdict + +#get all file names which contain key_str +def file_name(file_dir, key_str): + print(file_dir, key_str) + file_list = [] + rps_list = [] + + for root, dirs, files in os.walk(file_dir): + print(files, root, dirs) + for file_i in files: + if file_i.find(key_str) >= 0: + full_path = os.path.join(os.getcwd() + "/" + root, file_i) + #print(full_path) + segs = file_i.split('-') + if len(segs) < 2: + continue + rps=segs[1] + rps=rps.split(".")[0] + file_list.append(full_path) + rps_list.append(rps) + + file_list = sorted(file_list, key = lambda x: int(x.split('-')[-1].split(".")[0])) + rps_list = sorted(rps_list) + print(file_list) + print(rps_list) + return file_list, rps_list + +def get_values(key, files_list, latency_dict, slow_down_dict, slow_down_99_9_dict, latency_99_9_dict, slow_down_99_99_dict, latency_99_99_dict): + for file_i in files_list: + cmd='sudo python3 ./meet_deadline_percentage.py %s 99' % file_i + rt=os.popen(cmd).read().strip() + print(rt) + # Define regular expressions to match the desired values + latency_rule = r'99 percentile latency is\s*([\d.]+)' + slow_down_rule = r'99 percentile slow down is\s*([\d.]+)' + latency_99_9_rule = '99.9 percentile latency is\s*([\d.]+)' + slow_down_99_9_rule = '99.9 percentile slow down is\s*([\d.]+)' + latency_99_99_rule = '99.99 percentile latency is\s*([\d.]+)' + slow_down_99_99_rule = '99.99 percentile slow down is\s*([\d.]+)' + + # Use the regular expressions to find the values + latency_match = re.search(latency_rule, rt) + slow_down_match = re.search(slow_down_rule, rt) + latency_99_9_match = re.search(latency_99_9_rule, rt) + slow_down_99_9_match = re.search(slow_down_99_9_rule, rt) + latency_99_99_match = re.search(latency_99_99_rule, rt) + slow_down_99_99_match = re.search(slow_down_99_99_rule, rt) + + # Check if matches were found and extract the values + if latency_match: + latency_value = 0 + latency_value = latency_match.group(1) + print("99th latency is:", latency_value) + latency_dict[key].append(latency_value) + + if slow_down_match: + slow_down_value = 0 + slow_down_value = slow_down_match.group(1) + print("99th slow down is:", slow_down_value) + slow_down_dict[key].append(slow_down_value) + + if latency_99_9_match: + latency_value = 0 + latency_value = latency_99_9_match.group(1) + print("99.9th latency is:", latency_value) + latency_99_9_dict[key].append(latency_value) + + if slow_down_99_9_match: + slow_down_value = 0 + slow_down_value = slow_down_99_9_match.group(1) + print("99.9th slow down is:", slow_down_value) + slow_down_99_9_dict[key].append(slow_down_value) + + if latency_99_99_match: + latency_value = 0 + latency_value = latency_99_99_match.group(1) + print("99.99th latency is:", latency_value) + latency_99_99_dict[key].append(latency_value) + + if slow_down_99_99_match: + slow_down_value = 0 + slow_down_value = slow_down_99_99_match.group(1) + print("99.99th slow down is:", slow_down_value) + slow_down_99_99_dict[key].append(slow_down_value) + +if __name__ == "__main__": + import json + #file_folders = ['SHINJUKU', 'SHINJUKU_25', 'DARC', 'EDF_SRSF_INTERRUPT'] + #file_folders = ['SHINJUKU_100', 'SHINJUKU_200', 'SHINJUKU_25', 'DARC', 'EDF_SRSF_INTERRUPT'] + file_folders = ['SHINJUKU'] + latency = defaultdict(list) + slow_down = defaultdict(list) + slow_down_99_9 = defaultdict(list) + latency_99_9 = defaultdict(list) + slow_down_99_99 = defaultdict(list) + latency_99_99 = defaultdict(list) + + rps_list = [] + + argv = sys.argv[1:] + if len(argv) < 1: + print("usage ", sys.argv[0], "[file key]") + sys.exit() + + for key in file_folders: + files_list, rps_list = file_name(key, argv[0]) + get_values(key, files_list, latency, slow_down, slow_down_99_9, latency_99_9, slow_down_99_99, latency_99_99) + + print("99 latency:") + for key, value in latency.items(): + print(key, ":", value) + print("99 slow down:") + for key, value in slow_down.items(): + print(key, ":", value) + + js1 = json.dumps(latency) + f1 = open("99_latency.txt", 'w') + f1.write(js1) + f1.close() + + js2 = json.dumps(slow_down) + f2 = open("99_slow_down.txt", 'w') + f2.write(js2) + f2.close() + + js4 = json.dumps(latency_99_9) + f4 = open("99_9_latency.txt", 'w') + f4.write(js4) + f4.close() + + js5 = json.dumps(slow_down_99_9) + f5 = open("99_9_slow_down.txt", 'w') + f5.write(js5) + f5.close() + + js6 = json.dumps(latency_99_99) + f6 = open("99_99_latency.txt", 'w') + f6.write(js6) + f6.close() + + js7 = json.dumps(slow_down_99_99) + f7 = open("99_99_slow_down.txt", 'w') + f7.write(js7) + f7.close() + + js3 = json.dumps(rps_list) + f3 = open("rps.txt", 'w') + f3.write(js3) + f3.close() diff --git a/runtime/tests/start_test.sh b/runtime/tests/start_test.sh new file mode 100755 index 000000000..be41cee43 --- /dev/null +++ b/runtime/tests/start_test.sh @@ -0,0 +1,52 @@ +#!/bin/bash +ulimit -n 655350 + +function usage { + echo "$0 [worker num] [listener num] [first worker core id] [dispatcher policy, SHINJUKU or EDF_INTERRUPT or DARC] [server log file]" + exit 1 +} + +if [ $# != 5 ] ; then + usage + exit 1; +fi + +worker_num=$1 +listener_num=$2 +first_worker_core_id=$3 +dispatcher_policy=$4 +server_log=$5 + +declare project_path="$( + cd "$(dirname "$0")/../.." + pwd +)" +echo $project_path +path=`pwd` +export SLEDGE_DISABLE_PREEMPTION=true +#export SLEDGE_SIGALRM_HANDLER=TRIAGED +export SLEDGE_FIRST_WORKER_COREID=$first_worker_core_id +export SLEDGE_NWORKERS=$worker_num +export SLEDGE_NLISTENERS=$listener_num +export SLEDGE_WORKER_GROUP_SIZE=3 +export SLEDGE_SCHEDULER=EDF +#export SLEDGE_DISPATCHER=DARC +export SLEDGE_DISPATCHER=$dispatcher_policy +#export SLEDGE_DISPATCHER=EDF_INTERRUPT +export SLEDGE_SANDBOX_PERF_LOG=$path/$server_log +#echo $SLEDGE_SANDBOX_PERF_LOG +cd $project_path/runtime/bin +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_fibonacci.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_big_fibonacci.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_armcifar10.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_png2bmp.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_image_processing.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/mulitple_linear_chain.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing3.json +LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/fib.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/empty.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/my_fibonacci.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_sodresize.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/my_sodresize.json + From d14f89ceccb2a962eb19f67284311b40d6293ae9 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 20 Oct 2023 16:19:09 -0600 Subject: [PATCH 072/198] add sledge extend abi for webassembly to get cpu cycles --- libsledge/include/sledge_abi.h | 1 + libsledge/src/sledge_extensions.c | 9 +++++++++ runtime/src/sledge_abi.c | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/libsledge/include/sledge_abi.h b/libsledge/include/sledge_abi.h index 2b47f86ec..4c5556b80 100644 --- a/libsledge/include/sledge_abi.h +++ b/libsledge/include/sledge_abi.h @@ -256,3 +256,4 @@ int sledge_abi__scratch_storage_set(uint32_t key_offset, uint32_t key_len, uint3 int sledge_abi__scratch_storage_delete(uint32_t key_offset, uint32_t key_len); void sledge_abi__scratch_storage_upsert(uint32_t key_offset, uint32_t key_len, uint32_t value_offset, uint32_t value_len); +uint64_t sledge_abi__env_getcycles(); diff --git a/libsledge/src/sledge_extensions.c b/libsledge/src/sledge_extensions.c index 3687a4fe5..1d973e7e3 100644 --- a/libsledge/src/sledge_extensions.c +++ b/libsledge/src/sledge_extensions.c @@ -63,3 +63,12 @@ scratch_storage_upsert(uint32_t key_offset, uint32_t key_len, uint32_t value_off { sledge_abi__scratch_storage_upsert(key_offset, key_len, value_offset, value_len); } + +/* + * Return CPU cycles + */ +INLINE uint64_t +env_getcycles() { + return sledge_abi__env_getcycles(); +} + diff --git a/runtime/src/sledge_abi.c b/runtime/src/sledge_abi.c index 6d1424ad5..86daa4fa4 100644 --- a/runtime/src/sledge_abi.c +++ b/runtime/src/sledge_abi.c @@ -1163,3 +1163,8 @@ sledge_abi__scratch_storage_upsert(uint32_t key_offset, uint32_t key_len, uint32 sandbox_return(sandbox); } + +EXPORT uint64_t +sledge_abi__env_getcycles() { + return __getcycles(); +} From 08b6d41aa7780f865dd1a6568283af3c0f25a54e Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Mon, 23 Oct 2023 12:12:29 -0600 Subject: [PATCH 073/198] Add more debug log, but comment them for later use --- runtime/include/sandbox_set_as_complete.h | 5 +- runtime/include/sandbox_set_as_interrupted.h | 4 + runtime/include/sandbox_set_as_running_sys.h | 6 + runtime/include/sandbox_set_as_running_user.h | 9 + runtime/include/scheduler.h | 3 + runtime/src/current_sandbox.c | 12 +- runtime/src/listener_thread.c | 26 ++- runtime/src/software_interrupt.c | 3 +- runtime/tests/parse_batch.py | 12 +- runtime/tests/test_dequeue.cpp | 192 +++++++++--------- 10 files changed, 163 insertions(+), 109 deletions(-) diff --git a/runtime/include/sandbox_set_as_complete.h b/runtime/include/sandbox_set_as_complete.h index 59a984d68..3cc3b949a 100644 --- a/runtime/include/sandbox_set_as_complete.h +++ b/runtime/include/sandbox_set_as_complete.h @@ -45,7 +45,10 @@ sandbox_set_as_complete(struct sandbox *sandbox, sandbox_state_t last_state) sandbox_state_history_append(&sandbox->state_history, SANDBOX_COMPLETE); sandbox_state_totals_increment(SANDBOX_COMPLETE); sandbox_state_totals_decrement(last_state); - + //---------xiaosu--------------- + //printf("id %lu total running sys %lu, total running user %lu\n", sandbox->id, sandbox->duration_of_state[SANDBOX_RUNNING_SYS], + // sandbox->duration_of_state[SANDBOX_RUNNING_USER]); + //----------xiaosu------------- /* Admissions Control Post Processing */ admissions_info_update(&sandbox->route->admissions_info, sandbox->duration_of_state[SANDBOX_RUNNING_USER] + sandbox->duration_of_state[SANDBOX_RUNNING_SYS]); diff --git a/runtime/include/sandbox_set_as_interrupted.h b/runtime/include/sandbox_set_as_interrupted.h index e2ee3699d..41cc08797 100644 --- a/runtime/include/sandbox_set_as_interrupted.h +++ b/runtime/include/sandbox_set_as_interrupted.h @@ -26,6 +26,10 @@ sandbox_set_as_interrupted(struct sandbox *sandbox, sandbox_state_t last_state) assert(now > sandbox->timestamp_of.last_state_change); sandbox->last_state_duration = now - sandbox->timestamp_of.last_state_change; sandbox->duration_of_state[last_state] += sandbox->last_state_duration; + //------------xiaosu------------------- + //printf("id %lu interrupt, current ts %lu last state %d last duration %lu total duration %lu\n", sandbox->id, now, last_state, + // sandbox->last_state_duration, sandbox->duration_of_state[last_state]); + //-------------xiaosu------------------ sandbox->timestamp_of.last_state_change = now; /* We do not append SANDBOX_INTERRUPTED to the sandbox_state_history because it would quickly fill the buffer */ sandbox_state_totals_increment(SANDBOX_INTERRUPTED); diff --git a/runtime/include/sandbox_set_as_running_sys.h b/runtime/include/sandbox_set_as_running_sys.h index a77a69788..ec8c6840c 100644 --- a/runtime/include/sandbox_set_as_running_sys.h +++ b/runtime/include/sandbox_set_as_running_sys.h @@ -42,6 +42,12 @@ sandbox_set_as_running_sys(struct sandbox *sandbox, sandbox_state_t last_state) assert(now > sandbox->timestamp_of.last_state_change); sandbox->last_state_duration = now - sandbox->timestamp_of.last_state_change; sandbox->duration_of_state[last_state] += sandbox->last_state_duration; + //--------------xiaosu------------------ + //if (last_state == SANDBOX_RUNNING_USER) { + // printf("id %lu running sys, current ts %lu last running user duration %lu total running user duration %lu\n", + // sandbox->id, now, sandbox->last_state_duration, sandbox->duration_of_state[last_state]); + //} + //-------------xiaosu------------------- sandbox->timestamp_of.last_state_change = now; sandbox_state_history_append(&sandbox->state_history, SANDBOX_RUNNING_SYS); sandbox_state_totals_increment(SANDBOX_RUNNING_SYS); diff --git a/runtime/include/sandbox_set_as_running_user.h b/runtime/include/sandbox_set_as_running_user.h index 5f0469efc..aff21f103 100644 --- a/runtime/include/sandbox_set_as_running_user.h +++ b/runtime/include/sandbox_set_as_running_user.h @@ -40,6 +40,15 @@ sandbox_set_as_running_user(struct sandbox *sandbox, sandbox_state_t last_state) assert(now > sandbox->timestamp_of.last_state_change); sandbox->last_state_duration = now - sandbox->timestamp_of.last_state_change; sandbox->duration_of_state[last_state] += sandbox->last_state_duration; + //------------xiaosu------------------ + /*if (last_state == SANDBOX_RUNNING_SYS) { + printf("id %lu running user, last running sys, current ts %lu total running user %lu total running sys %lu\n", + sandbox->id, now, sandbox->duration_of_state[SANDBOX_RUNNING_USER], sandbox->duration_of_state[last_state]); + } else { + printf("id %lu running user, last preempt, current ts %lu total running user %lu total preempt %lu\n", + sandbox->id, now, sandbox->duration_of_state[SANDBOX_RUNNING_USER], sandbox->duration_of_state[last_state]); + }*/ + //-------------xiaosu---------------- sandbox->timestamp_of.last_state_change = now; sandbox_state_history_append(&sandbox->state_history, SANDBOX_RUNNING_USER); sandbox_state_totals_increment(SANDBOX_RUNNING_USER); diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index 91cbe763c..aa6648b65 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -282,6 +282,9 @@ scheduler_preemptive_switch_to(ucontext_t *interrupted_context, struct sandbox * assert(next->state == SANDBOX_PREEMPTED); arch_context_restore_slow(&interrupted_context->uc_mcontext, &next->ctxt); current_sandbox_set(next); + //-----------xiaosu-------------- + //printf("id %lu resume from slow\n", next->id); + //-----------xiaosu-------------- sandbox_set_as_running_user(next, SANDBOX_PREEMPTED); break; } diff --git a/runtime/src/current_sandbox.c b/runtime/src/current_sandbox.c index 31f66e51b..75061dc04 100644 --- a/runtime/src/current_sandbox.c +++ b/runtime/src/current_sandbox.c @@ -64,6 +64,14 @@ current_sandbox_exit() panic("Cooperatively switching from a sandbox in a non-terminal %s state\n", sandbox_state_stringify(exiting_sandbox->state)); } + //---------xiaosu----------------- + /*char str[4096] = {0}; + sprintf(str, "id %lu ", exiting_sandbox->id); + for (int i = 0; i < exiting_sandbox->state_history.size; i++) { + sprintf(str + strlen(str), "sate %d ", exiting_sandbox->state_history.buffer[i]); + } + printf("%s\n", str);*/ + //-----------xiaosu--------------- scheduler_cooperative_sched(true); /* The scheduler should never switch back to completed sandboxes */ @@ -159,7 +167,9 @@ current_sandbox_fini() sandbox->timestamp_of.completion = __getcycles(); sandbox->total_time = sandbox->timestamp_of.completion - sandbox->timestamp_of.allocation; - + //-----------xiaosu----------------------- + //printf("id %lu finish, total time %lu, current ts %lu\n", sandbox->id, sandbox->total_time, sandbox->timestamp_of.completion); + //----------xiaosu------------------------- assert(sandbox->state == SANDBOX_RUNNING_SYS); done: diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 76b46166a..45231ffc6 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -19,6 +19,9 @@ #include "request_typed_deque.h" #include "local_preempted_fifo_queue.h" +thread_local uint32_t global_queue_length = 0; +thread_local uint32_t max_queue_length = 0; + struct perf_window * worker_perf_windows[1024]; struct priority_queue * worker_queues[1024]; struct binary_tree * worker_binary_trees[1024]; @@ -588,6 +591,11 @@ void darc_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t s memcpy(sandbox->rpc_request_body, msg, size); sandbox->rpc_request_body_size = size; push_to_rqueue(sandbox, request_type_queue[req_type - 1], __getcycles()); + global_queue_length++; + if (global_queue_length > max_queue_length) { + max_queue_length = global_queue_length; + } + } @@ -645,6 +653,10 @@ void shinjuku_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size memcpy(sandbox->rpc_request_body, msg, size); sandbox->rpc_request_body_size = size; insertrear(request_type_deque[req_type -1], sandbox, __getcycles()); + global_queue_length++; + if (global_queue_length > max_queue_length) { + max_queue_length = global_queue_length; + } } void drain_queue(struct request_typed_queue *rtype) { @@ -681,6 +693,7 @@ void drain_queue(struct request_typed_queue *rtype) { struct sandbox *sandbox = rtype->rqueue[rtype->rqueue_tail & (RQUEUE_LEN - 1)]; //add sandbox to worker's local queue local_runqueue_add_index(worker_list[worker_id], sandbox); + global_queue_length--; rtype->rqueue_tail++; atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << worker_id); } @@ -785,7 +798,7 @@ void shinjuku_dispatch_different_core() { struct sandbox *current = current_sandboxes[worker_list[i]]; if (!current) continue; //In case that worker thread hasn't call current_sandbox_set to set the current sandbox uint64_t duration = (__getcycles() - current->start_ts) / runtime_processor_speed_MHz; - if (duration >= 7 && (current->state == SANDBOX_RUNNING_USER || current->state == SANDBOX_RUNNING_SYS)) { + if (duration >= 100 && (current->state == SANDBOX_RUNNING_USER || current->state == SANDBOX_RUNNING_SYS)) { struct sandbox *sandbox = shinjuku_select_sandbox(); if (!sandbox) return; // queue is empty @@ -811,6 +824,7 @@ void shinjuku_dispatch() { while(preempted_sandbox != NULL) { uint8_t req_type = preempted_sandbox->route->request_type; insertfront(request_type_deque[req_type - 1], preempted_sandbox, tsc); + global_queue_length++; //insertrear(request_type_deque[req_type - 1], preempted_sandbox, tsc); preempted_sandbox = pop_worker_preempted_queue(worker_list[i], preempted_queue, &tsc); } @@ -821,25 +835,28 @@ void shinjuku_dispatch() { while (sandbox->global_worker_thread_idx != -1) { sandbox->start_ts = __getcycles(); local_runqueue_add_index(sandbox->global_worker_thread_idx, sandbox); + global_queue_length--; sandbox = shinjuku_select_sandbox(); if (!sandbox) return; } sandbox->start_ts = __getcycles(); local_runqueue_add_index(worker_list[i], sandbox); + global_queue_length--; atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << i); } else { // core is busy //check if the current sandbox is running longer than the specified time duration struct sandbox *current = current_sandboxes[worker_list[i]]; if (!current) continue; //In case that worker thread hasn't call current_sandbox_set to set the current sandbox uint64_t duration = (__getcycles() - current->start_ts) / runtime_processor_speed_MHz; - if (duration >= 25 && (current->state == SANDBOX_RUNNING_USER || current->state == SANDBOX_RUNNING_SYS)) { + if (duration >= 5 && (current->state == SANDBOX_RUNNING_USER || current->state == SANDBOX_RUNNING_SYS)) { struct sandbox *sandbox = shinjuku_select_sandbox(); if (!sandbox) return; // queue is empty while (sandbox->global_worker_thread_idx != -1) { sandbox->start_ts = __getcycles(); local_runqueue_add_index(sandbox->global_worker_thread_idx, sandbox); + global_queue_length--; sandbox = shinjuku_select_sandbox(); if (!sandbox) return; } @@ -847,6 +864,7 @@ void shinjuku_dispatch() { //preempt the current sandbox and put it back the typed queue, select a new one to send to it sandbox->start_ts = __getcycles(); local_runqueue_add_index(worker_list[i], sandbox); + global_queue_length--; //preempt worker preempt_worker(worker_list[i]); dispatcher_try_interrupts++; @@ -874,10 +892,10 @@ listener_thread_main(void *dummy) { is_listener = true; /* Unmask SIGINT signals */ - software_interrupt_unmask_signal(SIGINT); + software_interrupt_unmask_signal(SIGINT); /* Index was passed via argument */ - dispatcher_thread_idx = *(int *)dummy; + dispatcher_thread_idx = *(int *)dummy; /* init typed queue */ typed_queue_init(); diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index 31fe598ac..b8b3cd48a 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -27,6 +27,7 @@ #include "memlogging.h" #include "tenant_functions.h" +extern thread_local uint32_t max_queue_length; extern thread_local uint32_t dispatcher_try_interrupts; thread_local uint32_t interrupts = 0; thread_local uint32_t preemptable_interrupts = 0; @@ -246,7 +247,7 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void if (is_listener) { pthread_stop = true; - printf("try preempts:%u\n", dispatcher_try_interrupts); + printf("try preempts:%u max queue %u\n", dispatcher_try_interrupts, max_queue_length); break; } diff --git a/runtime/tests/parse_batch.py b/runtime/tests/parse_batch.py index 5dd73ce46..8fbca84db 100644 --- a/runtime/tests/parse_batch.py +++ b/runtime/tests/parse_batch.py @@ -37,10 +37,10 @@ def get_values(key, files_list, latency_dict, slow_down_dict, slow_down_99_9_dic # Define regular expressions to match the desired values latency_rule = r'99 percentile latency is\s*([\d.]+)' slow_down_rule = r'99 percentile slow down is\s*([\d.]+)' - latency_99_9_rule = '99.9 percentile latency is\s*([\d.]+)' - slow_down_99_9_rule = '99.9 percentile slow down is\s*([\d.]+)' - latency_99_99_rule = '99.99 percentile latency is\s*([\d.]+)' - slow_down_99_99_rule = '99.99 percentile slow down is\s*([\d.]+)' + latency_99_9_rule = r'99.9 percentile latency is\s*([\d.]+)' + slow_down_99_9_rule = r'99.9 percentile slow down is\s*([\d.]+)' + latency_99_99_rule = r'99.99 percentile latency is\s*([\d.]+)' + slow_down_99_99_rule = r'99.99 percentile slow down is\s*([\d.]+)' # Use the regular expressions to find the values latency_match = re.search(latency_rule, rt) @@ -90,8 +90,8 @@ def get_values(key, files_list, latency_dict, slow_down_dict, slow_down_99_9_dic if __name__ == "__main__": import json #file_folders = ['SHINJUKU', 'SHINJUKU_25', 'DARC', 'EDF_SRSF_INTERRUPT'] - #file_folders = ['SHINJUKU_100', 'SHINJUKU_200', 'SHINJUKU_25', 'DARC', 'EDF_SRSF_INTERRUPT'] - file_folders = ['SHINJUKU'] + file_folders = ['SHINJUKU_5', 'SHINJUKU_100', 'SHINJUKU_200', 'SHINJUKU_25', 'DARC', 'EDF_SRSF_INTERRUPT'] + #file_folders = ['SHINJUKU'] latency = defaultdict(list) slow_down = defaultdict(list) slow_down_99_9 = defaultdict(list) diff --git a/runtime/tests/test_dequeue.cpp b/runtime/tests/test_dequeue.cpp index aee4a85db..7f17baca3 100644 --- a/runtime/tests/test_dequeue.cpp +++ b/runtime/tests/test_dequeue.cpp @@ -1,193 +1,193 @@ -// C++ implementation of De-queue using circular -// array -#include -using namespace std; - +// C implementation of De-queue using circular array // Maximum size of array or Dequeue +#include +#include #define MAX 100 - + +using namespace std; // A structure to represent a Deque -class Deque { +struct Deque { int arr[MAX]; int front; int rear; int size; - -public: - Deque(int size) - { - front = -1; - rear = 0; - this->size = size; - } - - // Operations on Deque: - void insertfront(int key); - void insertrear(int key); - void deletefront(); - void deleterear(); - bool isFull(); - bool isEmpty(); - int getFront(); - int getRear(); }; + + +void init_deque(struct Deque * queue, int size) { + assert(queue != NULL); + queue->front = -1; + queue->rear = 0; + queue->size = size; +} // Checks whether Deque is full or not. -bool Deque::isFull() +bool isFull(struct Deque * queue) { - return ((front == 0 && rear == size - 1) - || front == rear + 1); + assert(queue != NULL); + return ((queue->front == 0 && queue->rear == queue->size - 1) + || queue->front == queue->rear + 1); } // Checks whether Deque is empty or not. -bool Deque::isEmpty() { return (front == -1); } +bool isEmpty(struct Deque * queue) { + + assert(queue != NULL); + return (queue->front == -1); +} // Inserts an element at front -void Deque::insertfront(int key) +void insertfront(struct Deque * queue, int key) { + assert(queue != NULL); // check whether Deque if full or not - if (isFull()) { - cout << "Overflow\n" << endl; + if (isFull(queue)) { + printf( "Overflow\n"); return; } // If queue is initially empty - if (front == -1) { - front = 0; - rear = 0; + if (queue->front == -1) { + queue->front = 0; + queue->rear = 0; } // front is at first position of queue - else if (front == 0) - front = size - 1; + else if (queue->front == 0) + queue->front = queue->size - 1; else // decrement front end by '1' - front = front - 1; + queue->front = queue->front - 1; // insert current element into Deque - arr[front] = key; + queue->arr[queue->front] = key; } // function to inset element at rear end // of Deque. -void Deque ::insertrear(int key) +void insertrear(struct Deque * queue, int key) { - if (isFull()) { - cout << " Overflow\n " << endl; + assert(queue != NULL); + + if (isFull(queue)) { + printf(" Overflow\n"); return; } // If queue is initially empty - if (front == -1) { - front = 0; - rear = 0; + if (queue->front == -1) { + queue->front = 0; + queue->rear = 0; } // rear is at last position of queue - else if (rear == size - 1) - rear = 0; + else if (queue->rear == queue->size - 1) + queue->rear = 0; // increment rear end by '1' else - rear = rear + 1; + queue->rear = queue->rear + 1; // insert current element into Deque - arr[rear] = key; + queue->arr[queue->rear] = key; } // Deletes element at front end of Deque -void Deque ::deletefront() +void deletefront(struct Deque * queue) { + assert(queue != NULL); + // check whether Deque is empty or not - if (isEmpty()) { - cout << "Queue Underflow\n" << endl; + if (isEmpty(queue)) { + printf("Queue Underflow\n"); return; } // Deque has only one element - if (front == rear) { - front = -1; - rear = -1; + if (queue->front == queue->rear) { + queue->front = -1; + queue->rear = -1; } - else + else { // back to initial position - if (front == size - 1) - front = 0; + if (queue->front == queue->size - 1) + queue->front = 0; - else // increment front by '1' to remove current - // front value from Deque - front = front + 1; + else // increment front by '1' to remove current + // front value from Deque + queue->front = queue->front + 1; + } } // Delete element at rear end of Deque -void Deque::deleterear() +void deleterear(struct Deque * queue) { - if (isEmpty()) { - cout << " Underflow\n" << endl; + assert(queue != NULL); + if (isEmpty(queue)) { + printf(" Underflow\n"); return; } // Deque has only one element - if (front == rear) { - front = -1; - rear = -1; + if (queue->front == queue->rear) { + queue->front = -1; + queue->rear = -1; } - else if (rear == 0) - rear = size - 1; + else if (queue->rear == 0) + queue->rear = queue->size - 1; else - rear = rear - 1; + queue->rear = queue->rear - 1; } // Returns front element of Deque -int Deque::getFront() +int getFront(struct Deque * queue) { + assert(queue != NULL); // check whether Deque is empty or not - if (isEmpty()) { - cout << " Underflow\n" << endl; + if (isEmpty(queue)) { + printf(" Underflow\n"); return -1; } - return arr[front]; + return queue->arr[queue->front]; } // function return rear element of Deque -int Deque::getRear() +int getRear(struct Deque * queue) { + assert(queue != NULL); // check whether Deque is empty or not - if (isEmpty() || rear < 0) { - cout << " Underflow\n" << endl; + if (isEmpty(queue) || queue->rear < 0) { + printf(" Underflow\n"); return -1; } - return arr[rear]; + return queue->arr[queue->rear]; } // Driver code int main() { - Deque dq(5); + struct Deque dq; + init_deque(&dq, 5); - // Function calls - cout << "Insert element at rear end : 5 \n"; - dq.insertrear(5); + // Function calls + printf("Insert element at rear end : 5 \n"); + insertrear(&dq, 5); - cout << "insert element at rear end : 10 \n"; - dq.insertrear(10); + printf("insert element at rear end : 10 \n"); + insertrear(&dq, 10); - cout << "get rear element " - << " " << dq.getRear() << endl; + printf("get rear element %d \n", getRear(&dq)); - dq.deleterear(); - cout << "After delete rear element new rear" - << " become " << dq.getRear() << endl; + deleterear(&dq); + printf("After delete rear element new rear become %d ", getRear(&dq)); - cout << "inserting element at front end \n"; - dq.insertfront(15); + printf("inserting element at front end \n"); + insertfront(&dq, 15); - cout << "get front element " - << " " << dq.getFront() << endl; + printf("get front element %d\n", getFront(&dq)); - dq.deletefront(); + deletefront(&dq); - cout << "After delete front element new " - << "front become " << dq.getFront() << endl; + printf("After delete front element new front become %d", getFront(&dq)); return 0; } From 2eb381c9074e056a63264cbbd045c2e02526b8de Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Mon, 23 Oct 2023 12:15:30 -0600 Subject: [PATCH 074/198] add test_tsc.c --- runtime/tests/test_tsc.c | 179 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 runtime/tests/test_tsc.c diff --git a/runtime/tests/test_tsc.c b/runtime/tests/test_tsc.c new file mode 100644 index 000000000..0c80a8460 --- /dev/null +++ b/runtime/tests/test_tsc.c @@ -0,0 +1,179 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#define LISTENER_COUNTS 3 +#define WORKER_COUNTS 9 +#define LISTENER_THREAD_START_CORE_ID 1 + + +int listener_threads[LISTENER_COUNTS] = {1, 2, 3}; +int worker_threads[WORKER_COUNTS] = {4, 5, 6, 7, 8, 9, 10, 11, 12}; +int runtime_first_worker_processor = 4; +thread_local int global_worker_thread_idx; +thread_local int dispatcher_id; +thread_local int group_worker_thread_idx; +int diff_cycles[LISTENER_COUNTS][WORKER_COUNTS] = {0}; +//thread_local uint64_t current_cycles = 0; +uint64_t current_worker_cycles[WORKER_COUNTS] = {0}; +uint64_t current_listener_cycles[LISTENER_COUNTS] = {0}; +int runtime_worker_group_size = 3; +int stop = 0; +pthread_t *runtime_worker_threads; +pthread_t *runtime_listener_threads; +thread_local pthread_t listener_thread_id; +thread_local uint8_t dispatcher_thread_idx; +int *runtime_worker_threads_argument; +int *runtime_listener_threads_argument; + +//#if defined(X86_64) || defined(x86_64) + +unsigned long long int +__getcycles(void) +{ + unsigned long long int cpu_time_in_cycles = 0; + unsigned int cycles_lo; + unsigned int cycles_hi; + __asm__ volatile("rdtsc" : "=a"(cycles_lo), "=d"(cycles_hi)); + cpu_time_in_cycles = (unsigned long long int)cycles_hi << 32 | cycles_lo; + + return cpu_time_in_cycles; +} + +//#endif + +void * +worker_thread_main(void *argument) +{ + /* Index was passed via argument */ + global_worker_thread_idx = *(int *)argument; + + /* Set dispatcher id for this worker */ + dispatcher_id = global_worker_thread_idx / runtime_worker_group_size; + + group_worker_thread_idx = global_worker_thread_idx - dispatcher_id * runtime_worker_group_size; + + printf("global thread %d's dispatcher id is %d group size is %d group id is %d\n", global_worker_thread_idx, + dispatcher_id, runtime_worker_group_size, group_worker_thread_idx); + while(stop == 0) { + current_worker_cycles[global_worker_thread_idx] = __getcycles(); + } +} +/** + * Starts all worker threads and sleeps forever on pthread_join, which should never return + */ +void +runtime_start_runtime_worker_threads() +{ + for (int i = 0; i < WORKER_COUNTS; i++) { + printf("start %d thread\n", i); + runtime_worker_threads_argument[i] = i; + /* Pass the value we want the threads to use when indexing into global arrays of per-thread values */ + int ret = pthread_create(&runtime_worker_threads[i], NULL, worker_thread_main, (void *)&runtime_worker_threads_argument[i]); + if (ret) { + perror("pthread_create"); + exit(-1); + } + + cpu_set_t cs; + CPU_ZERO(&cs); + CPU_SET(runtime_first_worker_processor + i, &cs); + ret = pthread_setaffinity_np(runtime_worker_threads[i], sizeof(cs), &cs); + assert(ret == 0); + printf("Starting %d worker thread(s), pin to core %d\n", i, runtime_first_worker_processor + i); + } +} + +void * +listener_thread_main(void *dummy) +{ + /* Index was passed via argument */ + dispatcher_thread_idx = *(int *)dummy; + while(stop == 0) { + current_listener_cycles[dispatcher_thread_idx] = __getcycles(); + } +} + +void +listener_thread_initialize(uint8_t thread_id) +{ + printf("Starting listener thread\n"); + + cpu_set_t cs; + + CPU_ZERO(&cs); + CPU_SET(LISTENER_THREAD_START_CORE_ID + thread_id, &cs); + + runtime_listener_threads_argument[thread_id] = thread_id; + + int ret = pthread_create(&runtime_listener_threads[thread_id], NULL, listener_thread_main, (void *)&runtime_listener_threads_argument[thread_id]); + listener_thread_id = runtime_listener_threads[thread_id]; + assert(ret == 0); + ret = pthread_setaffinity_np(listener_thread_id, sizeof(cpu_set_t), &cs); + assert(ret == 0); + + printf("\tListener %d thread, pin to core %d\n", thread_id, LISTENER_THREAD_START_CORE_ID + thread_id); +} + +void listener_threads_initialize() { + printf("Starting %d listener thread(s)\n", LISTENER_COUNTS); + for (int i = 0; i < LISTENER_COUNTS; i++) { + listener_thread_initialize(i); + } +} + +int main() { + + cpu_set_t cs; + + CPU_ZERO(&cs); + CPU_SET(0, &cs); + + int ret = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cs); + assert(ret == 0); + + runtime_worker_threads = calloc(WORKER_COUNTS, sizeof(pthread_t)); + assert(runtime_worker_threads != NULL); + runtime_listener_threads = calloc(LISTENER_COUNTS, sizeof(pthread_t)); + assert(runtime_listener_threads != NULL); + runtime_worker_threads_argument = calloc(WORKER_COUNTS, sizeof(int)); + assert(runtime_worker_threads_argument != NULL); + + runtime_listener_threads_argument = calloc(WORKER_COUNTS, sizeof(int)); + assert(runtime_listener_threads_argument != NULL); + + runtime_start_runtime_worker_threads(); + listener_threads_initialize(); + + sleep(5); + stop = 1; + for (int i = 0; i < WORKER_COUNTS; i++) { + int ret = pthread_join(runtime_worker_threads[i], NULL); + if (ret) { + perror("worker pthread_join"); + exit(-1); + } + } + + for (int i = 0; i < LISTENER_COUNTS; i++) { + int ret = pthread_join(runtime_listener_threads[i], NULL); + if (ret) { + perror("listener pthread_join"); + exit(-1); + } + } + + for(int i = 0; i < LISTENER_COUNTS; i++) { + for (int j = 0; j < WORKER_COUNTS; j++) { + int diff = current_worker_cycles[j] - current_listener_cycles[i]; + diff_cycles[i][j] = diff; + printf("listener %d diff worker %d is %d\n", i, j, diff); + } + } +} From 2303536ff978bbac37ee970e3b3a0fad92b07c58 Mon Sep 17 00:00:00 2001 From: xiaosuGW Date: Thu, 26 Oct 2023 23:39:18 -0600 Subject: [PATCH 075/198] precalculate the interrupt interval to cycles for shinjuku --- runtime/src/listener_thread.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 45231ffc6..35fd3d15b 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -19,6 +19,7 @@ #include "request_typed_deque.h" #include "local_preempted_fifo_queue.h" +uint64_t shinjuku_interrupt_interval = 0; thread_local uint32_t global_queue_length = 0; thread_local uint32_t max_queue_length = 0; @@ -797,8 +798,8 @@ void shinjuku_dispatch_different_core() { //check if the current sandbox is running longer than the specified time duration struct sandbox *current = current_sandboxes[worker_list[i]]; if (!current) continue; //In case that worker thread hasn't call current_sandbox_set to set the current sandbox - uint64_t duration = (__getcycles() - current->start_ts) / runtime_processor_speed_MHz; - if (duration >= 100 && (current->state == SANDBOX_RUNNING_USER || current->state == SANDBOX_RUNNING_SYS)) { + uint64_t elapsed_cycles = (__getcycles() - current->start_ts); + if (elapsed_cycles >= shinjuku_interrupt_interval && (current->state == SANDBOX_RUNNING_USER || current->state == SANDBOX_RUNNING_SYS)) { struct sandbox *sandbox = shinjuku_select_sandbox(); if (!sandbox) return; // queue is empty @@ -806,6 +807,7 @@ void shinjuku_dispatch_different_core() { sandbox->start_ts = __getcycles(); local_runqueue_add_index(worker_list[i], sandbox); //preempt worker + dispatcher_try_interrupts++; preempt_worker(worker_list[i]); } } @@ -848,8 +850,8 @@ void shinjuku_dispatch() { //check if the current sandbox is running longer than the specified time duration struct sandbox *current = current_sandboxes[worker_list[i]]; if (!current) continue; //In case that worker thread hasn't call current_sandbox_set to set the current sandbox - uint64_t duration = (__getcycles() - current->start_ts) / runtime_processor_speed_MHz; - if (duration >= 5 && (current->state == SANDBOX_RUNNING_USER || current->state == SANDBOX_RUNNING_SYS)) { + uint64_t elapsed_cycles = (__getcycles() - current->start_ts); + if (elapsed_cycles >= shinjuku_interrupt_interval && (current->state == SANDBOX_RUNNING_USER || current->state == SANDBOX_RUNNING_SYS)) { struct sandbox *sandbox = shinjuku_select_sandbox(); if (!sandbox) return; // queue is empty @@ -891,6 +893,7 @@ void * listener_thread_main(void *dummy) { is_listener = true; + shinjuku_interrupt_interval = 50 * runtime_processor_speed_MHz; /* Unmask SIGINT signals */ software_interrupt_unmask_signal(SIGINT); From 31de83c6631654dda351a3e04da97a2d06aa34ec Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Mon, 30 Oct 2023 01:05:18 -0600 Subject: [PATCH 076/198] add simulated exponential service time on sledge: when sledge get a parameter from client, it can know the execution time and deadline. Currently, the deadline is 10 times of the execution time --- runtime/include/sandbox_perf_log.h | 9 ++++---- runtime/include/sandbox_types.h | 1 + runtime/src/listener_thread.c | 27 +++++++++++++++++++++--- runtime/src/local_runqueue_binary_tree.c | 24 ++++++++++++--------- runtime/src/main.c | 12 +++++++++++ runtime/src/sandbox.c | 1 + 6 files changed, 57 insertions(+), 17 deletions(-) diff --git a/runtime/include/sandbox_perf_log.h b/runtime/include/sandbox_perf_log.h index 17f830ef8..671349593 100644 --- a/runtime/include/sandbox_perf_log.h +++ b/runtime/include/sandbox_perf_log.h @@ -44,6 +44,7 @@ sandbox_perf_log_print_entry(struct sandbox *sandbox) / runtime_processor_speed_MHz; uint64_t cleanup = sandbox->timestamp_of.cleanup / runtime_processor_speed_MHz; + uint64_t deadline = sandbox->relative_deadline / runtime_processor_speed_MHz; uint64_t other = sandbox->timestamp_of.other / runtime_processor_speed_MHz; uint64_t t1 = sandbox->ret[0] / runtime_processor_speed_MHz; uint64_t t2 = sandbox->ret[1] / runtime_processor_speed_MHz; @@ -54,11 +55,11 @@ sandbox_perf_log_print_entry(struct sandbox *sandbox) uint64_t init_time = sandbox->duration_of_state[SANDBOX_INITIALIZED] / runtime_processor_speed_MHz; if (miss_deadline) { - mem_log("tid %d %u miss %lu %lu %lu %s %lu %lu f%d %lu %lu %lu %lu %lu %lu\n", global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route, - init_time, cleanup, sandbox->context_switch_to, other, t1,t2,t3,t4,t5); + mem_log("tid %d %u miss %lu %lu %lu %s %lu %lu %lu f%d %lu %lu %lu %lu %lu %lu\n", global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route, + init_time, cleanup, deadline, sandbox->context_switch_to, other, t1,t2,t3,t4,t5); } else { - mem_log("tid %d %u meet %lu %lu %lu %s %lu %lu f%d %lu %lu %lu %lu %lu %lu\n", global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route, - init_time, cleanup, sandbox->context_switch_to, other, t1,t2,t3,t4,t5); + mem_log("tid %d %u meet %lu %lu %lu %s %lu %lu %lu f%d %lu %lu %lu %lu %lu %lu\n", global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route, + init_time, cleanup, deadline, sandbox->context_switch_to, other, t1,t2,t3,t4,t5); } /* * Assumption: A sandbox is never able to free pages. If linear memory management diff --git a/runtime/include/sandbox_types.h b/runtime/include/sandbox_types.h index 2158a3b95..30fb71818 100644 --- a/runtime/include/sandbox_types.h +++ b/runtime/include/sandbox_types.h @@ -83,6 +83,7 @@ struct sandbox { int context_switch_to; /* 1 means context switch to base, 2 means context swtich to next sandbox */ uint64_t ret[5]; uint64_t estimated_cost; /* estimated execution cost */ + uint64_t relative_deadline; int global_worker_thread_idx; /* which thread in a global view processes this sandbox. pause and restore the sandbox must be done in the same thread */ int group_worker_thread_idx; /* what's the thread index in the group */ diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 35fd3d15b..a4cd6494d 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -19,6 +19,10 @@ #include "request_typed_deque.h" #include "local_preempted_fifo_queue.h" +#define BASE_SERVICE_TIME 10 +#define LOSS_PERCENTAGE 0.11 + +uint64_t base_simulated_service_time = 0; uint64_t shinjuku_interrupt_interval = 0; thread_local uint32_t global_queue_length = 0; thread_local uint32_t max_queue_length = 0; @@ -30,6 +34,7 @@ struct request_fifo_queue * worker_circular_queue[1024]; struct ps_list_head * worker_lists[1024]; struct request_fifo_queue * worker_preempted_queue[1024]; +extern bool runtime_exponential_service_time_simulation_enabled; extern _Atomic uint64_t worker_queuing_cost[1024]; //struct sandbox *urgent_request[1024] = { NULL }; extern uint32_t runtime_worker_threads_count; @@ -489,6 +494,13 @@ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, return; } + /* Reset estimated execution time and relative deadline for exponential service time simulation */ + if (runtime_exponential_service_time_simulation_enabled) { + sandbox->estimated_cost = base_simulated_service_time * atoi((const char *)msg) * (1 - LOSS_PERCENTAGE); + sandbox->relative_deadline = 10 * sandbox->estimated_cost; + sandbox->absolute_deadline = sandbox->timestamp_of.allocation + sandbox->relative_deadline; + } + /* copy the received data since it will be released by erpc */ sandbox->rpc_request_body = malloc(size); if (!sandbox->rpc_request_body) { @@ -645,6 +657,13 @@ void shinjuku_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size return; } + /* Reset estimated execution time and relative deadline for exponential service time simulation */ + if (runtime_exponential_service_time_simulation_enabled) { + sandbox->estimated_cost = base_simulated_service_time * atoi((const char *)msg) * (1 - LOSS_PERCENTAGE); + sandbox->relative_deadline = 10 * sandbox->estimated_cost; + sandbox->absolute_deadline = sandbox->timestamp_of.allocation + sandbox->relative_deadline; + } + /* copy the received data since it will be released by erpc */ sandbox->rpc_request_body = malloc(size); if (!sandbox->rpc_request_body) { @@ -715,7 +734,7 @@ struct sandbox * shinjuku_peek_selected_sandbox(int *selected_queue_idx) { struct sandbox *sandbox = getFront(request_type_deque[i], &ts); assert(sandbox != NULL); uint64_t dt = __getcycles() - ts; - float priority = (float)dt / (float)sandbox->route->relative_deadline; + float priority = (float)dt / (float)sandbox->relative_deadline; if (priority > highest_priority) { highest_priority = priority; *selected_queue_idx = i; @@ -747,7 +766,7 @@ struct sandbox * shinjuku_select_sandbox() { struct sandbox *sandbox = getFront(request_type_deque[i], &ts); assert(sandbox != NULL); uint64_t dt = __getcycles() - ts; - float priority = (float)dt / (float)sandbox->route->relative_deadline; + float priority = (float)dt / (float)sandbox->relative_deadline; if (priority > highest_priority) { highest_priority = priority; selected_queue_idx = i; @@ -893,7 +912,9 @@ void * listener_thread_main(void *dummy) { is_listener = true; - shinjuku_interrupt_interval = 50 * runtime_processor_speed_MHz; + shinjuku_interrupt_interval = 100 * runtime_processor_speed_MHz; + base_simulated_service_time = BASE_SERVICE_TIME * runtime_processor_speed_MHz; + /* Unmask SIGINT signals */ software_interrupt_unmask_signal(SIGINT); diff --git a/runtime/src/local_runqueue_binary_tree.c b/runtime/src/local_runqueue_binary_tree.c index 888edd978..ac9a6b1e5 100644 --- a/runtime/src/local_runqueue_binary_tree.c +++ b/runtime/src/local_runqueue_binary_tree.c @@ -13,6 +13,7 @@ #include "sandbox_functions.h" #include "runtime.h" +extern bool runtime_exponential_service_time_simulation_enabled; extern thread_local int global_worker_thread_idx; extern struct sandbox* current_sandboxes[1024]; extern struct binary_tree *worker_binary_trees[1024]; @@ -59,17 +60,20 @@ local_runqueue_binary_tree_add_index(int index, struct sandbox *sandbox) lock_unlock(&binary_tree->lock, &node_lock); /* Set estimated exeuction time for the sandbox */ - uint32_t uid = sandbox->route->admissions_info.uid; - uint64_t estimated_execute_cost = perf_window_get_percentile(&worker_perf_windows[index][uid], + if (runtime_exponential_service_time_simulation_enabled == false) { + uint32_t uid = sandbox->route->admissions_info.uid; + uint64_t estimated_execute_cost = perf_window_get_percentile(&worker_perf_windows[index][uid], sandbox->route->admissions_info.percentile, sandbox->route->admissions_info.control_index); - /* Use expected execution time in the configuration file as the esitmated execution time - if estimated_execute_cost is 0 - */ - if (estimated_execute_cost == 0) { - estimated_execute_cost = sandbox->route->expected_execution_cycle; - } - sandbox->estimated_cost = estimated_execute_cost; + /* Use expected execution time in the configuration file as the esitmated execution time + if estimated_execute_cost is 0 + */ + if (estimated_execute_cost == 0) { + estimated_execute_cost = sandbox->route->expected_execution_cycle; + } + sandbox->estimated_cost = estimated_execute_cost; + sandbox->relative_deadline = sandbox->route->relative_deadline; + } /* Record TS and calcuate RS. SRSF algo: 1. When reqeust arrives to the queue, record TS and calcuate RS. RS = deadline - execution time 2. When request starts running, update RS @@ -77,7 +81,7 @@ local_runqueue_binary_tree_add_index(int index, struct sandbox *sandbox) 4. When request resumes, update RS */ sandbox->srsf_stop_running_ts = __getcycles(); - sandbox->srsf_remaining_slack = sandbox->route->relative_deadline - sandbox->estimated_cost; + sandbox->srsf_remaining_slack = sandbox->relative_deadline - sandbox->estimated_cost; } /** diff --git a/runtime/src/main.c b/runtime/src/main.c index c1f92b71d..6d030e1ff 100644 --- a/runtime/src/main.c +++ b/runtime/src/main.c @@ -45,6 +45,7 @@ uint32_t runtime_worker_group_size = 1; enum RUNTIME_SIGALRM_HANDLER runtime_sigalrm_handler = RUNTIME_SIGALRM_HANDLER_BROADCAST; +bool runtime_exponential_service_time_simulation_enabled = false; bool runtime_preemption_enabled = true; bool runtime_worker_spinloop_pause_enabled = false; uint32_t runtime_quantum_us = 5000; /* 5ms */ @@ -298,6 +299,17 @@ runtime_configure() } pretty_print_key_value("Quantum", "%u us\n", runtime_quantum_us); + /* Runtime exponential service time simulation */ + char *exponential_service_time_simulation_disable = getenv("SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION"); + if (exponential_service_time_simulation_disable != NULL && + strcmp(exponential_service_time_simulation_disable, "false") == 0) { + runtime_exponential_service_time_simulation_enabled = true; + } + + pretty_print_key_value("Exponential_service_time_simulation", " %s\n", + runtime_exponential_service_time_simulation_enabled ? + PRETTY_PRINT_GREEN_ENABLED : PRETTY_PRINT_RED_DISABLED); + sandbox_perf_log_init(); http_session_perf_log_init(); } diff --git a/runtime/src/sandbox.c b/runtime/src/sandbox.c index 5f1dbf993..1a09620cd 100644 --- a/runtime/src/sandbox.c +++ b/runtime/src/sandbox.c @@ -181,6 +181,7 @@ sandbox_init(struct sandbox *sandbox, struct module *module, struct http_session sandbox->cursor = 0; sandbox->absolute_deadline = sandbox->timestamp_of.allocation + sandbox->route->relative_deadline; + sandbox->relative_deadline = sandbox->route->relative_deadline; sandbox->global_worker_thread_idx = -1; sandbox->group_worker_thread_idx = -1; From f034eb89da41b00cd38e8b53b9262ab594c53613 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Mon, 30 Oct 2023 01:09:25 -0600 Subject: [PATCH 077/198] 1. change type 2's execution time and deadline for fib.json. 2. Modify meet_deadline_percentage.py to get deadline from the server log instead of hardcode. 3. Export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION in start.sh and start_test.sh --- runtime/tests/fib.json | 8 ++++---- runtime/tests/meet_deadline_percentage.py | 16 ++++++++++++---- runtime/tests/start.sh | 1 + runtime/tests/start_test.sh | 1 + 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/runtime/tests/fib.json b/runtime/tests/fib.json index bbdbaa091..47604108a 100644 --- a/runtime/tests/fib.json +++ b/runtime/tests/fib.json @@ -8,7 +8,7 @@ { "route": "/fib", "request-type": 1, - "n-resas": 2, + "n-resas": 2, "path": "fibonacci.wasm.so", "admissions-percentile": 70, "expected-execution-us": 5, @@ -18,11 +18,11 @@ { "route": "/fib2", "request-type": 2, - "n-resas": 1, + "n-resas": 1, "path": "fibonacci.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 798, - "relative-deadline-us": 7980, + "expected-execution-us": 6480, + "relative-deadline-us": 64800, "http-resp-content-type": "text/plain" } ] diff --git a/runtime/tests/meet_deadline_percentage.py b/runtime/tests/meet_deadline_percentage.py index 09bea486a..d685673da 100644 --- a/runtime/tests/meet_deadline_percentage.py +++ b/runtime/tests/meet_deadline_percentage.py @@ -10,6 +10,7 @@ def def_value(): def count_miss_or_meet_deadline_requests(file_dir, percentage): throughput = 0; + max_exe_time = 0 ### each time for a request request_times_dict = defaultdict(def_list_value) #### get execution time @@ -64,21 +65,24 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): meet_deadline += 1 name = line.split(" ")[7] cleanup = line.split(" ")[9] + deadline = int(line.split(" ")[10]) name = name[1:] tid = line.split(" ")[1] request_counter[name] += 1 total_time = int(line.split(" ")[4]) total_time_dist[name].append(total_time) if name == "fib": - total_slow_down.append(round((float(total_time) / 50), 2)) + total_slow_down.append(round((float(total_time) / deadline), 2)) else: - total_slow_down.append(round((float(total_time) / 7980), 2)) + total_slow_down.append(round((float(total_time) / deadline), 2)) total_time_list.append(total_time) thread_times[tid].append(total_time) if total_time > max_latency_dist[name]: max_latency_dist[name] = total_time meet_deadline_dist[name] += 1 exe_time = int(line.split(" ")[5]) + if exe_time > max_exe_time: + max_exe_time = exe_time running_times[name].append(exe_time); queue_time = int(line.split(" ")[6]) queuing_times[name].append(queue_time); @@ -88,6 +92,7 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): miss_deadline += 1 name = line.split(" ")[7] cleanup = line.split(" ")[9] + deadline = int(line.split(" ")[10]) name = name[1:] tid = line.split(" ")[1] total_time = int(line.split(" ")[4]) @@ -97,13 +102,15 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): total_time_dist[name].append(total_time) total_time_list.append(total_time) if name == "fib": - total_slow_down.append(round((float(total_time) / 50), 2)) + total_slow_down.append(round((float(total_time) / deadline), 2)) else: - total_slow_down.append(round((float(total_time) / 7980), 2)) + total_slow_down.append(round((float(total_time) / deadline), 2)) thread_times[tid].append(total_time) miss_deadline_dist[name] += 1 exe_time = line.split(" ")[5] exe_time = int(line.split(" ")[5]) + if exe_time > max_exe_time: + max_exe_time = exe_time running_times[name].append(exe_time); queue_time = int(line.split(" ")[6]) queuing_times[name].append(queue_time); @@ -169,6 +176,7 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): print("99 percentile slow down is ", p_99_slow_down) print("99.9 percentile slow down is ", p_99_9_slow_down) print("99.99 percentile slow down is ", p_99_99_slow_down) + print("max exe time:", max_exe_time) js_latency = json.dumps(total_time_list) f_latency = open("total_time_list.txt", 'w') f_latency.write(js_latency) diff --git a/runtime/tests/start.sh b/runtime/tests/start.sh index f5839f956..bc4453220 100755 --- a/runtime/tests/start.sh +++ b/runtime/tests/start.sh @@ -22,6 +22,7 @@ declare project_path="$( echo $project_path path=`pwd` export SLEDGE_DISABLE_PREEMPTION=true +export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=true #export SLEDGE_SIGALRM_HANDLER=TRIAGED export SLEDGE_FIRST_WORKER_COREID=$first_worker_core_id export SLEDGE_NWORKERS=$worker_num diff --git a/runtime/tests/start_test.sh b/runtime/tests/start_test.sh index be41cee43..ccc1d597c 100755 --- a/runtime/tests/start_test.sh +++ b/runtime/tests/start_test.sh @@ -25,6 +25,7 @@ echo $project_path path=`pwd` export SLEDGE_DISABLE_PREEMPTION=true #export SLEDGE_SIGALRM_HANDLER=TRIAGED +export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=false export SLEDGE_FIRST_WORKER_COREID=$first_worker_core_id export SLEDGE_NWORKERS=$worker_num export SLEDGE_NLISTENERS=$listener_num From 64864d4ad777caf4eaae33fc34c2ba3a7010ddc2 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 1 Nov 2023 00:42:22 -0600 Subject: [PATCH 078/198] 1. Add code to print out the maximum local queue length of each worker when exit. 2. Increase local queue maximum length to 4096 and global queue maximum length to 65535 for shinjuku. 3. For simulated exponential service time distribution, if the passed argument value is 1, let the execution time to 10, otherwise, multiply the loss rate 4. For simulated exponential distribution service time, send each request's pure cpu time as the response content to the client side --- runtime/include/request_fifo_queue.h | 2 +- runtime/include/request_typed_deque.h | 2 +- runtime/src/listener_thread.c | 14 ++++++++++++-- runtime/src/local_runqueue_binary_tree.c | 10 +++++++++- runtime/src/local_runqueue_circular_queue.c | 7 +++++++ runtime/src/sandbox.c | 14 ++++++++++++-- runtime/src/software_interrupt.c | 4 +++- 7 files changed, 45 insertions(+), 8 deletions(-) diff --git a/runtime/include/request_fifo_queue.h b/runtime/include/request_fifo_queue.h index 3b4fbe088..f380ca97f 100644 --- a/runtime/include/request_fifo_queue.h +++ b/runtime/include/request_fifo_queue.h @@ -2,7 +2,7 @@ #include #include -#define RQUEUE_QUEUE_LEN 256 +#define RQUEUE_QUEUE_LEN 4096 struct request_fifo_queue { struct sandbox *rqueue[RQUEUE_QUEUE_LEN]; diff --git a/runtime/include/request_typed_deque.h b/runtime/include/request_typed_deque.h index 29390b331..0adca59ca 100644 --- a/runtime/include/request_typed_deque.h +++ b/runtime/include/request_typed_deque.h @@ -3,7 +3,7 @@ #include #include -#define RDEQUE_LEN 4096 +#define RDEQUE_LEN 65535 struct request_typed_deque { uint8_t type; diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index a4cd6494d..9dba33156 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -496,7 +496,12 @@ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, /* Reset estimated execution time and relative deadline for exponential service time simulation */ if (runtime_exponential_service_time_simulation_enabled) { - sandbox->estimated_cost = base_simulated_service_time * atoi((const char *)msg) * (1 - LOSS_PERCENTAGE); + int exp_num = atoi((const char *)msg); + if (exp_num == 1) { + sandbox->estimated_cost = base_simulated_service_time; + } else { + sandbox->estimated_cost = base_simulated_service_time * exp_num * (1 - LOSS_PERCENTAGE); + } sandbox->relative_deadline = 10 * sandbox->estimated_cost; sandbox->absolute_deadline = sandbox->timestamp_of.allocation + sandbox->relative_deadline; } @@ -659,7 +664,12 @@ void shinjuku_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size /* Reset estimated execution time and relative deadline for exponential service time simulation */ if (runtime_exponential_service_time_simulation_enabled) { - sandbox->estimated_cost = base_simulated_service_time * atoi((const char *)msg) * (1 - LOSS_PERCENTAGE); + int exp_num = atoi((const char *)msg); + if (exp_num == 1) { + sandbox->estimated_cost = base_simulated_service_time; + } else { + sandbox->estimated_cost = base_simulated_service_time * exp_num * (1 - LOSS_PERCENTAGE); + } sandbox->relative_deadline = 10 * sandbox->estimated_cost; sandbox->absolute_deadline = sandbox->timestamp_of.allocation + sandbox->relative_deadline; } diff --git a/runtime/src/local_runqueue_binary_tree.c b/runtime/src/local_runqueue_binary_tree.c index ac9a6b1e5..985c08445 100644 --- a/runtime/src/local_runqueue_binary_tree.c +++ b/runtime/src/local_runqueue_binary_tree.c @@ -13,6 +13,8 @@ #include "sandbox_functions.h" #include "runtime.h" +uint32_t local_queue_length[1024] = {0}; +uint32_t max_local_queue_length[1024] = {0}; extern bool runtime_exponential_service_time_simulation_enabled; extern thread_local int global_worker_thread_idx; extern struct sandbox* current_sandboxes[1024]; @@ -59,6 +61,11 @@ local_runqueue_binary_tree_add_index(int index, struct sandbox *sandbox) binary_tree->root = insert(binary_tree, binary_tree->root, sandbox); lock_unlock(&binary_tree->lock, &node_lock); + local_queue_length[index]++; + if (local_queue_length[index] > max_local_queue_length[index]) { + max_local_queue_length[index] = local_queue_length[index]; + } + /* Set estimated exeuction time for the sandbox */ if (runtime_exponential_service_time_simulation_enabled == false) { uint32_t uid = sandbox->route->admissions_info.uid; @@ -102,7 +109,8 @@ local_runqueue_binary_tree_delete(struct sandbox *sandbox) panic("Tried to delete sandbox %lu state %d from runqueue %p, but was not present\n", sandbox->id, sandbox->state, local_runqueue_binary_tree); } - + + local_queue_length[global_worker_thread_idx]--; } diff --git a/runtime/src/local_runqueue_circular_queue.c b/runtime/src/local_runqueue_circular_queue.c index b2a94dc38..2ac410242 100644 --- a/runtime/src/local_runqueue_circular_queue.c +++ b/runtime/src/local_runqueue_circular_queue.c @@ -8,6 +8,8 @@ #include "likely.h" #include "request_fifo_queue.h" +extern uint32_t local_queue_length[1024]; +extern uint32_t max_local_queue_length[1024]; extern thread_local int global_worker_thread_idx; extern struct request_fifo_queue * worker_circular_queue[1024]; thread_local static struct request_fifo_queue * local_runqueue_circular_queue = NULL; @@ -44,6 +46,10 @@ local_runqueue_circular_queue_add_index(int index, struct sandbox *sandbox){ local_runqueue->rqueue[head & (RQUEUE_QUEUE_LEN - 1)] = sandbox; local_runqueue->rqueue_head++; } + local_queue_length[index]++; + if (local_queue_length[index] > max_local_queue_length[index]) { + max_local_queue_length[index] = local_queue_length[index]; + } } bool @@ -64,6 +70,7 @@ local_runqueue_circular_queue_delete(struct sandbox *sandbox) { = NULL; local_runqueue_circular_queue->rqueue_tail++; + local_queue_length[global_worker_thread_idx]--; } /* Called by worker thread to get item from the tail of the queue */ diff --git a/runtime/src/sandbox.c b/runtime/src/sandbox.c index 1a09620cd..76b44bfe7 100644 --- a/runtime/src/sandbox.c +++ b/runtime/src/sandbox.c @@ -15,6 +15,7 @@ #include "wasm_memory.h" #include "wasm_stack.h" +extern bool runtime_exponential_service_time_simulation_enabled; extern thread_local int group_worker_thread_idx; _Atomic uint64_t sandbox_total = 0; @@ -281,6 +282,15 @@ sandbox_free(struct sandbox *sandbox, uint64_t *ret) } void sandbox_send_response(struct sandbox *sandbox, uint8_t response_code) { - auto_buf_flush(&sandbox->response_body); - erpc_req_response_enqueue(sandbox->rpc_id, sandbox->rpc_handler, sandbox->response_body.data, sandbox->response_body.size, response_code); + if (runtime_exponential_service_time_simulation_enabled && response_code == 0) { + uint64_t pure_cpu_time = (sandbox->duration_of_state[SANDBOX_RUNNING_SYS] + sandbox->duration_of_state[SANDBOX_RUNNING_USER]) + / runtime_processor_speed_MHz; + char tmp_buf[20] = {0}; + sprintf(tmp_buf, "%lu", pure_cpu_time); + erpc_req_response_enqueue(sandbox->rpc_id, sandbox->rpc_handler, tmp_buf, strlen(tmp_buf), response_code); + } else { + auto_buf_flush(&sandbox->response_body); + erpc_req_response_enqueue(sandbox->rpc_id, sandbox->rpc_handler, + sandbox->response_body.data, sandbox->response_body.size, response_code); + } } diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index b8b3cd48a..6a2afd335 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -27,6 +27,7 @@ #include "memlogging.h" #include "tenant_functions.h" +extern uint32_t max_local_queue_length[1024]; extern thread_local uint32_t max_queue_length; extern thread_local uint32_t dispatcher_try_interrupts; thread_local uint32_t interrupts = 0; @@ -247,7 +248,7 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void if (is_listener) { pthread_stop = true; - printf("try preempts:%u max queue %u\n", dispatcher_try_interrupts, max_queue_length); + printf("try preempts:%u max global queue %u\n", dispatcher_try_interrupts, max_queue_length); break; } @@ -260,6 +261,7 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void throughput, global_worker_thread_idx, total_sandboxes_error, atomic_load(&sandbox_state_totals[SANDBOX_COMPLETE]), atomic_load(&sandbox_state_totals[SANDBOX_ALLOCATED]), total_local_requests, interrupts, preemptable_interrupts); dump_log_to_file(); + printf("max local queue %u\n", max_local_queue_length[global_worker_thread_idx]); pthread_stop = true; break; } From b55279d730e4de2f70051649248ef11a0509d39b Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 2 Nov 2023 18:00:53 -0600 Subject: [PATCH 079/198] fix bug for shinjuku: The first worker of each listener thread has a longer queue then other workers, because each time, the iteration is from the first worker queue. Fixing this by using round robin to choose a different queue to iterate with --- runtime/include/binary_search_tree.h | 2 +- runtime/include/local_runqueue.h | 3 ++ runtime/include/scheduler.h | 3 +- runtime/src/listener_thread.c | 57 +++++++++++++++------ runtime/src/local_runqueue.c | 3 ++ runtime/src/local_runqueue_binary_tree.c | 8 +-- runtime/src/local_runqueue_circular_queue.c | 16 ++++-- runtime/src/sandbox.c | 2 +- runtime/src/software_interrupt.c | 18 ++++--- runtime/src/worker_thread.c | 3 ++ 10 files changed, 82 insertions(+), 33 deletions(-) diff --git a/runtime/include/binary_search_tree.h b/runtime/include/binary_search_tree.h index abbe7beb3..4265cd819 100644 --- a/runtime/include/binary_search_tree.h +++ b/runtime/include/binary_search_tree.h @@ -4,7 +4,7 @@ #include "lock.h" -#define MAX_NODES 1024 // Maximum number of nodes in the pool +#define MAX_NODES 4096 // Maximum number of nodes in the pool typedef uint64_t (*binary_tree_get_priority_fn_t)(void *data); typedef uint64_t (*binary_tree_get_execution_cost_fn_t)(void *data, int thread_id); diff --git a/runtime/include/local_runqueue.h b/runtime/include/local_runqueue.h index fc035a8cf..09deaa7c4 100644 --- a/runtime/include/local_runqueue.h +++ b/runtime/include/local_runqueue.h @@ -13,6 +13,7 @@ typedef void (*local_runqueue_delete_fn_t)(struct sandbox *sandbox); typedef struct sandbox *(*local_runqueue_get_next_fn_t)(); typedef int (*local_runqueue_get_height_fn_t)(); typedef int (*local_runqueue_get_length_fn_t)(); +typedef int (*local_runqueue_get_length_fn_t_idx)(int index); struct local_runqueue_config { local_runqueue_add_fn_t add_fn; @@ -23,6 +24,7 @@ struct local_runqueue_config { local_runqueue_get_next_fn_t get_next_fn; local_runqueue_get_height_fn_t get_height_fn; local_runqueue_get_length_fn_t get_length_fn; + local_runqueue_get_length_fn_t_idx get_length_fn_idx; }; void local_runqueue_add(struct sandbox *); @@ -34,3 +36,4 @@ struct sandbox *local_runqueue_get_next(); void local_runqueue_initialize(struct local_runqueue_config *config); int local_runqueue_get_height(); int local_runqueue_get_length(); +int local_runqueue_get_length_index(int index); diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index aa6648b65..d734c85ce 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -552,7 +552,8 @@ scheduler_cooperative_sched(bool add_to_cleanup_queue) next_sandbox->context_switch_to = 2; scheduler_cooperative_switch_to(exiting_context, next_sandbox); } else { - if (dispatcher == DISPATCHER_DARC || dispatcher == DISPATCHER_SHINJUKU) { + //if (dispatcher == DISPATCHER_DARC || dispatcher == DISPATCHER_SHINJUKU) { + if (dispatcher == DISPATCHER_DARC) { int virtual_id = global_worker_thread_idx - dispatcher_id * runtime_worker_group_size; atomic_fetch_or(&free_workers[dispatcher_id], 1 << virtual_id); } diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 9dba33156..206e49c58 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -19,14 +19,19 @@ #include "request_typed_deque.h" #include "local_preempted_fifo_queue.h" +#define INTERRUPT_INTERVAL 50 #define BASE_SERVICE_TIME 10 #define LOSS_PERCENTAGE 0.11 +thread_local int next_loop_start_index = -1; +thread_local uint64_t total_requests = 0; uint64_t base_simulated_service_time = 0; uint64_t shinjuku_interrupt_interval = 0; thread_local uint32_t global_queue_length = 0; thread_local uint32_t max_queue_length = 0; +uint32_t worker_old_sandbox[1024] = {0}; +uint32_t worker_new_sandbox[1024] = {0}; struct perf_window * worker_perf_windows[1024]; struct priority_queue * worker_queues[1024]; struct binary_tree * worker_binary_trees[1024]; @@ -485,6 +490,7 @@ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, return; } + total_requests++; /* Allocate a Sandbox */ //session->state = HTTP_SESSION_EXECUTING; struct sandbox *sandbox = sandbox_alloc(route->module, NULL, route, tenant, work_admitted, req_handle, dispatcher_thread_idx); @@ -520,14 +526,20 @@ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, int candidate_thread_with_interrupt = -1; /* This thread can server the request immediately by interrupting the current one */ - for (uint32_t i = worker_start_id; i < worker_end_id; i++) { + next_loop_start_index++; + if (next_loop_start_index == runtime_worker_group_size) { + next_loop_start_index = 0; + } + + for (uint32_t i = next_loop_start_index; i < next_loop_start_index + runtime_worker_group_size; ++i) { + int true_idx = i % runtime_worker_group_size; bool need_interrupt; - uint64_t waiting_serving_time = local_runqueue_try_add_index(i, sandbox, &need_interrupt); + uint64_t waiting_serving_time = local_runqueue_try_add_index(worker_list[true_idx], sandbox, &need_interrupt); /* The local queue is empty, the worker is idle, can be served this request immediately * without interrupting */ if (waiting_serving_time == 0 && need_interrupt == false) { - local_runqueue_add_index(i, sandbox); + local_runqueue_add_index(worker_list[true_idx], sandbox); return; } else if (waiting_serving_time == 0 && need_interrupt == true) {//The worker can serve the request immediately // by interrupting the current one @@ -537,11 +549,11 @@ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, if (candidate_thread_with_interrupt != -1) { continue; } else { - candidate_thread_with_interrupt = i; + candidate_thread_with_interrupt = worker_list[true_idx]; } } else if (min_waiting_serving_time > waiting_serving_time) { min_waiting_serving_time = waiting_serving_time; - thread_id = i; + thread_id = worker_list[true_idx]; } } @@ -591,6 +603,7 @@ void darc_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t s return; } + total_requests++; /* Allocate a Sandbox */ //session->state = HTTP_SESSION_EXECUTING; struct sandbox *sandbox = sandbox_alloc(route->module, NULL, route, tenant, work_admitted, req_handle, dispatcher_thread_idx); @@ -653,6 +666,7 @@ void shinjuku_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size return; } + total_requests++; /* Allocate a Sandbox */ //session->state = HTTP_SESSION_EXECUTING; struct sandbox *sandbox = sandbox_alloc(route->module, NULL, route, tenant, work_admitted, req_handle, dispatcher_thread_idx); @@ -846,38 +860,47 @@ void shinjuku_dispatch_different_core() { } void shinjuku_dispatch() { - for (uint32_t i = 0; i < runtime_worker_group_size; ++i) { + next_loop_start_index++; + if (next_loop_start_index == runtime_worker_group_size) { + next_loop_start_index = 0; + } + + for (uint32_t i = next_loop_start_index; i < next_loop_start_index + runtime_worker_group_size; ++i) { + int true_idx = i % runtime_worker_group_size; /* move all preempted sandboxes from worker to dispatcher's typed queue */ - struct request_fifo_queue * preempted_queue = worker_preempted_queue[worker_list[i]]; + struct request_fifo_queue * preempted_queue = worker_preempted_queue[worker_list[true_idx]]; assert(preempted_queue != NULL); uint64_t tsc = 0; - struct sandbox * preempted_sandbox = pop_worker_preempted_queue(worker_list[i], preempted_queue, &tsc); + struct sandbox * preempted_sandbox = pop_worker_preempted_queue(worker_list[true_idx], preempted_queue, &tsc); while(preempted_sandbox != NULL) { uint8_t req_type = preempted_sandbox->route->request_type; insertfront(request_type_deque[req_type - 1], preempted_sandbox, tsc); global_queue_length++; //insertrear(request_type_deque[req_type - 1], preempted_sandbox, tsc); - preempted_sandbox = pop_worker_preempted_queue(worker_list[i], preempted_queue, &tsc); + preempted_sandbox = pop_worker_preempted_queue(worker_list[true_idx], preempted_queue, &tsc); } /* core is idle */ - if ((1 << i) & free_workers[dispatcher_thread_idx]) { + //if ((1 << i) & free_workers[dispatcher_thread_idx]) { + if (local_runqueue_get_length_index(worker_list[true_idx]) == 0) { struct sandbox *sandbox = shinjuku_select_sandbox(); if (!sandbox) return; // queue is empty while (sandbox->global_worker_thread_idx != -1) { sandbox->start_ts = __getcycles(); local_runqueue_add_index(sandbox->global_worker_thread_idx, sandbox); global_queue_length--; + worker_old_sandbox[worker_list[true_idx]]++; sandbox = shinjuku_select_sandbox(); if (!sandbox) return; } sandbox->start_ts = __getcycles(); - local_runqueue_add_index(worker_list[i], sandbox); + local_runqueue_add_index(worker_list[true_idx], sandbox); global_queue_length--; - atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << i); + worker_new_sandbox[worker_list[true_idx]]++; + atomic_fetch_xor(&free_workers[dispatcher_thread_idx], 1 << true_idx); } else { // core is busy //check if the current sandbox is running longer than the specified time duration - struct sandbox *current = current_sandboxes[worker_list[i]]; + struct sandbox *current = current_sandboxes[worker_list[true_idx]]; if (!current) continue; //In case that worker thread hasn't call current_sandbox_set to set the current sandbox uint64_t elapsed_cycles = (__getcycles() - current->start_ts); if (elapsed_cycles >= shinjuku_interrupt_interval && (current->state == SANDBOX_RUNNING_USER || current->state == SANDBOX_RUNNING_SYS)) { @@ -888,16 +911,18 @@ void shinjuku_dispatch() { sandbox->start_ts = __getcycles(); local_runqueue_add_index(sandbox->global_worker_thread_idx, sandbox); global_queue_length--; + worker_old_sandbox[worker_list[true_idx]]++; sandbox = shinjuku_select_sandbox(); if (!sandbox) return; } //preempt the current sandbox and put it back the typed queue, select a new one to send to it sandbox->start_ts = __getcycles(); - local_runqueue_add_index(worker_list[i], sandbox); + local_runqueue_add_index(worker_list[true_idx], sandbox); global_queue_length--; + worker_new_sandbox[worker_list[true_idx]]++; //preempt worker - preempt_worker(worker_list[i]); + preempt_worker(worker_list[true_idx]); dispatcher_try_interrupts++; } } @@ -922,7 +947,7 @@ void * listener_thread_main(void *dummy) { is_listener = true; - shinjuku_interrupt_interval = 100 * runtime_processor_speed_MHz; + shinjuku_interrupt_interval = INTERRUPT_INTERVAL * runtime_processor_speed_MHz; base_simulated_service_time = BASE_SERVICE_TIME * runtime_processor_speed_MHz; /* Unmask SIGINT signals */ diff --git a/runtime/src/local_runqueue.c b/runtime/src/local_runqueue.c index a8ab8f524..b8a5694f9 100644 --- a/runtime/src/local_runqueue.c +++ b/runtime/src/local_runqueue.c @@ -90,6 +90,9 @@ int local_runqueue_get_height() { int local_runqueue_get_length() { return local_runqueue.get_length_fn(); } +int local_runqueue_get_length_index(int index) { + return local_runqueue.get_length_fn_idx(index); +} /** * Get next sandbox from run queue, where next is defined by * @returns sandbox (or NULL?) diff --git a/runtime/src/local_runqueue_binary_tree.c b/runtime/src/local_runqueue_binary_tree.c index 985c08445..d69193d71 100644 --- a/runtime/src/local_runqueue_binary_tree.c +++ b/runtime/src/local_runqueue_binary_tree.c @@ -13,8 +13,8 @@ #include "sandbox_functions.h" #include "runtime.h" -uint32_t local_queue_length[1024] = {0}; -uint32_t max_local_queue_length[1024] = {0}; +extern _Atomic uint32_t local_queue_length[1024]; +extern uint32_t max_local_queue_length[1024]; extern bool runtime_exponential_service_time_simulation_enabled; extern thread_local int global_worker_thread_idx; extern struct sandbox* current_sandboxes[1024]; @@ -61,7 +61,7 @@ local_runqueue_binary_tree_add_index(int index, struct sandbox *sandbox) binary_tree->root = insert(binary_tree, binary_tree->root, sandbox); lock_unlock(&binary_tree->lock, &node_lock); - local_queue_length[index]++; + atomic_fetch_add(&local_queue_length[index], 1); if (local_queue_length[index] > max_local_queue_length[index]) { max_local_queue_length[index] = local_queue_length[index]; } @@ -110,7 +110,7 @@ local_runqueue_binary_tree_delete(struct sandbox *sandbox) sandbox->id, sandbox->state, local_runqueue_binary_tree); } - local_queue_length[global_worker_thread_idx]--; + atomic_fetch_sub(&local_queue_length[global_worker_thread_idx], 1); } diff --git a/runtime/src/local_runqueue_circular_queue.c b/runtime/src/local_runqueue_circular_queue.c index 2ac410242..914874c4d 100644 --- a/runtime/src/local_runqueue_circular_queue.c +++ b/runtime/src/local_runqueue_circular_queue.c @@ -8,7 +8,7 @@ #include "likely.h" #include "request_fifo_queue.h" -extern uint32_t local_queue_length[1024]; +extern _Atomic uint32_t local_queue_length[1024]; extern uint32_t max_local_queue_length[1024]; extern thread_local int global_worker_thread_idx; extern struct request_fifo_queue * worker_circular_queue[1024]; @@ -46,7 +46,7 @@ local_runqueue_circular_queue_add_index(int index, struct sandbox *sandbox){ local_runqueue->rqueue[head & (RQUEUE_QUEUE_LEN - 1)] = sandbox; local_runqueue->rqueue_head++; } - local_queue_length[index]++; + atomic_fetch_add(&local_queue_length[index], 1); if (local_queue_length[index] > max_local_queue_length[index]) { max_local_queue_length[index] = local_queue_length[index]; } @@ -70,7 +70,7 @@ local_runqueue_circular_queue_delete(struct sandbox *sandbox) { = NULL; local_runqueue_circular_queue->rqueue_tail++; - local_queue_length[global_worker_thread_idx]--; + atomic_fetch_sub(&local_queue_length[global_worker_thread_idx], 1); } /* Called by worker thread to get item from the tail of the queue */ @@ -92,6 +92,13 @@ local_runqueue_circular_queue_get_length() { return (local_runqueue_circular_queue->rqueue_head - local_runqueue_circular_queue->rqueue_tail); } +int +local_runqueue_circular_queue_get_length_index(int index) { + struct request_fifo_queue * local_runqueue = worker_circular_queue[index]; + assert(local_runqueue != NULL); + return (local_runqueue->rqueue_head - local_runqueue->rqueue_tail); +} + /** * Registers the PS variant with the polymorphic interface */ @@ -116,7 +123,8 @@ local_runqueue_circular_queue_initialize() .is_empty_fn = local_runqueue_circular_queue_is_empty, .delete_fn = local_runqueue_circular_queue_delete, .get_next_fn = local_runqueue_circular_queue_get_next, - .get_length_fn = local_runqueue_circular_queue_get_length + .get_length_fn = local_runqueue_circular_queue_get_length, + .get_length_fn_idx = local_runqueue_circular_queue_get_length_index }; local_runqueue_initialize(&config); diff --git a/runtime/src/sandbox.c b/runtime/src/sandbox.c index 76b44bfe7..a6b377093 100644 --- a/runtime/src/sandbox.c +++ b/runtime/src/sandbox.c @@ -282,7 +282,7 @@ sandbox_free(struct sandbox *sandbox, uint64_t *ret) } void sandbox_send_response(struct sandbox *sandbox, uint8_t response_code) { - if (runtime_exponential_service_time_simulation_enabled && response_code == 0) { + if (response_code == 0) { uint64_t pure_cpu_time = (sandbox->duration_of_state[SANDBOX_RUNNING_SYS] + sandbox->duration_of_state[SANDBOX_RUNNING_USER]) / runtime_processor_speed_MHz; char tmp_buf[20] = {0}; diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index 6a2afd335..ccf4bfe40 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -27,6 +27,9 @@ #include "memlogging.h" #include "tenant_functions.h" +extern uint32_t worker_old_sandbox[1024]; +extern uint32_t worker_new_sandbox[1024]; +extern thread_local uint64_t total_requests; extern uint32_t max_local_queue_length[1024]; extern thread_local uint32_t max_queue_length; extern thread_local uint32_t dispatcher_try_interrupts; @@ -245,23 +248,26 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void } case SIGINT: { /* Stop the alarm timer first */ software_interrupt_disarm_timer(); sigint_propagate_workers_listener(signal_info); + time_t t_end = time(NULL); + double seconds = difftime(t_end, t_start); if (is_listener) { pthread_stop = true; - printf("try preempts:%u max global queue %u\n", dispatcher_try_interrupts, max_queue_length); + double arriving_rate = total_requests / seconds; + printf("try preempts:%u max global queue %u arriving rate %f\n", dispatcher_try_interrupts, max_queue_length, arriving_rate); break; } /* calculate the throughput */ - time_t t_end = time(NULL); - double seconds = difftime(t_end, t_start); double throughput = atomic_load(&sandbox_state_totals[SANDBOX_COMPLETE]) / seconds; uint32_t total_sandboxes_error = atomic_load(&sandbox_state_totals[SANDBOX_ERROR]); - mem_log("throughput %f tid(%d) error request %u complete requests %u total request %u total_local_requests %u interrupts %u p-interrupts %u\n", + mem_log("throughput %f tid(%d) error request %u complete requests %u total request %u total_local_requests %u interrupts %u p-interrupts %u max local queue %u\n", throughput, global_worker_thread_idx, total_sandboxes_error, atomic_load(&sandbox_state_totals[SANDBOX_COMPLETE]), - atomic_load(&sandbox_state_totals[SANDBOX_ALLOCATED]), total_local_requests, interrupts, preemptable_interrupts); + atomic_load(&sandbox_state_totals[SANDBOX_ALLOCATED]), total_local_requests, interrupts, preemptable_interrupts, + max_local_queue_length[global_worker_thread_idx]); dump_log_to_file(); - printf("max local queue %u\n", max_local_queue_length[global_worker_thread_idx]); + printf("id %d max local queue %u new %u old %u\n", global_worker_thread_idx, max_local_queue_length[global_worker_thread_idx], + worker_new_sandbox[global_worker_thread_idx], worker_old_sandbox[global_worker_thread_idx]); pthread_stop = true; break; } diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c index 3c1cfddcc..af54b15ba 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c @@ -24,6 +24,8 @@ * Worker Thread State * **************************/ +_Atomic uint32_t local_queue_length[1024] = {0}; +uint32_t max_local_queue_length[1024] = {0}; extern struct perf_window * worker_perf_windows[1024]; thread_local struct perf_window perf_window_per_thread[1024]; struct sandbox* current_sandboxes[1024] = { NULL }; @@ -73,6 +75,7 @@ worker_thread_main(void *argument) /* Index was passed via argument */ global_worker_thread_idx = *(int *)argument; + atomic_init(&local_queue_length[global_worker_thread_idx], 0); /* Set dispatcher id for this worker */ dispatcher_id = global_worker_thread_idx / runtime_worker_group_size; From f6aa38667ae5eb558a5363f6cd936dd875f61efa Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 7 Nov 2023 16:14:53 -0700 Subject: [PATCH 080/198] 1. choose the worker with the minimum total amount of work if more than one can be interrupted. 2. Fix bug for simulating expontential service time distribution: use the sandbox->estimated_cost instead of the perf_window when calculate the total amount of work --- runtime/include/binary_search_tree.h | 26 ++++++++++++++++++- runtime/include/local_runqueue.h | 13 ++++++++++ runtime/include/local_runqueue_minheap.h | 22 ---------------- runtime/include/sandbox_functions.h | 16 ++++++++---- runtime/src/listener_thread.c | 32 +++++++++++++++++++++--- runtime/src/local_runqueue.c | 22 ++++++++++++++++ runtime/src/local_runqueue_binary_tree.c | 19 ++++++++++++-- runtime/src/software_interrupt.c | 5 +++- 8 files changed, 121 insertions(+), 34 deletions(-) diff --git a/runtime/include/binary_search_tree.h b/runtime/include/binary_search_tree.h index 4265cd819..cb1ed47dc 100644 --- a/runtime/include/binary_search_tree.h +++ b/runtime/include/binary_search_tree.h @@ -2,6 +2,7 @@ #include #include +#include "memlogging.h" #include "lock.h" #define MAX_NODES 4096 // Maximum number of nodes in the pool @@ -88,7 +89,7 @@ struct TreeNode* newNode(struct binary_tree *binary_tree, void *data) { void getAvailableCapacity(struct binary_tree *binary_tree) { - assert(binary_tree != NULL); + assert(binary_tree != NULL); int size = 0; struct TreeNode* start = binary_tree->nodePool.head; @@ -100,6 +101,29 @@ void getAvailableCapacity(struct binary_tree *binary_tree) { printf("available capacity of the queue is %d\n", size); } +void print_in_order(struct TreeNode* node) { + if (node != NULL) { + // Recursively traverse the left subtree + print_in_order(node->left); + + // Print the data in the current node + if (node->data) { + mem_log("%lu(%lu) ", ((struct sandbox *)node->data)->absolute_deadline, ((struct sandbox *)node->data)->estimated_cost); + } + + // Recursively traverse the right subtree + print_in_order(node->right); + } +} + +// Function to print the items in the binary search tree in order +void print_tree_in_order(struct binary_tree* bst) { + if (bst != NULL) { + print_in_order(bst->root); + mem_log("\n"); + } +} + // Return a node to the pool void deleteNode(struct binary_tree *binary_tree, struct TreeNode* node) { diff --git a/runtime/include/local_runqueue.h b/runtime/include/local_runqueue.h index 09deaa7c4..e9f52f702 100644 --- a/runtime/include/local_runqueue.h +++ b/runtime/include/local_runqueue.h @@ -14,6 +14,7 @@ typedef struct sandbox *(*local_runqueue_get_next_fn_t)(); typedef int (*local_runqueue_get_height_fn_t)(); typedef int (*local_runqueue_get_length_fn_t)(); typedef int (*local_runqueue_get_length_fn_t_idx)(int index); +typedef void (*local_runqueue_print_in_order_fn_t_idx)(int index); struct local_runqueue_config { local_runqueue_add_fn_t add_fn; @@ -25,6 +26,7 @@ struct local_runqueue_config { local_runqueue_get_height_fn_t get_height_fn; local_runqueue_get_length_fn_t get_length_fn; local_runqueue_get_length_fn_t_idx get_length_fn_idx; + local_runqueue_print_in_order_fn_t_idx print_in_order_fn_idx; }; void local_runqueue_add(struct sandbox *); @@ -37,3 +39,14 @@ void local_runqueue_initialize(struct local_runqueue_config *config); int local_runqueue_get_height(); int local_runqueue_get_length(); int local_runqueue_get_length_index(int index); +void local_runqueue_print_in_order(int index); + +void +worker_queuing_cost_initialize(); + +void +worker_queuing_cost_increment(int index, uint64_t cost); + +void +worker_queuing_cost_decrement(int index, uint64_t cost); + diff --git a/runtime/include/local_runqueue_minheap.h b/runtime/include/local_runqueue_minheap.h index 20f8cdeb0..e8ba9187d 100644 --- a/runtime/include/local_runqueue_minheap.h +++ b/runtime/include/local_runqueue_minheap.h @@ -1,25 +1,3 @@ #pragma once -extern _Atomic uint64_t worker_queuing_cost[1024]; - -static inline void -worker_queuing_cost_initialize() -{ - for (int i = 0; i < 1024; i++) atomic_init(&worker_queuing_cost[i], 0); -} - -static inline void -worker_queuing_cost_increment(int index, uint64_t cost) -{ - atomic_fetch_add(&worker_queuing_cost[index], cost); -} - -static inline void -worker_queuing_cost_decrement(int index, uint64_t cost) -{ - assert(index >= 0 && index < 1024); - atomic_fetch_sub(&worker_queuing_cost[index], cost); - assert(worker_queuing_cost[index] >= 0); -} - void local_runqueue_minheap_initialize(); diff --git a/runtime/include/sandbox_functions.h b/runtime/include/sandbox_functions.h index 7721bbdc1..808ee38c3 100644 --- a/runtime/include/sandbox_functions.h +++ b/runtime/include/sandbox_functions.h @@ -12,6 +12,7 @@ * Public API * **************************/ +extern bool runtime_exponential_service_time_simulation_enabled; extern struct perf_window * worker_perf_windows[1024]; struct sandbox *sandbox_alloc(struct module *module, struct http_session *session, struct route *route, struct tenant *tenant, uint64_t admissions_estimate, void *req_handle, @@ -60,13 +61,18 @@ sandbox_get_execution_cost(void *element, int thread_id) { assert(element != NULL); struct sandbox *sandbox = (struct sandbox *)element; - uint32_t uid = sandbox->route->admissions_info.uid; - return perf_window_get_percentile(&worker_perf_windows[thread_id][uid], - sandbox->route->admissions_info.percentile, - sandbox->route->admissions_info.control_index); + if (runtime_exponential_service_time_simulation_enabled) { + assert(sandbox->estimated_cost != 0); + return sandbox->estimated_cost; + } else { + uint32_t uid = sandbox->route->admissions_info.uid; + return perf_window_get_percentile(&worker_perf_windows[thread_id][uid], + sandbox->route->admissions_info.percentile, + sandbox->route->admissions_info.control_index); - + } } + static inline void sandbox_process_scheduler_updates(struct sandbox *sandbox) { diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 206e49c58..a89c2d7bf 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -39,6 +39,7 @@ struct request_fifo_queue * worker_circular_queue[1024]; struct ps_list_head * worker_lists[1024]; struct request_fifo_queue * worker_preempted_queue[1024]; +extern FILE *sandbox_perf_log; extern bool runtime_exponential_service_time_simulation_enabled; extern _Atomic uint64_t worker_queuing_cost[1024]; //struct sandbox *urgent_request[1024] = { NULL }; @@ -531,23 +532,32 @@ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, next_loop_start_index = 0; } + //uint64_t waiting_times[3] = {0}; for (uint32_t i = next_loop_start_index; i < next_loop_start_index + runtime_worker_group_size; ++i) { int true_idx = i % runtime_worker_group_size; bool need_interrupt; uint64_t waiting_serving_time = local_runqueue_try_add_index(worker_list[true_idx], sandbox, &need_interrupt); + /*waiting_times[true_idx] = waiting_serving_time; + if (waiting_times[true_idx] != 0) { + mem_log("listener %d %d queue:\n", dispatcher_thread_idx, worker_list[true_idx]); + local_runqueue_print_in_order(worker_list[true_idx]); + }*/ /* The local queue is empty, the worker is idle, can be served this request immediately * without interrupting */ if (waiting_serving_time == 0 && need_interrupt == false) { local_runqueue_add_index(worker_list[true_idx], sandbox); + //mem_log("listener %d %d is idle, choose it\n", dispatcher_thread_idx, worker_list[true_idx]); return; } else if (waiting_serving_time == 0 && need_interrupt == true) {//The worker can serve the request immediately // by interrupting the current one - /* We already have a candidate thread, continue to find a - * better thread without needing interrupt + /* We already have a candidate worker, continue to find a + * better worker without needing interrupt or a worker that has the minimum total amount of work */ if (candidate_thread_with_interrupt != -1) { - continue; + if (worker_queuing_cost[worker_list[true_idx]] < worker_queuing_cost[candidate_thread_with_interrupt]) { + candidate_thread_with_interrupt = worker_list[true_idx]; + } } else { candidate_thread_with_interrupt = worker_list[true_idx]; } @@ -560,10 +570,23 @@ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, if (candidate_thread_with_interrupt != -1) { //urgent_request[candidate_thread_with_interrupt] = sandbox; local_runqueue_add_index(candidate_thread_with_interrupt, sandbox); + //mem_log("listener %d %d can be interrupted immediately for req deadline %lu\n", dispatcher_thread_idx, + // candidate_thread_with_interrupt, sandbox->absolute_deadline); + preempt_worker(candidate_thread_with_interrupt); dispatcher_try_interrupts++; } else { local_runqueue_add_index(thread_id, sandbox); + /*mem_log("listener %d %d has the min waiting time for req deadline %lu. 0:%lu 1:%lu 2:%lu\n", + dispatcher_thread_idx, thread_id, sandbox->absolute_deadline, waiting_times[0], waiting_times[1], waiting_times[2]); + local_runqueue_print_in_order(thread_id); + int fake_id = thread_id % runtime_worker_group_size; + for (int i = 0; i < runtime_worker_group_size; i++) { + if (fake_id != i) { + mem_log("listener %d %d queue:\n", dispatcher_thread_idx, worker_list[i]); + local_runqueue_print_in_order(worker_list[i]); + } + }*/ } } @@ -950,6 +973,9 @@ listener_thread_main(void *dummy) shinjuku_interrupt_interval = INTERRUPT_INTERVAL * runtime_processor_speed_MHz; base_simulated_service_time = BASE_SERVICE_TIME * runtime_processor_speed_MHz; + /* Initialize memory logging, set 1M memory for logging */ + mem_log_init2(1024*1024*1024, sandbox_perf_log); + /* Unmask SIGINT signals */ software_interrupt_unmask_signal(SIGINT); diff --git a/runtime/src/local_runqueue.c b/runtime/src/local_runqueue.c index b8a5694f9..115cb9480 100644 --- a/runtime/src/local_runqueue.c +++ b/runtime/src/local_runqueue.c @@ -6,6 +6,7 @@ #include "local_runqueue.h" +extern _Atomic uint64_t worker_queuing_cost[1024]; thread_local uint32_t total_local_requests = 0; static struct local_runqueue_config local_runqueue; @@ -103,3 +104,24 @@ local_runqueue_get_next() assert(local_runqueue.get_next_fn != NULL); return local_runqueue.get_next_fn(); }; + +void +worker_queuing_cost_initialize() +{ + for (int i = 0; i < 1024; i++) atomic_init(&worker_queuing_cost[i], 0); +} + +void +worker_queuing_cost_increment(int index, uint64_t cost) +{ + atomic_fetch_add(&worker_queuing_cost[index], cost); +} + +void +worker_queuing_cost_decrement(int index, uint64_t cost) +{ + assert(index >= 0 && index < 1024); + atomic_fetch_sub(&worker_queuing_cost[index], cost); + assert(worker_queuing_cost[index] >= 0); +} + diff --git a/runtime/src/local_runqueue_binary_tree.c b/runtime/src/local_runqueue_binary_tree.c index d69193d71..39533d98b 100644 --- a/runtime/src/local_runqueue_binary_tree.c +++ b/runtime/src/local_runqueue_binary_tree.c @@ -12,7 +12,9 @@ #include "binary_search_tree.h" #include "sandbox_functions.h" #include "runtime.h" +#include "memlogging.h" +extern thread_local uint8_t dispatcher_thread_idx; extern _Atomic uint32_t local_queue_length[1024]; extern uint32_t max_local_queue_length[1024]; extern bool runtime_exponential_service_time_simulation_enabled; @@ -64,6 +66,11 @@ local_runqueue_binary_tree_add_index(int index, struct sandbox *sandbox) atomic_fetch_add(&local_queue_length[index], 1); if (local_queue_length[index] > max_local_queue_length[index]) { max_local_queue_length[index] = local_queue_length[index]; + /*mem_log("listener %d 1:%u 2:%u 3:%u 4:%u 5:%u 6:%u 7:%u 8:%u 9:%u\n", dispatcher_thread_idx, max_local_queue_length[0], + max_local_queue_length[1],max_local_queue_length[2], + max_local_queue_length[3],max_local_queue_length[4], max_local_queue_length[5], max_local_queue_length[6], + max_local_queue_length[7], max_local_queue_length[8]); + */ } /* Set estimated exeuction time for the sandbox */ @@ -89,6 +96,7 @@ local_runqueue_binary_tree_add_index(int index, struct sandbox *sandbox) */ sandbox->srsf_stop_running_ts = __getcycles(); sandbox->srsf_remaining_slack = sandbox->relative_deadline - sandbox->estimated_cost; + worker_queuing_cost_increment(index, sandbox->estimated_cost); } /** @@ -111,7 +119,7 @@ local_runqueue_binary_tree_delete(struct sandbox *sandbox) } atomic_fetch_sub(&local_queue_length[global_worker_thread_idx], 1); - + worker_queuing_cost_decrement(global_worker_thread_idx, sandbox->estimated_cost); } /** @@ -174,6 +182,12 @@ int local_runqueue_binary_tree_get_height() { return findHeight(local_runqueue_binary_tree->root); } +void local_runqueue_print_in_order(int index) { + struct binary_tree *binary_tree = worker_binary_trees[index]; + assert(binary_tree != NULL); + print_tree_in_order(binary_tree); +} + /** * Registers the PS variant with the polymorphic interface */ @@ -191,7 +205,8 @@ local_runqueue_binary_tree_initialize() .is_empty_fn = local_runqueue_binary_tree_is_empty, .delete_fn = local_runqueue_binary_tree_delete, .get_next_fn = local_runqueue_binary_tree_get_next, - .get_height_fn = local_runqueue_binary_tree_get_height + .get_height_fn = local_runqueue_binary_tree_get_height, + .print_in_order_fn_idx = local_runqueue_print_in_order }; local_runqueue_initialize(&config); diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index ccf4bfe40..42237252a 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -27,6 +27,7 @@ #include "memlogging.h" #include "tenant_functions.h" +extern thread_local uint8_t dispatcher_thread_idx; extern uint32_t worker_old_sandbox[1024]; extern uint32_t worker_new_sandbox[1024]; extern thread_local uint64_t total_requests; @@ -254,7 +255,9 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void if (is_listener) { pthread_stop = true; double arriving_rate = total_requests / seconds; - printf("try preempts:%u max global queue %u arriving rate %f\n", dispatcher_try_interrupts, max_queue_length, arriving_rate); + printf("%d try preempts:%u max global queue %u arriving rate %f total requests %lu\n", dispatcher_thread_idx, + dispatcher_try_interrupts, max_queue_length, arriving_rate, total_requests); + dump_log_to_file(); break; } From cd430ef5bb15687a19a3b90d25020d01d5f35ac9 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 8 Nov 2023 11:00:56 -0700 Subject: [PATCH 081/198] modify debug.sh --- runtime/tests/debug.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/runtime/tests/debug.sh b/runtime/tests/debug.sh index 1dd5efd21..3e87c2bbd 100755 --- a/runtime/tests/debug.sh +++ b/runtime/tests/debug.sh @@ -11,6 +11,7 @@ declare project_path="$( path=`pwd` echo $project_path cd $project_path/runtime/bin +export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=true export SLEDGE_DISABLE_PREEMPTION=true export SLEDGE_SANDBOX_PERF_LOG=$path/srsf.log export SLEDGE_NWORKERS=9 @@ -18,7 +19,8 @@ export SLEDGE_FIRST_WORKER_COREID=4 export SLEDGE_NLISTENERS=3 export SLEDGE_WORKER_GROUP_SIZE=3 #export SLEDGE_DISPATCHER=DARC -export SLEDGE_DISPATCHER=SHINJUKU +export SLEDGE_DISPATCHER=EDF_INTERRUPT +#export SLEDGE_DISPATCHER=SHINJUKU export LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" #gdb --eval-command="handle SIGUSR1 nostop" \ # --eval-command="set pagination off" \ From a3a3fe59fb973ec521522564eab0269b33c5f8b1 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 20 Dec 2023 12:45:06 -0700 Subject: [PATCH 082/198] implement partial code for autoscaling: each worker will keep idle if queue is empty. Listener thread will wake up workers when adding new requests to its queue. This was implemented by condition variable. 2. Set main thread cpu affinity to core #1(DPDK control threads also pin to core #1). Listener threads from core #2 --- runtime/include/listener_thread.h | 2 +- runtime/include/local_runqueue.h | 4 ++ runtime/include/scheduler.h | 10 +++- runtime/src/listener_thread.c | 10 ++-- runtime/src/local_runqueue.c | 28 +++++++++++- runtime/src/local_runqueue_binary_tree.c | 15 ++++++ runtime/src/main.c | 58 +++++++++++++++++++++++- runtime/src/software_interrupt.c | 2 + runtime/src/worker_thread.c | 9 ++++ 9 files changed, 129 insertions(+), 9 deletions(-) diff --git a/runtime/include/listener_thread.h b/runtime/include/listener_thread.h index 4206699ed..b4886a959 100644 --- a/runtime/include/listener_thread.h +++ b/runtime/include/listener_thread.h @@ -6,7 +6,7 @@ #include "http_session.h" #include "module.h" -#define LISTENER_THREAD_START_CORE_ID 1 +#define LISTENER_THREAD_START_CORE_ID 2 #define DIPATCH_ROUNTE_ERROR "Did not match any routes" #define WORK_ADMITTED_ERROR "Work is not admitted" #define SANDBOX_ALLOCATION_ERROR "Failed to allocate a sandbox" diff --git a/runtime/include/local_runqueue.h b/runtime/include/local_runqueue.h index e9f52f702..5992b8a42 100644 --- a/runtime/include/local_runqueue.h +++ b/runtime/include/local_runqueue.h @@ -9,6 +9,7 @@ typedef void (*local_runqueue_add_fn_t)(struct sandbox *); typedef void (*local_runqueue_add_fn_t_idx)(int index, struct sandbox *); typedef uint64_t (*local_runqueue_try_add_fn_t_idx)(int index, struct sandbox *, bool *need_interrupt); typedef bool (*local_runqueue_is_empty_fn_t)(void); +typedef bool (*local_runqueue_is_empty_fn_t_idx)(int index); typedef void (*local_runqueue_delete_fn_t)(struct sandbox *sandbox); typedef struct sandbox *(*local_runqueue_get_next_fn_t)(); typedef int (*local_runqueue_get_height_fn_t)(); @@ -21,6 +22,7 @@ struct local_runqueue_config { local_runqueue_add_fn_t_idx add_fn_idx; local_runqueue_try_add_fn_t_idx try_add_fn_idx; local_runqueue_is_empty_fn_t is_empty_fn; + local_runqueue_is_empty_fn_t_idx is_empty_fn_idx; local_runqueue_delete_fn_t delete_fn; local_runqueue_get_next_fn_t get_next_fn; local_runqueue_get_height_fn_t get_height_fn; @@ -34,6 +36,7 @@ void local_runqueue_add_index(int index, struct sandbox *); uint64_t local_runqueue_try_add_index(int index, struct sandbox *, bool *need_interrupt); void local_runqueue_delete(struct sandbox *); bool local_runqueue_is_empty(); +bool local_runqueue_is_empty_index(int index); struct sandbox *local_runqueue_get_next(); void local_runqueue_initialize(struct local_runqueue_config *config); int local_runqueue_get_height(); @@ -50,3 +53,4 @@ worker_queuing_cost_increment(int index, uint64_t cost); void worker_queuing_cost_decrement(int index, uint64_t cost); +void wakeup_worker(int index); diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index d734c85ce..8d0c3fccd 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -35,6 +35,8 @@ extern thread_local bool pthread_stop; extern uint32_t runtime_worker_group_size; extern _Atomic uint32_t free_workers[10]; extern thread_local int dispatcher_id; +extern pthread_mutex_t mutexs[1024]; +extern pthread_cond_t conds[1024]; /** * This scheduler provides for cooperative and preemptive multitasking in a OS process's userspace. * @@ -481,8 +483,12 @@ scheduler_idle_loop() ret[3] += ret_inner[3]; ret[4] += ret_inner[4]; } - /* Improve the performance of spin-wait loops (works only if preemptions enabled) */ - if (runtime_worker_spinloop_pause_enabled) pause(); + /* If queue is empty, then sleep to wait for the condition variable */ + if (next_sandbox == NULL) { + pthread_mutex_lock(&mutexs[global_worker_thread_idx]); + pthread_cond_wait(&conds[global_worker_thread_idx], &mutexs[global_worker_thread_idx]); + pthread_mutex_unlock(&mutexs[global_worker_thread_idx]); + } } } diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index a89c2d7bf..1c17aedd7 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -30,13 +30,15 @@ uint64_t shinjuku_interrupt_interval = 0; thread_local uint32_t global_queue_length = 0; thread_local uint32_t max_queue_length = 0; +pthread_mutex_t mutexs[1024]; +pthread_cond_t conds[1024]; + uint32_t worker_old_sandbox[1024] = {0}; uint32_t worker_new_sandbox[1024] = {0}; struct perf_window * worker_perf_windows[1024]; struct priority_queue * worker_queues[1024]; struct binary_tree * worker_binary_trees[1024]; struct request_fifo_queue * worker_circular_queue[1024]; -struct ps_list_head * worker_lists[1024]; struct request_fifo_queue * worker_preempted_queue[1024]; extern FILE *sandbox_perf_log; @@ -107,6 +109,7 @@ listener_thread_initialize(uint8_t thread_id) CPU_ZERO(&cs); CPU_SET(LISTENER_THREAD_START_CORE_ID + thread_id, &cs); + printf("cpu affinity core for listener is %d\n", LISTENER_THREAD_START_CORE_ID + thread_id); /* Setup epoll */ listener_thread_epoll_file_descriptor = epoll_create1(0); assert(listener_thread_epoll_file_descriptor >= 0); @@ -115,12 +118,13 @@ listener_thread_initialize(uint8_t thread_id) runtime_listener_threads_argument[thread_id] = thread_id; int ret = pthread_create(&runtime_listener_threads[thread_id], NULL, listener_thread_main, (void *)&runtime_listener_threads_argument[thread_id]); + /* Sleep 1 second to wait for listener_thread_main start up and set DPDK control threads cpu affinity */ + sleep(1); listener_thread_id = runtime_listener_threads[thread_id]; assert(ret == 0); + /* Set listener thread to a different cpu affinity to seperate from DPDK control threads */ ret = pthread_setaffinity_np(listener_thread_id, sizeof(cpu_set_t), &cs); assert(ret == 0); - ret = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cs); - assert(ret == 0); printf("\tListener core thread: %lx\n", listener_thread_id); } diff --git a/runtime/src/local_runqueue.c b/runtime/src/local_runqueue.c index 115cb9480..41263cf24 100644 --- a/runtime/src/local_runqueue.c +++ b/runtime/src/local_runqueue.c @@ -6,6 +6,9 @@ #include "local_runqueue.h" +extern pthread_mutex_t mutexs[1024]; +extern pthread_cond_t conds[1024]; + extern _Atomic uint64_t worker_queuing_cost[1024]; thread_local uint32_t total_local_requests = 0; static struct local_runqueue_config local_runqueue; @@ -42,7 +45,13 @@ local_runqueue_add_index(int index, struct sandbox *sandbox) #ifdef LOG_LOCAL_RUNQUEUE local_runqueue_count++; #endif - return local_runqueue.add_fn_idx(index, sandbox); + /* wakeup worker if it is empty before we add a new request */ + if (local_runqueue_is_empty_index(index)) { + local_runqueue.add_fn_idx(index, sandbox); + wakeup_worker(index); + } else { + local_runqueue.add_fn_idx(index, sandbox); + } } uint64_t @@ -77,6 +86,17 @@ local_runqueue_is_empty() return local_runqueue.is_empty_fn(); } +/** + * Checks if run queue is empty + * @returns true if empty + */ +bool +local_runqueue_is_empty_index(int index) +{ + assert(local_runqueue.is_empty_fn_idx != NULL); + return local_runqueue.is_empty_fn_idx(index); +} + /** * Get height if run queue is a binary search tree */ @@ -125,3 +145,9 @@ worker_queuing_cost_decrement(int index, uint64_t cost) assert(worker_queuing_cost[index] >= 0); } +void +wakeup_worker(int index) { + pthread_mutex_lock(&mutexs[index]); + pthread_cond_signal(&conds[index]); + pthread_mutex_unlock(&mutexs[index]); +} diff --git a/runtime/src/local_runqueue_binary_tree.c b/runtime/src/local_runqueue_binary_tree.c index 39533d98b..a4345d48f 100644 --- a/runtime/src/local_runqueue_binary_tree.c +++ b/runtime/src/local_runqueue_binary_tree.c @@ -36,6 +36,20 @@ local_runqueue_binary_tree_is_empty() return is_empty(local_runqueue_binary_tree); } +/** + * Checks if the run queue is empty + * @returns true if empty. false otherwise + */ +bool +local_runqueue_binary_tree_is_empty_index(int index) +{ + struct binary_tree *binary_tree = worker_binary_trees[index]; + + assert(binary_tree != NULL); + + return is_empty(binary_tree); +} + /** * Adds a sandbox to the run queue * @param sandbox @@ -203,6 +217,7 @@ local_runqueue_binary_tree_initialize() .add_fn_idx = local_runqueue_binary_tree_add_index, .try_add_fn_idx = local_runqueue_binary_tree_try_add_index, .is_empty_fn = local_runqueue_binary_tree_is_empty, + .is_empty_fn_idx = local_runqueue_binary_tree_is_empty_index, .delete_fn = local_runqueue_binary_tree_delete, .get_next_fn = local_runqueue_binary_tree_get_next, .get_height_fn = local_runqueue_binary_tree_get_height, diff --git a/runtime/src/main.c b/runtime/src/main.c index 6d030e1ff..5d49e8c54 100644 --- a/runtime/src/main.c +++ b/runtime/src/main.c @@ -9,6 +9,11 @@ #include #include #include +#include +#include +#include +#include + #ifdef LOG_TO_FILE #include @@ -213,7 +218,7 @@ runtime_process_debug_log_behavior() void runtime_start_runtime_worker_threads() { - printf("Starting %d worker thread(s)\n", runtime_worker_threads_count); + printf("Starting %d worker thread(s) first worker cpu is %d\n", runtime_worker_threads_count, runtime_first_worker_processor); for (int i = 0; i < runtime_worker_threads_count; i++) { /* Pass the value we want the threads to use when indexing into global arrays of per-thread values */ runtime_worker_threads_argument[i] = i; @@ -531,6 +536,41 @@ void listener_threads_initialize() { } } +int getUri(const char *interface, int port, char *uri) { + struct ifreq ifr; + + int sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd == -1) { + perror("socket"); + return -1; + } + + // Set the name of the interface + strncpy(ifr.ifr_name, interface, IFNAMSIZ - 1); + ifr.ifr_name[IFNAMSIZ - 1] = '\0'; + + // Get the IP address + if (ioctl(sockfd, SIOCGIFADDR, &ifr) == -1) { + perror("ioctl"); + close(sockfd); + return -1; + } + + close(sockfd); + + // Convert the IP address to a string + if (inet_ntop(AF_INET, &((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr, uri, INET_ADDRSTRLEN) == NULL) { + perror("inet_ntop"); + return -1; + } + + // Append the port to the IP address in the same buffer + int offset = strlen(uri); + snprintf(uri + offset, INET_ADDRSTRLEN - offset + 5, ":%d", port); + + return 0; +} + int main(int argc, char **argv) { @@ -546,7 +586,14 @@ main(int argc, char **argv) software_interrupt_initialize(); /* eRPC init */ - char *server_uri = "128.110.219.3:31850"; + char server_uri[INET_ADDRSTRLEN + 5]; + + if (getUri("ens1f0np0", 31850, server_uri) == 0) { + printf("URI: %s\n", server_uri); + } else { + printf("Failed to get URI.\n"); + } + erpc_init(server_uri, 0, 0); log_compiletime_config(); @@ -589,6 +636,13 @@ main(int argc, char **argv) runtime_get_listener_count(); runtime_get_worker_group_size(); + /* Set main thread cpu affinity to core #1 */ + cpu_set_t cs; + CPU_ZERO(&cs); + CPU_SET(1, &cs); + int ret = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cs); + assert(ret == 0); + runtime_start_runtime_worker_threads(); software_interrupt_arm_timer(); diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index 42237252a..e3526624a 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -272,6 +272,8 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void printf("id %d max local queue %u new %u old %u\n", global_worker_thread_idx, max_local_queue_length[global_worker_thread_idx], worker_new_sandbox[global_worker_thread_idx], worker_old_sandbox[global_worker_thread_idx]); pthread_stop = true; + /* Wake up worker so it can check if pthread_stop is true, othewise, it will block at condition wait */ + wakeup_worker(global_worker_thread_idx); break; } default: { diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c index af54b15ba..85e907358 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c @@ -24,6 +24,9 @@ * Worker Thread State * **************************/ +extern pthread_mutex_t mutexs[1024]; +extern pthread_cond_t conds[1024]; + _Atomic uint32_t local_queue_length[1024] = {0}; uint32_t max_local_queue_length[1024] = {0}; extern struct perf_window * worker_perf_windows[1024]; @@ -61,6 +64,11 @@ void perf_window_init() { tenant_database_foreach(tenant_perf_window_init, NULL, NULL); } +void condition_variable_init() { + pthread_mutex_init(&mutexs[global_worker_thread_idx], NULL); + pthread_cond_init(&conds[global_worker_thread_idx], NULL); +} + /** * The entry function for sandbox worker threads * Initializes thread-local state, unmasks signals, sets up epoll loop and @@ -89,6 +97,7 @@ worker_thread_main(void *argument) preallocate_memory(); perf_window_init(); + condition_variable_init(); scheduler_runqueue_initialize(); local_preempted_fifo_queue_init(); From ac2bfa0ede805a64309679d068ff7630adc9da0c Mon Sep 17 00:00:00 2001 From: xiaosuGW Date: Thu, 28 Dec 2023 16:28:50 -0700 Subject: [PATCH 083/198] add local_runqueue_circular_queue_is_empty_index for DARC and Shinjuku to support checking empty of a local queue with queue index --- runtime/src/local_runqueue_circular_queue.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/runtime/src/local_runqueue_circular_queue.c b/runtime/src/local_runqueue_circular_queue.c index 914874c4d..bbfa977fa 100644 --- a/runtime/src/local_runqueue_circular_queue.c +++ b/runtime/src/local_runqueue_circular_queue.c @@ -58,6 +58,18 @@ local_runqueue_circular_queue_is_empty() { return (local_runqueue_circular_queue->rqueue_head == local_runqueue_circular_queue->rqueue_tail); } +/** + * Checks if the run queue is empty + * @returns true if empty. false otherwise + */ +bool +local_runqueue_circular_queue_is_empty_index(int index) +{ + struct request_fifo_queue * local_runqueue = worker_circular_queue[index]; + assert(local_runqueue != NULL); + return (local_runqueue->rqueue_head == local_runqueue->rqueue_tail); +} + /* Called by worker thread to delete item from the tail of the queue, the to be deleted sandbox must be in the tail */ void local_runqueue_circular_queue_delete(struct sandbox *sandbox) { @@ -121,6 +133,7 @@ local_runqueue_circular_queue_initialize() struct local_runqueue_config config = { .add_fn = local_runqueue_circular_queue_add, .add_fn_idx = local_runqueue_circular_queue_add_index, .is_empty_fn = local_runqueue_circular_queue_is_empty, + .is_empty_fn_idx = local_runqueue_circular_queue_is_empty_index, .delete_fn = local_runqueue_circular_queue_delete, .get_next_fn = local_runqueue_circular_queue_get_next, .get_length_fn = local_runqueue_circular_queue_get_length, From 94e485e06a72621b845b2474e99a925d63c6cdfe Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 2 Jan 2024 15:25:08 -0700 Subject: [PATCH 084/198] add SLEDGE_DISABLE_AUTOSCALING to enable or disable autoscaling --- runtime/include/binary_search_tree.h | 2 +- runtime/src/listener_thread.c | 21 +++++++++++++++------ runtime/src/main.c | 13 ++++++++++--- runtime/tests/start.sh | 1 + 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/runtime/include/binary_search_tree.h b/runtime/include/binary_search_tree.h index cb1ed47dc..32aa6c3c1 100644 --- a/runtime/include/binary_search_tree.h +++ b/runtime/include/binary_search_tree.h @@ -73,7 +73,7 @@ struct TreeNode* newNode(struct binary_tree *binary_tree, void *data) { assert(binary_tree != NULL); if (binary_tree->nodePool.head == NULL) { - panic("queue is full\n"); + panic("Binary search tree queue is full\n"); return NULL; } else { // Remove a node from the head of the memory pool diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 1c17aedd7..aa0054105 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -23,6 +23,7 @@ #define BASE_SERVICE_TIME 10 #define LOSS_PERCENTAGE 0.11 +thread_local int current_active_workers = 1; thread_local int next_loop_start_index = -1; thread_local uint64_t total_requests = 0; uint64_t base_simulated_service_time = 0; @@ -41,6 +42,7 @@ struct binary_tree * worker_binary_trees[1024]; struct request_fifo_queue * worker_circular_queue[1024]; struct request_fifo_queue * worker_preempted_queue[1024]; +extern bool runtime_autoscaling_enabled; extern FILE *sandbox_perf_log; extern bool runtime_exponential_service_time_simulation_enabled; extern _Atomic uint64_t worker_queuing_cost[1024]; @@ -532,13 +534,13 @@ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, the current one */ next_loop_start_index++; - if (next_loop_start_index == runtime_worker_group_size) { + if (next_loop_start_index == current_active_workers) { next_loop_start_index = 0; } //uint64_t waiting_times[3] = {0}; - for (uint32_t i = next_loop_start_index; i < next_loop_start_index + runtime_worker_group_size; ++i) { - int true_idx = i % runtime_worker_group_size; + for (uint32_t i = next_loop_start_index; i < next_loop_start_index + current_active_workers; ++i) { + int true_idx = i % current_active_workers; bool need_interrupt; uint64_t waiting_serving_time = local_runqueue_try_add_index(worker_list[true_idx], sandbox, &need_interrupt); /*waiting_times[true_idx] = waiting_serving_time; @@ -992,7 +994,6 @@ listener_thread_main(void *dummy) /* calucate the worker start and end id for this listener */ worker_start_id = dispatcher_thread_idx * runtime_worker_group_size; worker_end_id = worker_start_id + runtime_worker_group_size; - printf("listener %d worker_start_id %d worker_end_id %d\n", dispatcher_thread_idx, worker_start_id, worker_end_id - 1); int index = 0; for (uint32_t i = worker_start_id; i < worker_end_id; i++) { @@ -1000,7 +1001,15 @@ listener_thread_main(void *dummy) index++; } - free_workers[dispatcher_thread_idx] = __builtin_powi(2, runtime_worker_group_size) - 1; + if (runtime_autoscaling_enabled) { + current_active_workers = 1; + } else { + current_active_workers = runtime_worker_group_size; + } + printf("listener %d worker_start_id %d worker_end_id %d active worker %d\n", + dispatcher_thread_idx, worker_start_id, worker_end_id - 1, current_active_workers); + + free_workers[dispatcher_thread_idx] = __builtin_powi(2, current_active_workers) - 1; printf("free_workers is %u\n", free_workers[dispatcher_thread_idx]); @@ -1034,7 +1043,7 @@ listener_thread_main(void *dummy) } } - /* won't go to the following implementaion */ + /* code will end here with eRPC and won't go to the following implementaion */ while (!pthread_stop) { printf("pthread_stop is false\n"); /* Block indefinitely on the epoll file descriptor, waiting on up to a max number of events */ diff --git a/runtime/src/main.c b/runtime/src/main.c index 5d49e8c54..13430556a 100644 --- a/runtime/src/main.c +++ b/runtime/src/main.c @@ -51,9 +51,10 @@ uint32_t runtime_worker_group_size = 1; enum RUNTIME_SIGALRM_HANDLER runtime_sigalrm_handler = RUNTIME_SIGALRM_HANDLER_BROADCAST; bool runtime_exponential_service_time_simulation_enabled = false; -bool runtime_preemption_enabled = true; -bool runtime_worker_spinloop_pause_enabled = false; -uint32_t runtime_quantum_us = 5000; /* 5ms */ +bool runtime_autoscaling_enabled = false; +bool runtime_preemption_enabled = true; +bool runtime_worker_spinloop_pause_enabled = false; +uint32_t runtime_quantum_us = 5000; /* 5ms */ uint64_t runtime_boot_timestamp; pid_t runtime_pid = 0; @@ -293,6 +294,12 @@ runtime_configure() pretty_print_key_value("Preemption", "%s\n", runtime_preemption_enabled ? PRETTY_PRINT_GREEN_ENABLED : PRETTY_PRINT_RED_DISABLED); + /* Runtime Autoscaling */ + char *autoscaling_disable = getenv("SLEDGE_DISABLE_AUTOSCALING"); + if (autoscaling_disable != NULL && strcmp(autoscaling_disable, "true") != 0) runtime_autoscaling_enabled = true; + pretty_print_key_value("Autoscaling", "%s\n", + runtime_autoscaling_enabled ? PRETTY_PRINT_GREEN_ENABLED : PRETTY_PRINT_RED_DISABLED); + /* Runtime Quantum */ char *quantum_raw = getenv("SLEDGE_QUANTUM_US"); if (quantum_raw != NULL) { diff --git a/runtime/tests/start.sh b/runtime/tests/start.sh index bc4453220..9fffcdecb 100755 --- a/runtime/tests/start.sh +++ b/runtime/tests/start.sh @@ -28,6 +28,7 @@ export SLEDGE_FIRST_WORKER_COREID=$first_worker_core_id export SLEDGE_NWORKERS=$worker_num export SLEDGE_NLISTENERS=$listener_num export SLEDGE_WORKER_GROUP_SIZE=3 +export SLEDGE_DISABLE_AUTOSCALING=false export SLEDGE_SCHEDULER=EDF #export SLEDGE_DISPATCHER=DARC #export SLEDGE_DISPATCHER=SHINJUKU From 60bf4b623888fc00ee1a6917c70b04fb97fdbf4d Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 9 Jan 2024 15:25:45 -0700 Subject: [PATCH 085/198] 1. fix bug: condition variable lost signal 2. Add semaphore to wake up worker --- runtime/include/binary_search_tree.h | 40 ++++++++++++++---- runtime/include/scheduler.h | 18 +++++--- runtime/src/listener_thread.c | 12 ++++-- runtime/src/local_runqueue.c | 53 +++++++++++++++--------- runtime/src/local_runqueue_binary_tree.c | 20 ++++++++- runtime/src/main.c | 23 ++++------ runtime/src/runtime.c | 4 ++ runtime/src/software_interrupt.c | 14 ++++--- runtime/src/worker_thread.c | 6 +++ runtime/tests/start.sh | 3 +- 10 files changed, 132 insertions(+), 61 deletions(-) diff --git a/runtime/include/binary_search_tree.h b/runtime/include/binary_search_tree.h index 32aa6c3c1..9543f618a 100644 --- a/runtime/include/binary_search_tree.h +++ b/runtime/include/binary_search_tree.h @@ -25,55 +25,77 @@ struct TreeNodePool { }; struct binary_tree { - struct TreeNode *root; + struct TreeNode *root; struct TreeNodePool nodePool; binary_tree_get_priority_fn_t get_priority_fn; binary_tree_get_execution_cost_fn_t get_execution_cost_fn; lock_t lock; bool use_lock; + int id; }; // Initialize the node pool -void initNodePool(struct TreeNodePool *nodePool) { +void initNodePool(struct TreeNodePool *nodePool, int pool_size) { assert(nodePool != NULL); - struct TreeNode *nodes = (struct TreeNode*)malloc(MAX_NODES * sizeof(struct TreeNode)); + struct TreeNode *nodes = (struct TreeNode*)malloc(pool_size * sizeof(struct TreeNode)); nodePool->head = nodes; // Initialize head to the beginning of the node array for (int i = 0; i < MAX_NODES - 1; ++i) { nodes[i].next = &nodes[i + 1]; // Set the next pointer of each node to the next node nodes[i].left = NULL; - nodes[i].right = NULL; - nodes[i].data = NULL; + nodes[i].right = NULL; + nodes[i].data = NULL; } nodes[MAX_NODES - 1].next = NULL; } struct binary_tree * init_binary_tree(bool use_lock, binary_tree_get_priority_fn_t get_priority_fn, - binary_tree_get_execution_cost_fn_t get_execution_cost_fn) { + binary_tree_get_execution_cost_fn_t get_execution_cost_fn, int id, int queue_size) { assert(get_priority_fn != NULL); struct binary_tree *binary_tree = (struct binary_tree *)calloc(1, sizeof(struct binary_tree)); - initNodePool(&binary_tree->nodePool); + initNodePool(&binary_tree->nodePool, queue_size); binary_tree->root = NULL; binary_tree->get_priority_fn = get_priority_fn; binary_tree->get_execution_cost_fn = get_execution_cost_fn; binary_tree->use_lock = use_lock; + binary_tree->id = id; if (binary_tree->use_lock) lock_init(&binary_tree->lock); return binary_tree; } +// Helper function for counting non-deleted nodes in the binary tree +static int countNonDeletedNodesRec(struct TreeNode* root) { + if (root == NULL) { + return 0; + } + + // Only count nodes that are not marked as deleted + if (root->data != NULL) { + return 1 + countNonDeletedNodesRec(root->left) + countNonDeletedNodesRec(root->right); + } else { + return countNonDeletedNodesRec(root->left) + countNonDeletedNodesRec(root->right); + } +} + +// Function to get the total number of non-deleted nodes in the binary tree +int getNonDeletedNodeCount(struct binary_tree *binary_tree) { + assert(binary_tree != NULL); + return countNonDeletedNodesRec(binary_tree->root); +} + // Get a new node from the pool struct TreeNode* newNode(struct binary_tree *binary_tree, void *data) { assert(binary_tree != NULL); if (binary_tree->nodePool.head == NULL) { - panic("Binary search tree queue is full\n"); + panic("Binary search tree queue %d is full\n", binary_tree->id); return NULL; } else { // Remove a node from the head of the memory pool @@ -142,7 +164,7 @@ int findHeight(struct TreeNode *root) { int lefth, righth; if(root == NULL) - return -1; + return 0; lefth = findHeight(root->left); righth = findHeight(root->right); return (lefth > righth ? lefth : righth)+1; diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index 8d0c3fccd..74727cf53 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -30,6 +30,7 @@ #include "listener_thread.h" #include "local_preempted_fifo_queue.h" +extern bool runtime_worker_busy_loop_enabled; extern thread_local uint32_t interrupts; extern thread_local bool pthread_stop; extern uint32_t runtime_worker_group_size; @@ -37,6 +38,7 @@ extern _Atomic uint32_t free_workers[10]; extern thread_local int dispatcher_id; extern pthread_mutex_t mutexs[1024]; extern pthread_cond_t conds[1024]; +extern sem_t semlock[1024]; /** * This scheduler provides for cooperative and preemptive multitasking in a OS process's userspace. * @@ -483,11 +485,17 @@ scheduler_idle_loop() ret[3] += ret_inner[3]; ret[4] += ret_inner[4]; } - /* If queue is empty, then sleep to wait for the condition variable */ - if (next_sandbox == NULL) { - pthread_mutex_lock(&mutexs[global_worker_thread_idx]); - pthread_cond_wait(&conds[global_worker_thread_idx], &mutexs[global_worker_thread_idx]); - pthread_mutex_unlock(&mutexs[global_worker_thread_idx]); + /* If queue is empty, then sleep to wait for the condition variable or sempahore */ + if (!runtime_worker_busy_loop_enabled) { + /*pthread_mutex_lock(&mutexs[global_worker_thread_idx]); + if (local_runqueue_is_empty()) { + pthread_cond_wait(&conds[global_worker_thread_idx], &mutexs[global_worker_thread_idx]); + } + pthread_mutex_unlock(&mutexs[global_worker_thread_idx]); + */ + if (local_runqueue_is_empty()) { + sem_wait(&semlock[global_worker_thread_idx]); + } } } } diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index aa0054105..5f068899d 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -33,6 +33,7 @@ thread_local uint32_t max_queue_length = 0; pthread_mutex_t mutexs[1024]; pthread_cond_t conds[1024]; +sem_t semlock[1024]; uint32_t worker_old_sandbox[1024] = {0}; uint32_t worker_new_sandbox[1024] = {0}; @@ -42,6 +43,7 @@ struct binary_tree * worker_binary_trees[1024]; struct request_fifo_queue * worker_circular_queue[1024]; struct request_fifo_queue * worker_preempted_queue[1024]; +extern uint64_t wakeup_thread_cycles; extern bool runtime_autoscaling_enabled; extern FILE *sandbox_perf_log; extern bool runtime_exponential_service_time_simulation_enabled; @@ -567,10 +569,12 @@ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, } else { candidate_thread_with_interrupt = worker_list[true_idx]; } - } else if (min_waiting_serving_time > waiting_serving_time) { - min_waiting_serving_time = waiting_serving_time; - thread_id = worker_list[true_idx]; - } + } else { + if (min_waiting_serving_time > waiting_serving_time) { + min_waiting_serving_time = waiting_serving_time; + thread_id = worker_list[true_idx]; + } + } } if (candidate_thread_with_interrupt != -1) { diff --git a/runtime/src/local_runqueue.c b/runtime/src/local_runqueue.c index 41263cf24..dff773075 100644 --- a/runtime/src/local_runqueue.c +++ b/runtime/src/local_runqueue.c @@ -6,16 +6,16 @@ #include "local_runqueue.h" +extern thread_local int global_worker_thread_idx; +extern bool runtime_worker_busy_loop_enabled; extern pthread_mutex_t mutexs[1024]; extern pthread_cond_t conds[1024]; +extern sem_t semlock[1024]; extern _Atomic uint64_t worker_queuing_cost[1024]; -thread_local uint32_t total_local_requests = 0; static struct local_runqueue_config local_runqueue; - -#ifdef LOG_LOCAL_RUNQUEUE -thread_local uint32_t local_runqueue_count = 0; -#endif +thread_local uint32_t total_complete_requests = 0; +_Atomic uint32_t local_runqueue_count[1024]; /* Initializes a concrete implementation of the sandbox request scheduler interface */ void @@ -32,26 +32,38 @@ void local_runqueue_add(struct sandbox *sandbox) { assert(local_runqueue.add_fn != NULL); -#ifdef LOG_LOCAL_RUNQUEUE - local_runqueue_count++; -#endif - return local_runqueue.add_fn(sandbox); + local_runqueue.add_fn(sandbox); + //atomic_fetch_add(&local_runqueue_count[global_worker_thread_idx], 1); } void local_runqueue_add_index(int index, struct sandbox *sandbox) { assert(local_runqueue.add_fn_idx != NULL); -#ifdef LOG_LOCAL_RUNQUEUE - local_runqueue_count++; -#endif /* wakeup worker if it is empty before we add a new request */ - if (local_runqueue_is_empty_index(index)) { - local_runqueue.add_fn_idx(index, sandbox); - wakeup_worker(index); + + if (!runtime_worker_busy_loop_enabled) { + /*pthread_mutex_lock(&mutexs[index]); + if (local_runqueue_is_empty_index(index)) { + local_runqueue.add_fn_idx(index, sandbox); + //atomic_fetch_add(&local_runqueue_count[index], 1); + pthread_mutex_unlock(&mutexs[index]); + pthread_cond_signal(&conds[index]); + } else { + pthread_mutex_unlock(&mutexs[index]); + local_runqueue.add_fn_idx(index, sandbox); + }*/ + + if (local_runqueue_is_empty_index(index)) { + local_runqueue.add_fn_idx(index, sandbox); + sem_post(&semlock[index]); + } else { + local_runqueue.add_fn_idx(index, sandbox); + } } else { local_runqueue.add_fn_idx(index, sandbox); } + } uint64_t @@ -68,11 +80,9 @@ void local_runqueue_delete(struct sandbox *sandbox) { assert(local_runqueue.delete_fn != NULL); - total_local_requests++; -#ifdef LOG_LOCAL_RUNQUEUE - local_runqueue_count--; -#endif + total_complete_requests++; local_runqueue.delete_fn(sandbox); + //atomic_fetch_sub(&local_runqueue_count[global_worker_thread_idx], 1); } /** @@ -128,7 +138,10 @@ local_runqueue_get_next() void worker_queuing_cost_initialize() { - for (int i = 0; i < 1024; i++) atomic_init(&worker_queuing_cost[i], 0); + for (int i = 0; i < 1024; i++) { + atomic_init(&worker_queuing_cost[i], 0); + //atomic_init(&local_runqueue_count[i], 0); + } } void diff --git a/runtime/src/local_runqueue_binary_tree.c b/runtime/src/local_runqueue_binary_tree.c index a4345d48f..4062ec83e 100644 --- a/runtime/src/local_runqueue_binary_tree.c +++ b/runtime/src/local_runqueue_binary_tree.c @@ -159,12 +159,14 @@ local_runqueue_binary_tree_get_next() * Try but not real add a item to the local runqueue. * @param index The worker thread id * @param sandbox Try to add - * @returns The waiting serving time for this sandbox if adding it to the queue + * @returns The waiting serving time in cycles for this sandbox if adding it to the queue */ uint64_t local_runqueue_binary_tree_try_add_index(int index, struct sandbox *sandbox, bool *need_interrupt) { struct binary_tree *binary_tree = worker_binary_trees[index]; + assert(binary_tree != NULL); + if (is_empty(binary_tree)) { /* The worker is idle */ *need_interrupt = false; @@ -196,6 +198,18 @@ int local_runqueue_binary_tree_get_height() { return findHeight(local_runqueue_binary_tree->root); } +int local_runqueue_binary_tree_get_length() { + assert (local_runqueue_binary_tree != NULL); + return getNonDeletedNodeCount(local_runqueue_binary_tree); +} + +int local_runqueue_binary_tree_get_length_index(int index) { + struct binary_tree *binary_tree = worker_binary_trees[index]; + assert(binary_tree != NULL); + + return getNonDeletedNodeCount(binary_tree); +} + void local_runqueue_print_in_order(int index) { struct binary_tree *binary_tree = worker_binary_trees[index]; assert(binary_tree != NULL); @@ -209,7 +223,7 @@ void local_runqueue_binary_tree_initialize() { /* Initialize local state */ - local_runqueue_binary_tree = init_binary_tree(true, sandbox_get_priority, sandbox_get_execution_cost); + local_runqueue_binary_tree = init_binary_tree(true, sandbox_get_priority, sandbox_get_execution_cost, global_worker_thread_idx, 4096); worker_binary_trees[global_worker_thread_idx] = local_runqueue_binary_tree; /* Register Function Pointers for Abstract Scheduling API */ @@ -221,6 +235,8 @@ local_runqueue_binary_tree_initialize() .delete_fn = local_runqueue_binary_tree_delete, .get_next_fn = local_runqueue_binary_tree_get_next, .get_height_fn = local_runqueue_binary_tree_get_height, + .get_length_fn = local_runqueue_binary_tree_get_length, + .get_length_fn_idx = local_runqueue_binary_tree_get_length_index, .print_in_order_fn_idx = local_runqueue_print_in_order }; diff --git a/runtime/src/main.c b/runtime/src/main.c index 13430556a..a83db5013 100644 --- a/runtime/src/main.c +++ b/runtime/src/main.c @@ -52,6 +52,7 @@ enum RUNTIME_SIGALRM_HANDLER runtime_sigalrm_handler = RUNTIME_SIGALRM_HANDLER_B bool runtime_exponential_service_time_simulation_enabled = false; bool runtime_autoscaling_enabled = false; +bool runtime_worker_busy_loop_enabled = false; bool runtime_preemption_enabled = true; bool runtime_worker_spinloop_pause_enabled = false; uint32_t runtime_quantum_us = 5000; /* 5ms */ @@ -299,7 +300,13 @@ runtime_configure() if (autoscaling_disable != NULL && strcmp(autoscaling_disable, "true") != 0) runtime_autoscaling_enabled = true; pretty_print_key_value("Autoscaling", "%s\n", runtime_autoscaling_enabled ? PRETTY_PRINT_GREEN_ENABLED : PRETTY_PRINT_RED_DISABLED); - + + /* Runtime worker busy loop */ + char *worker_busy_loop_disable = getenv("SLEDGE_DISABLE_BUSY_LOOP"); + if (worker_busy_loop_disable != NULL && strcmp(worker_busy_loop_disable, "true") != 0) runtime_worker_busy_loop_enabled = true; + pretty_print_key_value("Worker busy loop", "%s\n", + runtime_worker_busy_loop_enabled ? PRETTY_PRINT_GREEN_ENABLED : PRETTY_PRINT_RED_DISABLED); + /* Runtime Quantum */ char *quantum_raw = getenv("SLEDGE_QUANTUM_US"); if (quantum_raw != NULL) { @@ -326,17 +333,6 @@ runtime_configure() http_session_perf_log_init(); } -void -runtime_configure_worker_spinloop_pause() -{ - /* Runtime Worker-Spinloop-Pause Toggle */ - char *pause_enable = getenv("SLEDGE_SPINLOOP_PAUSE_ENABLED"); - if (pause_enable != NULL && strcmp(pause_enable, "true") == 0) runtime_worker_spinloop_pause_enabled = true; - pretty_print_key_value("Worker-Spinloop-Pause", "%s\n", - runtime_worker_spinloop_pause_enabled ? PRETTY_PRINT_GREEN_ENABLED - : PRETTY_PRINT_RED_DISABLED); -} - void log_compiletime_config() { @@ -612,10 +608,7 @@ main(int argc, char **argv) runtime_allocate_available_cores(); runtime_configure(); runtime_initialize(); - //runtime_start_runtime_worker_threads(); runtime_get_processor_speed_MHz(); - //runtime_configure_worker_spinloop_pause(); - //software_interrupt_arm_timer(); #ifdef LOG_TENANT_LOADING diff --git a/runtime/src/runtime.c b/runtime/src/runtime.c index c124461cc..429c52474 100644 --- a/runtime/src/runtime.c +++ b/runtime/src/runtime.c @@ -24,6 +24,8 @@ #include "software_interrupt.h" #include "sandbox_perf_log.h" +#define WAKEUP_THREAD_OVERHEAD 5 /* 5us */ + /*************************** * Shared Process State * **************************/ @@ -36,6 +38,7 @@ int *runtime_worker_threads_argument; int *runtime_listener_threads_argument; /* The active deadline of the sandbox running on each worker thread */ uint64_t *runtime_worker_threads_deadline; +uint64_t wakeup_thread_cycles; /****************************************** * Shared Process / Listener Thread Logic * @@ -136,6 +139,7 @@ runtime_initialize(void) http_parser_settings_initialize(); admissions_control_initialize(); + wakeup_thread_cycles = WAKEUP_THREAD_OVERHEAD * runtime_processor_speed_MHz; } static void diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index e3526624a..f00b14878 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -27,6 +27,8 @@ #include "memlogging.h" #include "tenant_functions.h" +extern sem_t semlock[1024]; +extern uint32_t local_runqueue_count[1024]; extern thread_local uint8_t dispatcher_thread_idx; extern uint32_t worker_old_sandbox[1024]; extern uint32_t worker_new_sandbox[1024]; @@ -42,7 +44,7 @@ extern time_t t_start; extern thread_local int global_worker_thread_idx; extern thread_local bool pthread_stop; extern thread_local bool is_listener; -extern thread_local uint32_t total_local_requests; +extern thread_local uint32_t total_complete_requests; thread_local _Atomic volatile sig_atomic_t handler_depth = 0; thread_local _Atomic volatile sig_atomic_t deferred_sigalrm = 0; @@ -264,16 +266,18 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void /* calculate the throughput */ double throughput = atomic_load(&sandbox_state_totals[SANDBOX_COMPLETE]) / seconds; uint32_t total_sandboxes_error = atomic_load(&sandbox_state_totals[SANDBOX_ERROR]); - mem_log("throughput %f tid(%d) error request %u complete requests %u total request %u total_local_requests %u interrupts %u p-interrupts %u max local queue %u\n", + mem_log("throughput %f tid(%d) error request %u complete requests %u total request %u total_complete_requests %u interrupts %u p-interrupts %u max local queue %u\n", throughput, global_worker_thread_idx, total_sandboxes_error, atomic_load(&sandbox_state_totals[SANDBOX_COMPLETE]), - atomic_load(&sandbox_state_totals[SANDBOX_ALLOCATED]), total_local_requests, interrupts, preemptable_interrupts, + atomic_load(&sandbox_state_totals[SANDBOX_ALLOCATED]), total_complete_requests, interrupts, preemptable_interrupts, max_local_queue_length[global_worker_thread_idx]); dump_log_to_file(); - printf("id %d max local queue %u new %u old %u\n", global_worker_thread_idx, max_local_queue_length[global_worker_thread_idx], - worker_new_sandbox[global_worker_thread_idx], worker_old_sandbox[global_worker_thread_idx]); + printf("id %d max local queue %u new %u old %u current length %u real length %d total complete request %u\n", global_worker_thread_idx, max_local_queue_length[global_worker_thread_idx], + worker_new_sandbox[global_worker_thread_idx], worker_old_sandbox[global_worker_thread_idx], local_runqueue_count[global_worker_thread_idx], + local_runqueue_get_length(), total_complete_requests); pthread_stop = true; /* Wake up worker so it can check if pthread_stop is true, othewise, it will block at condition wait */ wakeup_worker(global_worker_thread_idx); + sem_post(&semlock[global_worker_thread_idx]); break; } default: { diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c index 85e907358..b11b7a03f 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c @@ -26,6 +26,7 @@ extern pthread_mutex_t mutexs[1024]; extern pthread_cond_t conds[1024]; +extern sem_t semlock[1024]; _Atomic uint32_t local_queue_length[1024] = {0}; uint32_t max_local_queue_length[1024] = {0}; @@ -69,6 +70,10 @@ void condition_variable_init() { pthread_cond_init(&conds[global_worker_thread_idx], NULL); } +void semaphore_init(){ + sem_init(&semlock[global_worker_thread_idx], 0, 0); +} + /** * The entry function for sandbox worker threads * Initializes thread-local state, unmasks signals, sets up epoll loop and @@ -98,6 +103,7 @@ worker_thread_main(void *argument) preallocate_memory(); perf_window_init(); condition_variable_init(); + semaphore_init(); scheduler_runqueue_initialize(); local_preempted_fifo_queue_init(); diff --git a/runtime/tests/start.sh b/runtime/tests/start.sh index 9fffcdecb..c1654efa0 100755 --- a/runtime/tests/start.sh +++ b/runtime/tests/start.sh @@ -22,13 +22,14 @@ declare project_path="$( echo $project_path path=`pwd` export SLEDGE_DISABLE_PREEMPTION=true +export SLEDGE_DISABLE_BUSY_LOOP=false +export SLEDGE_DISABLE_AUTOSCALING=true export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=true #export SLEDGE_SIGALRM_HANDLER=TRIAGED export SLEDGE_FIRST_WORKER_COREID=$first_worker_core_id export SLEDGE_NWORKERS=$worker_num export SLEDGE_NLISTENERS=$listener_num export SLEDGE_WORKER_GROUP_SIZE=3 -export SLEDGE_DISABLE_AUTOSCALING=false export SLEDGE_SCHEDULER=EDF #export SLEDGE_DISPATCHER=DARC #export SLEDGE_DISPATCHER=SHINJUKU From cc5c33ea26a8ba6f32b17f57610e41b81640128e Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 9 Jan 2024 15:26:11 -0700 Subject: [PATCH 086/198] forgot submit runtime/include/runtime.h --- runtime/include/runtime.h | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/include/runtime.h b/runtime/include/runtime.h index 4437596ed..3d031166a 100644 --- a/runtime/include/runtime.h +++ b/runtime/include/runtime.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include /* for epoll_create1(), epoll_ctl(), struct epoll_event */ #include /* for pid_t */ #include From 6c84872e5aa2b7b37f5764c4b3e1cf0710ff6d45 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Mon, 15 Jan 2024 14:35:13 -0700 Subject: [PATCH 087/198] add scaling up implementation and cpu monitoring script --- runtime/include/scheduler.h | 13 +++++- runtime/src/listener_thread.c | 23 ++++++++-- runtime/src/local_runqueue.c | 3 ++ runtime/tests/hash.json | 33 ++++++++++++++ runtime/tests/parse_cpu_batch.py | 78 ++++++++++++++++++++++++++++++++ runtime/tests/start.sh | 9 ++-- runtime/tests/start_monitor.sh | 15 ++++++ runtime/tests/start_test.sh | 13 ++++-- runtime/tests/stop_monitor.sh | 5 ++ 9 files changed, 180 insertions(+), 12 deletions(-) create mode 100644 runtime/tests/hash.json create mode 100644 runtime/tests/parse_cpu_batch.py create mode 100755 runtime/tests/start_monitor.sh create mode 100755 runtime/tests/stop_monitor.sh diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index 74727cf53..9366b6410 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -30,6 +30,7 @@ #include "listener_thread.h" #include "local_preempted_fifo_queue.h" +extern struct timespec startT[1024]; extern bool runtime_worker_busy_loop_enabled; extern thread_local uint32_t interrupts; extern thread_local bool pthread_stop; @@ -39,6 +40,7 @@ extern thread_local int dispatcher_id; extern pthread_mutex_t mutexs[1024]; extern pthread_cond_t conds[1024]; extern sem_t semlock[1024]; + /** * This scheduler provides for cooperative and preemptive multitasking in a OS process's userspace. * @@ -487,14 +489,23 @@ scheduler_idle_loop() } /* If queue is empty, then sleep to wait for the condition variable or sempahore */ if (!runtime_worker_busy_loop_enabled) { - /*pthread_mutex_lock(&mutexs[global_worker_thread_idx]); + /*struct timespec endT; + int64_t delta_us = 0; + pthread_mutex_lock(&mutexs[global_worker_thread_idx]); if (local_runqueue_is_empty()) { pthread_cond_wait(&conds[global_worker_thread_idx], &mutexs[global_worker_thread_idx]); + clock_gettime(CLOCK_MONOTONIC, &endT); + delta_us = (endT.tv_sec - startT[global_worker_thread_idx].tv_sec) * 1000000 + (endT.tv_nsec - startT[global_worker_thread_idx].tv_nsec) / 1000; } pthread_mutex_unlock(&mutexs[global_worker_thread_idx]); + printf("worker %d delta %ld\n", global_worker_thread_idx, delta_us); */ if (local_runqueue_is_empty()) { sem_wait(&semlock[global_worker_thread_idx]); + //struct timespec endT; + //clock_gettime(CLOCK_MONOTONIC, &endT); + //int64_t delta_us = (endT.tv_sec - startT[global_worker_thread_idx].tv_sec) * 1000000 + (endT.tv_nsec - startT[global_worker_thread_idx].tv_nsec) / 1000; + //printf("worker %d delta %ld\n", global_worker_thread_idx, delta_us); } } } diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 5f068899d..ad16ca21c 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -43,6 +43,7 @@ struct binary_tree * worker_binary_trees[1024]; struct request_fifo_queue * worker_circular_queue[1024]; struct request_fifo_queue * worker_preempted_queue[1024]; +extern pthread_t *runtime_worker_threads; extern uint64_t wakeup_thread_cycles; extern bool runtime_autoscaling_enabled; extern FILE *sandbox_perf_log; @@ -541,9 +542,10 @@ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, } //uint64_t waiting_times[3] = {0}; + int violate_deadline_workers = 0; for (uint32_t i = next_loop_start_index; i < next_loop_start_index + current_active_workers; ++i) { int true_idx = i % current_active_workers; - bool need_interrupt; + bool need_interrupt; uint64_t waiting_serving_time = local_runqueue_try_add_index(worker_list[true_idx], sandbox, &need_interrupt); /*waiting_times[true_idx] = waiting_serving_time; if (waiting_times[true_idx] != 0) { @@ -573,10 +575,25 @@ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, if (min_waiting_serving_time > waiting_serving_time) { min_waiting_serving_time = waiting_serving_time; thread_id = worker_list[true_idx]; - } + } + /* Check flag and if need to autoscale */ + if (runtime_autoscaling_enabled && + (min_waiting_serving_time + sandbox->estimated_cost + (wakeup_thread_cycles) >= sandbox->relative_deadline)) { + violate_deadline_workers++; + } } } - + + /* If no any worker can meet the current request deadline, scale up */ + if (runtime_autoscaling_enabled && current_active_workers < runtime_worker_group_size + && violate_deadline_workers == current_active_workers) { + /* Add the current request to the scaling up worker */ + local_runqueue_add_index(current_active_workers, sandbox); + current_active_workers++; + printf("current_active_workers %d\n", current_active_workers); + return; + } + if (candidate_thread_with_interrupt != -1) { //urgent_request[candidate_thread_with_interrupt] = sandbox; local_runqueue_add_index(candidate_thread_with_interrupt, sandbox); diff --git a/runtime/src/local_runqueue.c b/runtime/src/local_runqueue.c index dff773075..5dc576c14 100644 --- a/runtime/src/local_runqueue.c +++ b/runtime/src/local_runqueue.c @@ -16,6 +16,7 @@ extern _Atomic uint64_t worker_queuing_cost[1024]; static struct local_runqueue_config local_runqueue; thread_local uint32_t total_complete_requests = 0; _Atomic uint32_t local_runqueue_count[1024]; +struct timespec startT[1024]; /* Initializes a concrete implementation of the sandbox request scheduler interface */ void @@ -48,6 +49,7 @@ local_runqueue_add_index(int index, struct sandbox *sandbox) local_runqueue.add_fn_idx(index, sandbox); //atomic_fetch_add(&local_runqueue_count[index], 1); pthread_mutex_unlock(&mutexs[index]); + clock_gettime(CLOCK_MONOTONIC, &startT[index]); pthread_cond_signal(&conds[index]); } else { pthread_mutex_unlock(&mutexs[index]); @@ -56,6 +58,7 @@ local_runqueue_add_index(int index, struct sandbox *sandbox) if (local_runqueue_is_empty_index(index)) { local_runqueue.add_fn_idx(index, sandbox); + //clock_gettime(CLOCK_MONOTONIC, &startT[index]); sem_post(&semlock[index]); } else { local_runqueue.add_fn_idx(index, sandbox); diff --git a/runtime/tests/hash.json b/runtime/tests/hash.json new file mode 100644 index 000000000..8c6212132 --- /dev/null +++ b/runtime/tests/hash.json @@ -0,0 +1,33 @@ +[ + { + "name": "gwu", + "port": 31850, + "replenishment-period-us": 0, + "max-budget-us": 0, + "routes": [ + { + "route": "/hash", + "request-type": 1, + "n-resas": 2, + "path": "hash.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 5, + "relative-deadline-us": 50, + "http-resp-content-type": "text/plain" + }, + { + "route": "/hash2", + "request-type": 2, + "n-resas": 1, + "path": "hash.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 6480, + "relative-deadline-us": 64800, + "http-resp-content-type": "text/plain" + } + ] + + } + +] + diff --git a/runtime/tests/parse_cpu_batch.py b/runtime/tests/parse_cpu_batch.py new file mode 100644 index 000000000..1be6c1212 --- /dev/null +++ b/runtime/tests/parse_cpu_batch.py @@ -0,0 +1,78 @@ +import re +import os +import sys +from collections import defaultdict + +sending_rate_dict = defaultdict(list) +service_rate_dict = defaultdict(list) + +#get all file names which contain key_str +def file_name(file_dir, key_str): + print(file_dir, key_str) + file_list = [] + rps_list = [] + + for root, dirs, files in os.walk(file_dir): + print("file:", files) + print("root:", root) + print("dirs:", dirs) + for file_i in files: + if file_i.find(key_str) >= 0: + full_path = os.path.join(os.getcwd() + "/" + root, file_i) + #print(full_path) + segs = file_i.split('-') + if len(segs) < 2: + continue + rps=segs[1] + print("rps---------", rps) + rps=rps.split(".")[0] + file_list.append(full_path) + rps_list.append(rps) + + file_list = sorted(file_list, key = lambda x: int(x.split('-')[-1].split(".")[0])) + rps_list = sorted(rps_list) + print(file_list) + print(rps_list) + return file_list, rps_list + +def get_values(key, files_list, cpu_usages_dict): + for file_i in files_list: + cmd="awk '/Average:/ {print $8}' %s" % file_i + rt=os.popen(cmd).read().strip() + cpu_count=float(rt)/100 + cpu_count=round(cpu_count, 2) + print(cpu_count) + cpu_usages_dict[key].append(cpu_count) + + +if __name__ == "__main__": + import json + #file_folders = ['SHINJUKU', 'SHINJUKU_25', 'DARC', 'EDF_SRSF_INTERRUPT'] + #file_folders = ['SHINJUKU_7', 'SHINJUKU_25', 'DARC', 'EDF_SRSF_INTERRUPT'] + #file_folders = ['SHINJUKU', 'DARC', 'EDF_SRSF_INTERRUPT'] + file_folders = ['EDF_INTERRUPT-disable-busy-loop-false-disable-autoscaling-true-9','EDF_INTERRUPT-disable-busy-loop-true-disable-autoscaling-false-9', 'EDF_INTERRUPT-disable-busy-loop-true-disable-autoscaling-true-27'] + #file_folders = ['EDF_INTERRUPT','EDF_SRSF_INTERRUPT_1'] + #file_folders = ['DARC', 'EDF_SRSF_INTERRUPT'] + #file_folders = ['SHINJUKU'] + cpu_usages_dict = defaultdict(list) + rps_list = [] + + argv = sys.argv[1:] + if len(argv) < 1: + print("usage ", sys.argv[0], "[file key]") + sys.exit() + + for key in file_folders: + files_list, rps_list = file_name(key, argv[0]) + get_values(key, files_list, cpu_usages_dict) + + print("cpu usage:") + for key, value in cpu_usages_dict.items(): + print(key, ":", value) + + js1 = json.dumps(cpu_usages_dict) + f1 = open("cpu.txt", 'w') + f1.write(js1) + f1.close() + + diff --git a/runtime/tests/start.sh b/runtime/tests/start.sh index c1654efa0..74bcafb26 100755 --- a/runtime/tests/start.sh +++ b/runtime/tests/start.sh @@ -22,14 +22,14 @@ declare project_path="$( echo $project_path path=`pwd` export SLEDGE_DISABLE_PREEMPTION=true -export SLEDGE_DISABLE_BUSY_LOOP=false +export SLEDGE_DISABLE_BUSY_LOOP=true export SLEDGE_DISABLE_AUTOSCALING=true -export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=true +export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=false #export SLEDGE_SIGALRM_HANDLER=TRIAGED export SLEDGE_FIRST_WORKER_COREID=$first_worker_core_id export SLEDGE_NWORKERS=$worker_num export SLEDGE_NLISTENERS=$listener_num -export SLEDGE_WORKER_GROUP_SIZE=3 +export SLEDGE_WORKER_GROUP_SIZE=9 export SLEDGE_SCHEDULER=EDF #export SLEDGE_DISPATCHER=DARC #export SLEDGE_DISPATCHER=SHINJUKU @@ -45,7 +45,8 @@ cd $project_path/runtime/bin #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/mulitple_linear_chain.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing3.json -LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/fib.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/fib.json +LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/hash.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/empty.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/my_fibonacci.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_sodresize.json diff --git a/runtime/tests/start_monitor.sh b/runtime/tests/start_monitor.sh new file mode 100755 index 000000000..19c14b87c --- /dev/null +++ b/runtime/tests/start_monitor.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +function usage { + echo "$0 [pidstat file]" + exit 1 +} + +if [ $# != 1 ] ; then + usage + exit 1; +fi + +pidstat_file=$1 +sledge_pid=`ps -ef|grep "sledgert"|grep -v grep |awk '{print $2}'` +sleep 6 && pidstat -u -p $sledge_pid 1 1800 > $pidstat_file 2>&1 & diff --git a/runtime/tests/start_test.sh b/runtime/tests/start_test.sh index ccc1d597c..f4a94ece5 100755 --- a/runtime/tests/start_test.sh +++ b/runtime/tests/start_test.sh @@ -2,11 +2,11 @@ ulimit -n 655350 function usage { - echo "$0 [worker num] [listener num] [first worker core id] [dispatcher policy, SHINJUKU or EDF_INTERRUPT or DARC] [server log file]" + echo "$0 [worker num] [listener num] [first worker core id] [dispatcher policy, SHINJUKU or EDF_INTERRUPT or DARC] [server log file] [disable busy loop] [disable autoscaling]" exit 1 } -if [ $# != 5 ] ; then +if [ $# != 7 ] ; then usage exit 1; fi @@ -16,6 +16,9 @@ listener_num=$2 first_worker_core_id=$3 dispatcher_policy=$4 server_log=$5 +disable_busy_loop=$6 +disable_autoscaling=$7 +worker_group_size=$((worker_num / listener_num)) declare project_path="$( cd "$(dirname "$0")/../.." @@ -24,12 +27,14 @@ declare project_path="$( echo $project_path path=`pwd` export SLEDGE_DISABLE_PREEMPTION=true +export SLEDGE_DISABLE_BUSY_LOOP=$disable_busy_loop +export SLEDGE_DISABLE_AUTOSCALING=$disable_autoscaling #export SLEDGE_SIGALRM_HANDLER=TRIAGED export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=false export SLEDGE_FIRST_WORKER_COREID=$first_worker_core_id export SLEDGE_NWORKERS=$worker_num export SLEDGE_NLISTENERS=$listener_num -export SLEDGE_WORKER_GROUP_SIZE=3 +export SLEDGE_WORKER_GROUP_SIZE=$worker_group_size export SLEDGE_SCHEDULER=EDF #export SLEDGE_DISPATCHER=DARC export SLEDGE_DISPATCHER=$dispatcher_policy @@ -45,7 +50,7 @@ cd $project_path/runtime/bin #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/mulitple_linear_chain.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing3.json -LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/fib.json +LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/hash.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/empty.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/my_fibonacci.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_sodresize.json diff --git a/runtime/tests/stop_monitor.sh b/runtime/tests/stop_monitor.sh new file mode 100755 index 000000000..fa67a47b5 --- /dev/null +++ b/runtime/tests/stop_monitor.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +pid=`ps -ef|grep "pidstat"|grep -v grep |awk '{print $2}'` +echo $pid +kill -2 $pid From f2cb83434cc3ff79339d4b7031425046a15b8415 Mon Sep 17 00:00:00 2001 From: xiaosuGW Date: Mon, 29 Jan 2024 15:04:23 -0700 Subject: [PATCH 088/198] add start_single_request.sh empty.json and parse_power_consumption.py --- runtime/tests/empty.json | 23 ++++++ runtime/tests/parse_power_consumption.py | 94 ++++++++++++++++++++++++ runtime/tests/start_single_request.sh | 54 ++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 runtime/tests/empty.json create mode 100644 runtime/tests/parse_power_consumption.py create mode 100755 runtime/tests/start_single_request.sh diff --git a/runtime/tests/empty.json b/runtime/tests/empty.json new file mode 100644 index 000000000..acfa2f6bb --- /dev/null +++ b/runtime/tests/empty.json @@ -0,0 +1,23 @@ +[ + { + "name": "gwu", + "port": 31850, + "replenishment-period-us": 0, + "max-budget-us": 0, + "routes": [ + { + "route": "/empty", + "request-type": 1, + "n-resas": 2, + "path": "empty.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + } + ] + + } + +] + diff --git a/runtime/tests/parse_power_consumption.py b/runtime/tests/parse_power_consumption.py new file mode 100644 index 000000000..55e0a208d --- /dev/null +++ b/runtime/tests/parse_power_consumption.py @@ -0,0 +1,94 @@ +import re +import os +import sys +from collections import defaultdict + +sending_rate_dict = defaultdict(list) +service_rate_dict = defaultdict(list) + +#get all file names which contain key_str +def file_name(file_dir, key_str): + print(file_dir, key_str) + file_list = [] + rps_list = [] + + for root, dirs, files in os.walk(file_dir): + print("file:", files) + print("root:", root) + print("dirs:", dirs) + for file_i in files: + if file_i.find(key_str) >= 0: + full_path = os.path.join(os.getcwd() + "/" + root, file_i) + #print(full_path) + segs = file_i.split('-') + if len(segs) < 2: + continue + rps=segs[1] + print("rps---------", rps) + rps=rps.split(".")[0] + file_list.append(full_path) + rps_list.append(rps) + + file_list = sorted(file_list, key = lambda x: int(x.split('-')[-1].split(".")[0])) + rps_list = sorted(rps_list) + print(file_list) + print(rps_list) + return file_list, rps_list + +def get_values(key, files_list, core_energy_consum_dict, pkg_energy_consum_dict): + for file_i in files_list: + with open(file_i, 'r') as file: + print(file_i) + lines = file.readlines() + + core_line_index = next(i for i, line in enumerate(lines) if "Domain CORE" in line) + pkg_line_index = next(i for i, line in enumerate(lines) if "Domain PKG" in line) + + core_value = float(lines[core_line_index+1].split()[-2]) + pkg_value = float(lines[pkg_line_index+1].split()[-2]) + + #print("Domain CORE 的值:", core_value) + #print("Domain PKG 的值:", pkg_value) + + core_energy_consum_dict[key].append(core_value) + pkg_energy_consum_dict[key].append(pkg_value) + + +if __name__ == "__main__": + import json + #file_folders = ['SHINJUKU', 'SHINJUKU_25', 'DARC', 'EDF_SRSF_INTERRUPT'] + #file_folders = ['SHINJUKU_7', 'SHINJUKU_25', 'DARC', 'EDF_SRSF_INTERRUPT'] + #file_folders = ['SHINJUKU', 'DARC', 'EDF_SRSF_INTERRUPT'] + file_folders = ['EDF_INTERRUPT-disable-busy-loop-true-disable-autoscaling-true-27', 'EDF_INTERRUPT-disable-busy-loop-true-disable-autoscaling-false-27'] + #file_folders = ['EDF_INTERRUPT','EDF_SRSF_INTERRUPT_1'] + #file_folders = ['DARC', 'EDF_SRSF_INTERRUPT'] + #file_folders = ['SHINJUKU'] + core_energy_consum_dict = defaultdict(list) + pkg_energy_consum_dict = defaultdict(list) + rps_list = [] + + argv = sys.argv[1:] + if len(argv) < 1: + print("usage ", sys.argv[0], "[file key]") + sys.exit() + + for key in file_folders: + files_list, rps_list = file_name(key, argv[0]) + get_values(key, files_list, core_energy_consum_dict, pkg_energy_consum_dict) + + print("core consume:") + for key, value in core_energy_consum_dict.items(): + print(key, ":", value) + for key, value in pkg_energy_consum_dict.items(): + print(key, ":", value) + + js1 = json.dumps(core_energy_consum_dict) + f1 = open("core_consume.txt", 'w') + f1.write(js1) + f1.close() + + js2 = json.dumps(pkg_energy_consum_dict) + f2 = open("pkg_consume.txt", 'w') + f2.write(js2) + f2.close() + diff --git a/runtime/tests/start_single_request.sh b/runtime/tests/start_single_request.sh new file mode 100755 index 000000000..2d4687cda --- /dev/null +++ b/runtime/tests/start_single_request.sh @@ -0,0 +1,54 @@ +#!/bin/bash +ulimit -n 655350 + +function usage { + echo "$0 [worker num] [listener num] [first worker core id]" + exit 1 +} + +if [ $# != 3 ] ; then + usage + exit 1; +fi + +worker_num=$1 +listener_num=$2 +first_worker_core_id=$3 + +declare project_path="$( + cd "$(dirname "$0")/../.." + pwd +)" +echo $project_path +path=`pwd` +export SLEDGE_DISABLE_PREEMPTION=true +export SLEDGE_DISABLE_BUSY_LOOP=true +export SLEDGE_DISABLE_AUTOSCALING=true +export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=true +#export SLEDGE_SIGALRM_HANDLER=TRIAGED +export SLEDGE_FIRST_WORKER_COREID=$first_worker_core_id +export SLEDGE_NWORKERS=$worker_num +export SLEDGE_NLISTENERS=$listener_num +export SLEDGE_WORKER_GROUP_SIZE=1 +export SLEDGE_SCHEDULER=EDF +#export SLEDGE_DISPATCHER=DARC +#export SLEDGE_DISPATCHER=SHINJUKU +export SLEDGE_DISPATCHER=EDF_INTERRUPT +export SLEDGE_SANDBOX_PERF_LOG=$path/server.log +#echo $SLEDGE_SANDBOX_PERF_LOG +cd $project_path/runtime/bin +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_fibonacci.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_big_fibonacci.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_armcifar10.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_png2bmp.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_image_processing.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/mulitple_linear_chain.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing3.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/fib.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/hash.json +LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/empty.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/my_fibonacci.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_sodresize.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/my_sodresize.json + From 55b28d38da02ac72ffb1cf9bc408eebc952e5e57 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Mon, 29 Jan 2024 15:15:05 -0700 Subject: [PATCH 089/198] comment autoscaling logic code in listener_thread.c due to no benefit --- runtime/src/listener_thread.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index ad16ca21c..35c142086 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -577,23 +577,23 @@ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, thread_id = worker_list[true_idx]; } /* Check flag and if need to autoscale */ - if (runtime_autoscaling_enabled && - (min_waiting_serving_time + sandbox->estimated_cost + (wakeup_thread_cycles) >= sandbox->relative_deadline)) { - violate_deadline_workers++; - } + //if (runtime_autoscaling_enabled && + // (min_waiting_serving_time + sandbox->estimated_cost + (wakeup_thread_cycles) >= sandbox->relative_deadline)) { + // violate_deadline_workers++; + //} } } - + /* If no any worker can meet the current request deadline, scale up */ - if (runtime_autoscaling_enabled && current_active_workers < runtime_worker_group_size - && violate_deadline_workers == current_active_workers) { + //if (runtime_autoscaling_enabled && current_active_workers < runtime_worker_group_size + // && violate_deadline_workers == current_active_workers) { /* Add the current request to the scaling up worker */ - local_runqueue_add_index(current_active_workers, sandbox); - current_active_workers++; - printf("current_active_workers %d\n", current_active_workers); - return; - } - + // local_runqueue_add_index(current_active_workers, sandbox); + // current_active_workers++; + // printf("current_active_workers %d\n", current_active_workers); + // return; + //} + if (candidate_thread_with_interrupt != -1) { //urgent_request[candidate_thread_with_interrupt] = sandbox; local_runqueue_add_index(candidate_thread_with_interrupt, sandbox); From add0aea3297047dd3b74d4ff0429f5fefb5ab6ca Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 20 Mar 2024 12:25:50 -0600 Subject: [PATCH 090/198] update Makefile to let it checkout specified awsm code --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 929f95a86..809428a17 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ install: submodules wasm_apps all # aWsm: the WebAssembly to LLVM bitcode compiler .PHONY: awsm awsm: - cd awsm && cargo build --release + cd awsm && git checkout f0b35e756395f79b06be8dd2660eecac94506e94 && cargo build --release .PHONY: awsm.clean awsm.clean: From cc1181519ea3d41f655a7618389684a448fe4e23 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 20 Mar 2024 12:42:17 -0600 Subject: [PATCH 091/198] update start.sh --- runtime/tests/start.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/tests/start.sh b/runtime/tests/start.sh index 74bcafb26..3a5672fbf 100755 --- a/runtime/tests/start.sh +++ b/runtime/tests/start.sh @@ -24,7 +24,7 @@ path=`pwd` export SLEDGE_DISABLE_PREEMPTION=true export SLEDGE_DISABLE_BUSY_LOOP=true export SLEDGE_DISABLE_AUTOSCALING=true -export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=false +export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=true #export SLEDGE_SIGALRM_HANDLER=TRIAGED export SLEDGE_FIRST_WORKER_COREID=$first_worker_core_id export SLEDGE_NWORKERS=$worker_num From 1dc9e473455e821eae9ae3257ceab5f081d024d1 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 20 Mar 2024 14:04:49 -0600 Subject: [PATCH 092/198] update sledge main.c --- runtime/src/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/src/main.c b/runtime/src/main.c index a83db5013..cac70074d 100644 --- a/runtime/src/main.c +++ b/runtime/src/main.c @@ -569,7 +569,7 @@ int getUri(const char *interface, int port, char *uri) { // Append the port to the IP address in the same buffer int offset = strlen(uri); - snprintf(uri + offset, INET_ADDRSTRLEN - offset + 5, ":%d", port); + snprintf(uri + offset, INET_ADDRSTRLEN - offset + 6, ":%d", port); return 0; } @@ -589,7 +589,7 @@ main(int argc, char **argv) software_interrupt_initialize(); /* eRPC init */ - char server_uri[INET_ADDRSTRLEN + 5]; + char server_uri[INET_ADDRSTRLEN + 6]; if (getUri("ens1f0np0", 31850, server_uri) == 0) { printf("URI: %s\n", server_uri); From 696ebda24594aa6c94dfe7f3728401150e4e306a Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 11 Apr 2024 17:39:33 -0600 Subject: [PATCH 093/198] upload ori_sledge_tests --- runtime/tests/ori_sledge_tests/.gitignore | 11 + runtime/tests/ori_sledge_tests/curl.sh | 1 + runtime/tests/ori_sledge_tests/debug.sh | 33 +++ runtime/tests/ori_sledge_tests/empty.json | 21 ++ runtime/tests/ori_sledge_tests/fib.json | 29 +++ runtime/tests/ori_sledge_tests/hash.json | 33 +++ runtime/tests/ori_sledge_tests/id_rsa | 27 +++ runtime/tests/ori_sledge_tests/kill_sledge.sh | 7 + .../measure_old_sledge_cost.sh | 27 +++ .../meet_deadline_percentage.py | 219 ++++++++++++++++++ runtime/tests/ori_sledge_tests/old_sledge.log | 1 + runtime/tests/ori_sledge_tests/parse_batch.py | 153 ++++++++++++ .../tests/ori_sledge_tests/parse_cpu_batch.py | 78 +++++++ .../parse_power_consumption.py | 94 ++++++++ .../tests/ori_sledge_tests/parse_single.py | 58 +++++ runtime/tests/ori_sledge_tests/server.log | 8 + runtime/tests/ori_sledge_tests/start.sh | 40 ++++ .../tests/ori_sledge_tests/start_monitor.sh | 15 ++ .../tests/ori_sledge_tests/stop_monitor.sh | 5 + 19 files changed, 860 insertions(+) create mode 100644 runtime/tests/ori_sledge_tests/.gitignore create mode 100755 runtime/tests/ori_sledge_tests/curl.sh create mode 100755 runtime/tests/ori_sledge_tests/debug.sh create mode 100644 runtime/tests/ori_sledge_tests/empty.json create mode 100644 runtime/tests/ori_sledge_tests/fib.json create mode 100644 runtime/tests/ori_sledge_tests/hash.json create mode 100644 runtime/tests/ori_sledge_tests/id_rsa create mode 100755 runtime/tests/ori_sledge_tests/kill_sledge.sh create mode 100755 runtime/tests/ori_sledge_tests/measure_old_sledge_cost.sh create mode 100644 runtime/tests/ori_sledge_tests/meet_deadline_percentage.py create mode 100644 runtime/tests/ori_sledge_tests/old_sledge.log create mode 100644 runtime/tests/ori_sledge_tests/parse_batch.py create mode 100644 runtime/tests/ori_sledge_tests/parse_cpu_batch.py create mode 100644 runtime/tests/ori_sledge_tests/parse_power_consumption.py create mode 100644 runtime/tests/ori_sledge_tests/parse_single.py create mode 100644 runtime/tests/ori_sledge_tests/server.log create mode 100755 runtime/tests/ori_sledge_tests/start.sh create mode 100755 runtime/tests/ori_sledge_tests/start_monitor.sh create mode 100755 runtime/tests/ori_sledge_tests/stop_monitor.sh diff --git a/runtime/tests/ori_sledge_tests/.gitignore b/runtime/tests/ori_sledge_tests/.gitignore new file mode 100644 index 000000000..d786eca17 --- /dev/null +++ b/runtime/tests/ori_sledge_tests/.gitignore @@ -0,0 +1,11 @@ +res +perf.data +perf.data.old +samples +perf.log +http_perf.log +log.csv +*res.dat +result.dat +result.jpg +rt.log diff --git a/runtime/tests/ori_sledge_tests/curl.sh b/runtime/tests/ori_sledge_tests/curl.sh new file mode 100755 index 000000000..ca8d2bae3 --- /dev/null +++ b/runtime/tests/ori_sledge_tests/curl.sh @@ -0,0 +1 @@ +curl -I -w "Total time: %{time_total}s\n" http://10.10.1.1:31850/empty diff --git a/runtime/tests/ori_sledge_tests/debug.sh b/runtime/tests/ori_sledge_tests/debug.sh new file mode 100755 index 000000000..3e87c2bbd --- /dev/null +++ b/runtime/tests/ori_sledge_tests/debug.sh @@ -0,0 +1,33 @@ +#!/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 +)" +path=`pwd` +echo $project_path +cd $project_path/runtime/bin +export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=true +export SLEDGE_DISABLE_PREEMPTION=true +export SLEDGE_SANDBOX_PERF_LOG=$path/srsf.log +export SLEDGE_NWORKERS=9 +export SLEDGE_FIRST_WORKER_COREID=4 +export SLEDGE_NLISTENERS=3 +export SLEDGE_WORKER_GROUP_SIZE=3 +#export SLEDGE_DISPATCHER=DARC +export SLEDGE_DISPATCHER=EDF_INTERRUPT +#export SLEDGE_DISPATCHER=SHINJUKU +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/runtime" \ +# --eval-command="run ../tests/fib.json" +# ./sledgert + +gdb --eval-command="handle SIGUSR1 nostop" \ + --eval-command="handle SIGUSR1 noprint" \ + ./sledgert diff --git a/runtime/tests/ori_sledge_tests/empty.json b/runtime/tests/ori_sledge_tests/empty.json new file mode 100644 index 000000000..d449eb563 --- /dev/null +++ b/runtime/tests/ori_sledge_tests/empty.json @@ -0,0 +1,21 @@ +[ + { + "name": "gwu", + "port": 31850, + "replenishment-period-us": 0, + "max-budget-us": 0, + "routes": [ + { + "route": "/empty", + "path": "empty.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + } + ] + + } + +] + diff --git a/runtime/tests/ori_sledge_tests/fib.json b/runtime/tests/ori_sledge_tests/fib.json new file mode 100644 index 000000000..a5840cc95 --- /dev/null +++ b/runtime/tests/ori_sledge_tests/fib.json @@ -0,0 +1,29 @@ +[ + { + "name": "gwu", + "port": 31850, + "replenishment-period-us": 0, + "max-budget-us": 0, + "routes": [ + { + "route": "/fib", + "path": "fibonacci.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib2", + "path": "fibonacci.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 6480, + "relative-deadline-us": 64800, + "http-resp-content-type": "text/plain" + } + ] + + } + +] + diff --git a/runtime/tests/ori_sledge_tests/hash.json b/runtime/tests/ori_sledge_tests/hash.json new file mode 100644 index 000000000..8c6212132 --- /dev/null +++ b/runtime/tests/ori_sledge_tests/hash.json @@ -0,0 +1,33 @@ +[ + { + "name": "gwu", + "port": 31850, + "replenishment-period-us": 0, + "max-budget-us": 0, + "routes": [ + { + "route": "/hash", + "request-type": 1, + "n-resas": 2, + "path": "hash.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 5, + "relative-deadline-us": 50, + "http-resp-content-type": "text/plain" + }, + { + "route": "/hash2", + "request-type": 2, + "n-resas": 1, + "path": "hash.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 6480, + "relative-deadline-us": 64800, + "http-resp-content-type": "text/plain" + } + ] + + } + +] + diff --git a/runtime/tests/ori_sledge_tests/id_rsa b/runtime/tests/ori_sledge_tests/id_rsa new file mode 100644 index 000000000..832cdbcd4 --- /dev/null +++ b/runtime/tests/ori_sledge_tests/id_rsa @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEoQIBAAKCAQEA2bxGJUQa7ywL7I6prE75oA2fE/AfTHTi5KzUEh+LezA/KObP +Aa7FgcWUu/QiwCz/aVMvIeVms7CZuu/QJJ9TEinSdxjHixoNhZvbBgLhweCje2YR +MUl9ynPsaVZwb/DebloVzlweXRkXKLCfx3s+HXDSHMpDgMhbF5AiehxQCXCUrNzE +/e6d217PmX02+VRQPwVWycu5/Mi+mMvlgN/e1XggHDYhvX6t4U0Am5KZ4kqdxXYP +T0x6gXxcLi6Ulb15LNCqbbdbFhfYg+tWlqxqIyTHJO2kSw4VNINxIR0dT5FYbxFV +4DL9msYQ+ePXUUym3LnPix0Bt9EQLPMeewYhYwIBIwKCAQAlU3m9PuALvmhxsg51 +T13+LjiHEziQw5ScOuKGw5RBAPTicLXFxjB8pYc2KdoSUNtT4l/Z7M/HCFTeN71I +G1ARvgbSloibgM8eN/mpQlKWQ8RBCi7VP8xr2Vu6SVUagRAwLLNH8ojcwnj/qT/2 +T6Q/j679nwRB9nYEChSJ9jmbN437tvrLSE1ZxvUIzV96Sd9aGaOjg4Ezyb7KqGSR +0pFKiufTAoAtUcpQ/hYrQ88KFgbFFNm4yRz0dfNpOekdio/IXs2WZ8688k8aZ1OS +DDmFiMLyHxZmp6s5d2pJsLQBIGGWMqxm7a2xeJHY6oLc3DVIRfoJqkFDNWXLlPyR +eBAbAoGBAPPvG4koPGbJ7MoJF6DXTg8bjdXDCPhKL5JoU7y/OX7vKdYLX69RYxs+ +ubILTM/7TTC33nEhqty+GWVVOkwOlap99vmWp2hhrjelLYPJmUsQ7aMWUM2Fsxcw +S/NH8RUeaM0F1QqwJEDbdvKjOrgteVQmtPaFo8LFHKmyHF1PsrQ/AoGBAOSBay+J +Nx6FvsWHt5PYrKpAjJvM7lAEgFM89zNvBLsIzqxsnTFjvnZ0ySKT5OeBfPA6nf13 +tx+GsurzIniwKjKeBgGUXRIQ5CjEuGtOdnox7rLfkiluiOyKVDyApUN/66d9FLLX +pEeJZSDlUSPGJBvlwfvNGBeVUj9XRv/awbndAoGAfXOnwuF+Jjv2HsLY86HtoV6g +txPYujTIAicGflO3K1ZtSYIxNZeSDgMAajGyeZcvAxy7iqOZs1pzdfFRLm3mkjIn +Pof+UvBoOd/rhZrhH0qI14fRyMhqu3fsi76ZPg+jnKPp6D1UeSBpDxIeMtWO2tIT +7H8+RukHbTcHRe55KX8CgYEAlikpLd3Tw5m34OQoLfTJPK4TQc/Pzi7X/C9gniRi +McP1h0APhtslY8kWdc7m4UZ2rH5KkJ8gkQ9fobW3kSNO7hASk1LeEy+r4EbCVSTu +xVQDQlhnXQ4fdt6PIHHLsAOa28c5fNbZq1pJxSj6zl2isz82VQMedeXIVYJ/HSla +u/cCgYAMNf9At68UjxBECLQOxfLU2GtJBQMP1r3QJzz6/PJqctgJZWzDL/SIg24F +hp6cEaaCiUYV158IShdeTUZpai7UNooQ9wijDYYcodXE/9HnNGgVjP+YqvpnizGx +yFiYiEcowoetWDVOkDzGHDVAtHdwlWBc4D4frJ5kNipMlEEw5Q== +-----END RSA PRIVATE KEY----- diff --git a/runtime/tests/ori_sledge_tests/kill_sledge.sh b/runtime/tests/ori_sledge_tests/kill_sledge.sh new file mode 100755 index 000000000..8069a8593 --- /dev/null +++ b/runtime/tests/ori_sledge_tests/kill_sledge.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +pid=`ps -ef|grep "sledgert"|grep -v grep |awk '{print $2}'` +echo $pid +sudo kill -2 $pid +sleep 2 +sudo kill -9 $pid diff --git a/runtime/tests/ori_sledge_tests/measure_old_sledge_cost.sh b/runtime/tests/ori_sledge_tests/measure_old_sledge_cost.sh new file mode 100755 index 000000000..6c6c6f31f --- /dev/null +++ b/runtime/tests/ori_sledge_tests/measure_old_sledge_cost.sh @@ -0,0 +1,27 @@ +#!/bin/bash +function usage { + echo "$0 [repeat count]" + exit 1 +} + +if [ $# != 1 ] ; then + usage + exit 1; +fi + +chmod 400 ./id_rsa +remote_ip="10.10.1.1" + +repeat_count=$1 +> old_sledge.log + +path="/my_mount/ori_sledge/sledge-serverless-framework/runtime/tests" +for(( i=0;i<$repeat_count;i++ )) do + echo "i is $i" + echo "start server..." + ssh -o stricthostkeychecking=no -i ./id_rsa xiaosuGW@$remote_ip "$path/start.sh > 1.txt 2>&1 &" + sleep 1 + echo "start client..." + ./curl.sh >> old_sledge.log + ssh -o stricthostkeychecking=no -i ./id_rsa xiaosuGW@$remote_ip "$path/kill_sledge.sh" +done diff --git a/runtime/tests/ori_sledge_tests/meet_deadline_percentage.py b/runtime/tests/ori_sledge_tests/meet_deadline_percentage.py new file mode 100644 index 000000000..d685673da --- /dev/null +++ b/runtime/tests/ori_sledge_tests/meet_deadline_percentage.py @@ -0,0 +1,219 @@ +import sys +import json +from collections import defaultdict +import numpy as np + +def def_list_value(): + return [0, 0, 0, 0, 0] +def def_value(): + return 0 + +def count_miss_or_meet_deadline_requests(file_dir, percentage): + throughput = 0; + max_exe_time = 0 + ### each time for a request + request_times_dict = defaultdict(def_list_value) + #### get execution time + running_time_dict = defaultdict(def_value) + queuing_times_dict = defaultdict(def_value) + total_times_dict = defaultdict(def_value) + runnable_times_dict = defaultdict(def_value) + blocked_times_dict = defaultdict(def_value) + initializing_times_dict = defaultdict(def_value) + execution_times_dict = defaultdict(def_value) + + ### init overhead + ### queuelength + queuelength_dict = defaultdict(list) + ### + running_times = defaultdict(list) + queuing_times = defaultdict(list) + thread_running_times = defaultdict(list) + total_times = defaultdict(list) + thread_times = defaultdict(list) + thread_throughput = defaultdict(list) + t2_cleanup = defaultdict(list) + runnable_times = defaultdict(list) + blocked_times = defaultdict(list) + initializing_times = defaultdict(list) + execution_times = defaultdict(list) + #### + request_counter = defaultdict(def_value) + total_time_dist = defaultdict(list) + total_time_list = [] + total_slow_down = [] + total_workload_dist = defaultdict(def_value) + total_real_time_workload_dist = defaultdict(def_value) + real_time_workload_times_dist = defaultdict(list) + real_time_workload_workloads_dist = defaultdict(list) + real_time_workload_requests_dist = defaultdict(list) + min_time = sys.maxsize + # list[0] is meet deadline number, list[1] is miss deadline number + delays_dict = defaultdict(list) + max_latency_dist = defaultdict(def_value) + total_deadline = 0 + miss_deadline_dist = defaultdict(def_value) + meet_deadline_dist = defaultdict(def_value) + meet_deadline = 0 + miss_deadline = 0 + max_sc = 0 + total_interrupts = 0; + fo = open(file_dir, "r+") + for line in fo: + line = line.strip() + if "meet" in line: + meet_deadline += 1 + name = line.split(" ")[7] + cleanup = line.split(" ")[9] + deadline = int(line.split(" ")[10]) + name = name[1:] + tid = line.split(" ")[1] + request_counter[name] += 1 + total_time = int(line.split(" ")[4]) + total_time_dist[name].append(total_time) + if name == "fib": + total_slow_down.append(round((float(total_time) / deadline), 2)) + else: + total_slow_down.append(round((float(total_time) / deadline), 2)) + total_time_list.append(total_time) + thread_times[tid].append(total_time) + if total_time > max_latency_dist[name]: + max_latency_dist[name] = total_time + meet_deadline_dist[name] += 1 + exe_time = int(line.split(" ")[5]) + if exe_time > max_exe_time: + max_exe_time = exe_time + running_times[name].append(exe_time); + queue_time = int(line.split(" ")[6]) + queuing_times[name].append(queue_time); + thread_running_times[tid].append(exe_time); + t2_cleanup[tid].append(cleanup) + if "miss" in line: + miss_deadline += 1 + name = line.split(" ")[7] + cleanup = line.split(" ")[9] + deadline = int(line.split(" ")[10]) + name = name[1:] + tid = line.split(" ")[1] + total_time = int(line.split(" ")[4]) + if total_time > max_latency_dist[name]: + max_latency_dist[name] = total_time + request_counter[name] += 1 + total_time_dist[name].append(total_time) + total_time_list.append(total_time) + if name == "fib": + total_slow_down.append(round((float(total_time) / deadline), 2)) + else: + total_slow_down.append(round((float(total_time) / deadline), 2)) + thread_times[tid].append(total_time) + miss_deadline_dist[name] += 1 + exe_time = line.split(" ")[5] + exe_time = int(line.split(" ")[5]) + if exe_time > max_exe_time: + max_exe_time = exe_time + running_times[name].append(exe_time); + queue_time = int(line.split(" ")[6]) + queuing_times[name].append(queue_time); + thread_running_times[tid].append(exe_time); + t2_cleanup[tid].append(cleanup) + #print("name:", name) + if "throughput" in line: + throughput = line.split(" ")[1] + interrupt = line.split(" ")[15] + total_interrupts += int(interrupt); + ### calculate the execution time + #if "memory" in line or "total_time" in line or "min" in line or "miss" in line or "meet" in line or "time " in line or "scheduling count" in line or "thread id" in line: + # continue + if "pthroughput" in line: + tid = line.split(" ")[2] + throughput = line.split(" ")[3] + thread_throughput[tid].append(throughput) + + miss_deadline_percentage = (miss_deadline * 100) / (miss_deadline + meet_deadline) + print("meet deadline num:", meet_deadline) + print("miss deadline num:", miss_deadline) + print("total requests:", meet_deadline + miss_deadline) + print("miss deadline percentage:", miss_deadline_percentage) + print("throughput:", throughput) + print("total interrupts:", total_interrupts) + + for key,value in request_counter.items(): + print(key, ":", str(value), "proportion:", (100*value)/(meet_deadline + miss_deadline)) + for key,value in total_time_dist.items(): + a = np.array(value) + p = np.percentile(a, int(percentage)) + print(key + " " + percentage + " percentile is:" + str(p) + " mean is:" + str(np.mean(value)) + " max latency is:" + str(max_latency_dist[key])) + #total_cpu_times = 0 + for key,value in meet_deadline_dist.items(): + # total_cpu_times += value * fun_execution_time[key] + miss_value = miss_deadline_dist[key] + total_request = miss_value + value + miss_rate = (miss_value * 100) / total_request + + print(key + " miss deadline rate:" + str(miss_rate)); + # print(func_name_dict[key] + " miss deadline rate:" + str(miss_rate) + " miss count is:" + str(miss_value) + " total request:" + str(total_request)) + #print("effective total cpu times:", total_cpu_times) + #for key,value in real_time_workload_times_dist.items(): + # real_time_workload_times_dist[key] = [x - min_time for x in value] + + for key,value in running_times.items(): + #print("function times:", func_name_with_id[key], np.median(total_times[key]), np.median(running_times[key]), np.median(queuing_times[key]), np.median(runnable_times[key]), np.median(blocked_times[key]), np.median(initializing_times[key])) + print("function :", key, "median total:", np.median(total_time_dist[key]), "exec:", np.median(running_times[key]), "queue:", np.median(queuing_times[key])) + print(len(value)) + print(len(queuing_times[key])) + print(len(total_time_dist[key])) + total_time_array = np.array(total_time_list) + p_99 = np.percentile(total_time_array, 99) + p_99_9 = np.percentile(total_time_array, 99.9) + p_99_99 = np.percentile(total_time_array, 99.99) + print("99 percentile latency is ", p_99) + print("99.9 percentile latency is ", p_99_9) + print("99.99 percentile latency is ", p_99_99) + total_time_slow_down = np.array(total_slow_down) + p_99_slow_down = np.percentile(total_time_slow_down, 99) + p_99_9_slow_down = np.percentile(total_time_slow_down, 99.9) + p_99_99_slow_down = np.percentile(total_time_slow_down, 99.99) + print("99 percentile slow down is ", p_99_slow_down) + print("99.9 percentile slow down is ", p_99_9_slow_down) + print("99.99 percentile slow down is ", p_99_99_slow_down) + print("max exe time:", max_exe_time) + js_latency = json.dumps(total_time_list) + f_latency = open("total_time_list.txt", 'w') + f_latency.write(js_latency) + f_latency.close() + js = json.dumps(total_time_dist) + f = open("total_time.txt", 'w') + f.write(js) + f.close() + + js1 = json.dumps(queuing_times) + f1 = open("queuing_time.txt", 'w') + f1.write(js1) + f1.close() + + js5 = json.dumps(thread_running_times) + f5 = open("running_time.txt", 'w') + f5.write(js5) + f5.close() + + js2 = json.dumps(thread_times) + f2 = open("thread_time.txt", 'w') + f2.write(js2) + f2.close() + + js3 = json.dumps(thread_throughput) + f3 = open("thread_throughput.txt", 'w') + f3.write(js3) + f3.close() + + js4 = json.dumps(t2_cleanup) + f4 = open("cleanup.txt", 'w') + f4.write(js4) + f4.close() + +if __name__ == "__main__": + argv = sys.argv[1:] + if len(argv) < 1: + print("usage ", sys.argv[0], " " " ") + sys.exit() + count_miss_or_meet_deadline_requests(argv[0], argv[1]) diff --git a/runtime/tests/ori_sledge_tests/old_sledge.log b/runtime/tests/ori_sledge_tests/old_sledge.log new file mode 100644 index 000000000..c09f84f29 --- /dev/null +++ b/runtime/tests/ori_sledge_tests/old_sledge.log @@ -0,0 +1 @@ +Total time: 0.000415s diff --git a/runtime/tests/ori_sledge_tests/parse_batch.py b/runtime/tests/ori_sledge_tests/parse_batch.py new file mode 100644 index 000000000..8fbca84db --- /dev/null +++ b/runtime/tests/ori_sledge_tests/parse_batch.py @@ -0,0 +1,153 @@ +import re +import os +import sys +from collections import defaultdict + +#get all file names which contain key_str +def file_name(file_dir, key_str): + print(file_dir, key_str) + file_list = [] + rps_list = [] + + for root, dirs, files in os.walk(file_dir): + print(files, root, dirs) + for file_i in files: + if file_i.find(key_str) >= 0: + full_path = os.path.join(os.getcwd() + "/" + root, file_i) + #print(full_path) + segs = file_i.split('-') + if len(segs) < 2: + continue + rps=segs[1] + rps=rps.split(".")[0] + file_list.append(full_path) + rps_list.append(rps) + + file_list = sorted(file_list, key = lambda x: int(x.split('-')[-1].split(".")[0])) + rps_list = sorted(rps_list) + print(file_list) + print(rps_list) + return file_list, rps_list + +def get_values(key, files_list, latency_dict, slow_down_dict, slow_down_99_9_dict, latency_99_9_dict, slow_down_99_99_dict, latency_99_99_dict): + for file_i in files_list: + cmd='sudo python3 ./meet_deadline_percentage.py %s 99' % file_i + rt=os.popen(cmd).read().strip() + print(rt) + # Define regular expressions to match the desired values + latency_rule = r'99 percentile latency is\s*([\d.]+)' + slow_down_rule = r'99 percentile slow down is\s*([\d.]+)' + latency_99_9_rule = r'99.9 percentile latency is\s*([\d.]+)' + slow_down_99_9_rule = r'99.9 percentile slow down is\s*([\d.]+)' + latency_99_99_rule = r'99.99 percentile latency is\s*([\d.]+)' + slow_down_99_99_rule = r'99.99 percentile slow down is\s*([\d.]+)' + + # Use the regular expressions to find the values + latency_match = re.search(latency_rule, rt) + slow_down_match = re.search(slow_down_rule, rt) + latency_99_9_match = re.search(latency_99_9_rule, rt) + slow_down_99_9_match = re.search(slow_down_99_9_rule, rt) + latency_99_99_match = re.search(latency_99_99_rule, rt) + slow_down_99_99_match = re.search(slow_down_99_99_rule, rt) + + # Check if matches were found and extract the values + if latency_match: + latency_value = 0 + latency_value = latency_match.group(1) + print("99th latency is:", latency_value) + latency_dict[key].append(latency_value) + + if slow_down_match: + slow_down_value = 0 + slow_down_value = slow_down_match.group(1) + print("99th slow down is:", slow_down_value) + slow_down_dict[key].append(slow_down_value) + + if latency_99_9_match: + latency_value = 0 + latency_value = latency_99_9_match.group(1) + print("99.9th latency is:", latency_value) + latency_99_9_dict[key].append(latency_value) + + if slow_down_99_9_match: + slow_down_value = 0 + slow_down_value = slow_down_99_9_match.group(1) + print("99.9th slow down is:", slow_down_value) + slow_down_99_9_dict[key].append(slow_down_value) + + if latency_99_99_match: + latency_value = 0 + latency_value = latency_99_99_match.group(1) + print("99.99th latency is:", latency_value) + latency_99_99_dict[key].append(latency_value) + + if slow_down_99_99_match: + slow_down_value = 0 + slow_down_value = slow_down_99_99_match.group(1) + print("99.99th slow down is:", slow_down_value) + slow_down_99_99_dict[key].append(slow_down_value) + +if __name__ == "__main__": + import json + #file_folders = ['SHINJUKU', 'SHINJUKU_25', 'DARC', 'EDF_SRSF_INTERRUPT'] + file_folders = ['SHINJUKU_5', 'SHINJUKU_100', 'SHINJUKU_200', 'SHINJUKU_25', 'DARC', 'EDF_SRSF_INTERRUPT'] + #file_folders = ['SHINJUKU'] + latency = defaultdict(list) + slow_down = defaultdict(list) + slow_down_99_9 = defaultdict(list) + latency_99_9 = defaultdict(list) + slow_down_99_99 = defaultdict(list) + latency_99_99 = defaultdict(list) + + rps_list = [] + + argv = sys.argv[1:] + if len(argv) < 1: + print("usage ", sys.argv[0], "[file key]") + sys.exit() + + for key in file_folders: + files_list, rps_list = file_name(key, argv[0]) + get_values(key, files_list, latency, slow_down, slow_down_99_9, latency_99_9, slow_down_99_99, latency_99_99) + + print("99 latency:") + for key, value in latency.items(): + print(key, ":", value) + print("99 slow down:") + for key, value in slow_down.items(): + print(key, ":", value) + + js1 = json.dumps(latency) + f1 = open("99_latency.txt", 'w') + f1.write(js1) + f1.close() + + js2 = json.dumps(slow_down) + f2 = open("99_slow_down.txt", 'w') + f2.write(js2) + f2.close() + + js4 = json.dumps(latency_99_9) + f4 = open("99_9_latency.txt", 'w') + f4.write(js4) + f4.close() + + js5 = json.dumps(slow_down_99_9) + f5 = open("99_9_slow_down.txt", 'w') + f5.write(js5) + f5.close() + + js6 = json.dumps(latency_99_99) + f6 = open("99_99_latency.txt", 'w') + f6.write(js6) + f6.close() + + js7 = json.dumps(slow_down_99_99) + f7 = open("99_99_slow_down.txt", 'w') + f7.write(js7) + f7.close() + + js3 = json.dumps(rps_list) + f3 = open("rps.txt", 'w') + f3.write(js3) + f3.close() diff --git a/runtime/tests/ori_sledge_tests/parse_cpu_batch.py b/runtime/tests/ori_sledge_tests/parse_cpu_batch.py new file mode 100644 index 000000000..1be6c1212 --- /dev/null +++ b/runtime/tests/ori_sledge_tests/parse_cpu_batch.py @@ -0,0 +1,78 @@ +import re +import os +import sys +from collections import defaultdict + +sending_rate_dict = defaultdict(list) +service_rate_dict = defaultdict(list) + +#get all file names which contain key_str +def file_name(file_dir, key_str): + print(file_dir, key_str) + file_list = [] + rps_list = [] + + for root, dirs, files in os.walk(file_dir): + print("file:", files) + print("root:", root) + print("dirs:", dirs) + for file_i in files: + if file_i.find(key_str) >= 0: + full_path = os.path.join(os.getcwd() + "/" + root, file_i) + #print(full_path) + segs = file_i.split('-') + if len(segs) < 2: + continue + rps=segs[1] + print("rps---------", rps) + rps=rps.split(".")[0] + file_list.append(full_path) + rps_list.append(rps) + + file_list = sorted(file_list, key = lambda x: int(x.split('-')[-1].split(".")[0])) + rps_list = sorted(rps_list) + print(file_list) + print(rps_list) + return file_list, rps_list + +def get_values(key, files_list, cpu_usages_dict): + for file_i in files_list: + cmd="awk '/Average:/ {print $8}' %s" % file_i + rt=os.popen(cmd).read().strip() + cpu_count=float(rt)/100 + cpu_count=round(cpu_count, 2) + print(cpu_count) + cpu_usages_dict[key].append(cpu_count) + + +if __name__ == "__main__": + import json + #file_folders = ['SHINJUKU', 'SHINJUKU_25', 'DARC', 'EDF_SRSF_INTERRUPT'] + #file_folders = ['SHINJUKU_7', 'SHINJUKU_25', 'DARC', 'EDF_SRSF_INTERRUPT'] + #file_folders = ['SHINJUKU', 'DARC', 'EDF_SRSF_INTERRUPT'] + file_folders = ['EDF_INTERRUPT-disable-busy-loop-false-disable-autoscaling-true-9','EDF_INTERRUPT-disable-busy-loop-true-disable-autoscaling-false-9', 'EDF_INTERRUPT-disable-busy-loop-true-disable-autoscaling-true-27'] + #file_folders = ['EDF_INTERRUPT','EDF_SRSF_INTERRUPT_1'] + #file_folders = ['DARC', 'EDF_SRSF_INTERRUPT'] + #file_folders = ['SHINJUKU'] + cpu_usages_dict = defaultdict(list) + rps_list = [] + + argv = sys.argv[1:] + if len(argv) < 1: + print("usage ", sys.argv[0], "[file key]") + sys.exit() + + for key in file_folders: + files_list, rps_list = file_name(key, argv[0]) + get_values(key, files_list, cpu_usages_dict) + + print("cpu usage:") + for key, value in cpu_usages_dict.items(): + print(key, ":", value) + + js1 = json.dumps(cpu_usages_dict) + f1 = open("cpu.txt", 'w') + f1.write(js1) + f1.close() + + diff --git a/runtime/tests/ori_sledge_tests/parse_power_consumption.py b/runtime/tests/ori_sledge_tests/parse_power_consumption.py new file mode 100644 index 000000000..55e0a208d --- /dev/null +++ b/runtime/tests/ori_sledge_tests/parse_power_consumption.py @@ -0,0 +1,94 @@ +import re +import os +import sys +from collections import defaultdict + +sending_rate_dict = defaultdict(list) +service_rate_dict = defaultdict(list) + +#get all file names which contain key_str +def file_name(file_dir, key_str): + print(file_dir, key_str) + file_list = [] + rps_list = [] + + for root, dirs, files in os.walk(file_dir): + print("file:", files) + print("root:", root) + print("dirs:", dirs) + for file_i in files: + if file_i.find(key_str) >= 0: + full_path = os.path.join(os.getcwd() + "/" + root, file_i) + #print(full_path) + segs = file_i.split('-') + if len(segs) < 2: + continue + rps=segs[1] + print("rps---------", rps) + rps=rps.split(".")[0] + file_list.append(full_path) + rps_list.append(rps) + + file_list = sorted(file_list, key = lambda x: int(x.split('-')[-1].split(".")[0])) + rps_list = sorted(rps_list) + print(file_list) + print(rps_list) + return file_list, rps_list + +def get_values(key, files_list, core_energy_consum_dict, pkg_energy_consum_dict): + for file_i in files_list: + with open(file_i, 'r') as file: + print(file_i) + lines = file.readlines() + + core_line_index = next(i for i, line in enumerate(lines) if "Domain CORE" in line) + pkg_line_index = next(i for i, line in enumerate(lines) if "Domain PKG" in line) + + core_value = float(lines[core_line_index+1].split()[-2]) + pkg_value = float(lines[pkg_line_index+1].split()[-2]) + + #print("Domain CORE 的值:", core_value) + #print("Domain PKG 的值:", pkg_value) + + core_energy_consum_dict[key].append(core_value) + pkg_energy_consum_dict[key].append(pkg_value) + + +if __name__ == "__main__": + import json + #file_folders = ['SHINJUKU', 'SHINJUKU_25', 'DARC', 'EDF_SRSF_INTERRUPT'] + #file_folders = ['SHINJUKU_7', 'SHINJUKU_25', 'DARC', 'EDF_SRSF_INTERRUPT'] + #file_folders = ['SHINJUKU', 'DARC', 'EDF_SRSF_INTERRUPT'] + file_folders = ['EDF_INTERRUPT-disable-busy-loop-true-disable-autoscaling-true-27', 'EDF_INTERRUPT-disable-busy-loop-true-disable-autoscaling-false-27'] + #file_folders = ['EDF_INTERRUPT','EDF_SRSF_INTERRUPT_1'] + #file_folders = ['DARC', 'EDF_SRSF_INTERRUPT'] + #file_folders = ['SHINJUKU'] + core_energy_consum_dict = defaultdict(list) + pkg_energy_consum_dict = defaultdict(list) + rps_list = [] + + argv = sys.argv[1:] + if len(argv) < 1: + print("usage ", sys.argv[0], "[file key]") + sys.exit() + + for key in file_folders: + files_list, rps_list = file_name(key, argv[0]) + get_values(key, files_list, core_energy_consum_dict, pkg_energy_consum_dict) + + print("core consume:") + for key, value in core_energy_consum_dict.items(): + print(key, ":", value) + for key, value in pkg_energy_consum_dict.items(): + print(key, ":", value) + + js1 = json.dumps(core_energy_consum_dict) + f1 = open("core_consume.txt", 'w') + f1.write(js1) + f1.close() + + js2 = json.dumps(pkg_energy_consum_dict) + f2 = open("pkg_consume.txt", 'w') + f2.write(js2) + f2.close() + diff --git a/runtime/tests/ori_sledge_tests/parse_single.py b/runtime/tests/ori_sledge_tests/parse_single.py new file mode 100644 index 000000000..c7107adb4 --- /dev/null +++ b/runtime/tests/ori_sledge_tests/parse_single.py @@ -0,0 +1,58 @@ +import re +import os +import sys +from collections import defaultdict + +#get all file names which contain key_str +def file_name(file_dir, key_str): + throughput_table = defaultdict(list) + errors_table = defaultdict(list) + for root, dirs, files in os.walk(file_dir): + if root != os.getcwd(): + continue + for file_i in files: + if file_i.find(key_str) >= 0: + segs = file_i.split('-') + if len(segs) < 3: + continue + #print(file_i) + cores_num = segs[1] + concurrency = segs[3].split(".")[0] + print("core:", cores_num, " concurrency:", concurrency) + get_values(cores_num, concurrency, file_i, throughput_table, errors_table) + #file_table[key].append(file_i) + s_result = sorted(throughput_table.items()) + for i in range(len(s_result)): + print(s_result[i], "errors request:", errors_table[s_result[i][0]]) + for i in range(len(s_result)): + print(int(float(((s_result[i][1][0])))),end=" ") + print(); + #sys.exit() + +def get_values(core, concurrency, file_name, throughput_table, errors_table): + fo = open(file_name, "r+") + total_throughput = 0 + for line in fo: + line = line.strip() + if "throughput is" in line: + print("line is ", line); + i_th = float(line.split(" ")[2]) + total_throughput += i_th + throughput_table[int(core)].append(total_throughput) + break; + + print("throughput:", total_throughput) + + +if __name__ == "__main__": + import json + argv = sys.argv[1:] + if len(argv) < 1: + print("usage ", sys.argv[0], " file containing key word") + sys.exit() + + file_name(os.getcwd(), argv[0]) + + for key, value in files_tables.items(): + get_values(key, value, miss_deadline_rate, total_latency, running_times, preemption_count, total_miss_deadline_rate) + diff --git a/runtime/tests/ori_sledge_tests/server.log b/runtime/tests/ori_sledge_tests/server.log new file mode 100644 index 000000000..a749ba460 --- /dev/null +++ b/runtime/tests/ori_sledge_tests/server.log @@ -0,0 +1,8 @@ +id,tenant,route,state,deadline,actual,queued,uninitialized,allocated,initialized,runnable,interrupted,preempted,running_sys,running_user,asleep,returned,complete,error,proc_MHz,memory +1,gwu,/empty,Complete,32400,153009,56541,0,447,56094,846,0,0,23899,71746,0,149836,0,0,3240 +2,gwu,/empty,Complete,32400,112424,46060,0,728,45332,587,0,0,14593,51231,0,128333,0,0,3240 +3,gwu,/empty,Complete,32400,141963,58233,0,728,57505,329,0,0,17530,65918,0,105633,0,0,3240 +4,gwu,/empty,Complete,32400,149483,74730,0,493,74237,305,0,0,19106,55389,0,102531,0,0,3240 +5,gwu,/empty,Complete,32400,28717,12925,0,494,12431,564,0,0,9283,5969,0,66951,0,0,3240 +6,gwu,/empty,Complete,32400,24111,7919,0,423,7496,1058,0,0,9447,5710,0,62064,0,0,3240 +7,gwu,/empty,Complete,32400,30527,15581,0,470,15111,329,0,0,8577,6063,0,65988,0,0,3240 diff --git a/runtime/tests/ori_sledge_tests/start.sh b/runtime/tests/ori_sledge_tests/start.sh new file mode 100755 index 000000000..c02f056c8 --- /dev/null +++ b/runtime/tests/ori_sledge_tests/start.sh @@ -0,0 +1,40 @@ +#!/bin/bash +ulimit -n 655350 + +function usage { + echo "$0" + exit 1 +} + +if [ $# != 0 ] ; then + usage + exit 1; +fi + +declare project_path="$( + cd "$(dirname "$0")/../.." + pwd +)" +echo $project_path +path=`pwd` +export SLEDGE_DISABLE_PREEMPTION=true +#export SLEDGE_SIGALRM_HANDLER=TRIAGED +export SLEDGE_SCHEDULER=EDF +export SLEDGE_SANDBOX_PERF_LOG=$path/server.log +#echo $SLEDGE_SANDBOX_PERF_LOG +cd $project_path/runtime/bin +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_fibonacci.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_big_fibonacci.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_armcifar10.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_png2bmp.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_image_processing.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/mulitple_linear_chain.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing3.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/fib.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/hash.json +LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/empty.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/my_fibonacci.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_sodresize.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/my_sodresize.json + diff --git a/runtime/tests/ori_sledge_tests/start_monitor.sh b/runtime/tests/ori_sledge_tests/start_monitor.sh new file mode 100755 index 000000000..19c14b87c --- /dev/null +++ b/runtime/tests/ori_sledge_tests/start_monitor.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +function usage { + echo "$0 [pidstat file]" + exit 1 +} + +if [ $# != 1 ] ; then + usage + exit 1; +fi + +pidstat_file=$1 +sledge_pid=`ps -ef|grep "sledgert"|grep -v grep |awk '{print $2}'` +sleep 6 && pidstat -u -p $sledge_pid 1 1800 > $pidstat_file 2>&1 & diff --git a/runtime/tests/ori_sledge_tests/stop_monitor.sh b/runtime/tests/ori_sledge_tests/stop_monitor.sh new file mode 100755 index 000000000..fa67a47b5 --- /dev/null +++ b/runtime/tests/ori_sledge_tests/stop_monitor.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +pid=`ps -ef|grep "pidstat"|grep -v grep |awk '{print $2}'` +echo $pid +kill -2 $pid From 027b680ba2cb7113ba87a7dc6fbdae76cd22270b Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 11 Apr 2024 17:53:37 -0600 Subject: [PATCH 094/198] update measure_old_sledge_cost.sh --- runtime/tests/ori_sledge_tests/curl.sh | 3 ++- runtime/tests/ori_sledge_tests/measure_old_sledge_cost.sh | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/runtime/tests/ori_sledge_tests/curl.sh b/runtime/tests/ori_sledge_tests/curl.sh index ca8d2bae3..b781b9515 100755 --- a/runtime/tests/ori_sledge_tests/curl.sh +++ b/runtime/tests/ori_sledge_tests/curl.sh @@ -1 +1,2 @@ -curl -I -w "Total time: %{time_total}s\n" http://10.10.1.1:31850/empty +#curl -I -w "Total time: %{time_total}s\n" http://10.10.1.1:31850/empty +curl -w "Total time: %{time_total}s\n" http://10.10.1.1:31850/empty diff --git a/runtime/tests/ori_sledge_tests/measure_old_sledge_cost.sh b/runtime/tests/ori_sledge_tests/measure_old_sledge_cost.sh index 6c6c6f31f..e04023869 100755 --- a/runtime/tests/ori_sledge_tests/measure_old_sledge_cost.sh +++ b/runtime/tests/ori_sledge_tests/measure_old_sledge_cost.sh @@ -19,9 +19,9 @@ path="/my_mount/ori_sledge/sledge-serverless-framework/runtime/tests" for(( i=0;i<$repeat_count;i++ )) do echo "i is $i" echo "start server..." - ssh -o stricthostkeychecking=no -i ./id_rsa xiaosuGW@$remote_ip "$path/start.sh > 1.txt 2>&1 &" - sleep 1 + ssh -o stricthostkeychecking=no -i ./id_rsa xiaosuGW@$remote_ip "sudo $path/start.sh > 1.txt 2>&1 &" + sleep 1 echo "start client..." ./curl.sh >> old_sledge.log - ssh -o stricthostkeychecking=no -i ./id_rsa xiaosuGW@$remote_ip "$path/kill_sledge.sh" + ssh -o stricthostkeychecking=no -i ./id_rsa xiaosuGW@$remote_ip "sudo $path/kill_sledge.sh" done From b7fe43965fe178cf5f309b9ed128a52790c58b34 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 11 Apr 2024 23:51:48 -0600 Subject: [PATCH 095/198] update curl.sh --- runtime/tests/ori_sledge_tests/curl.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/tests/ori_sledge_tests/curl.sh b/runtime/tests/ori_sledge_tests/curl.sh index b781b9515..b557a1d27 100755 --- a/runtime/tests/ori_sledge_tests/curl.sh +++ b/runtime/tests/ori_sledge_tests/curl.sh @@ -1,2 +1,2 @@ #curl -I -w "Total time: %{time_total}s\n" http://10.10.1.1:31850/empty -curl -w "Total time: %{time_total}s\n" http://10.10.1.1:31850/empty +curl -w "Total time: %{time_total}s\n" http://10.10.1.1:31850/empty http://10.10.1.1:31850/empty From 225d342c0156096a26ea2075bb696185507ef39c Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 16 Apr 2024 15:36:04 -0600 Subject: [PATCH 096/198] remove meet_deadline_percentage.py parse_single.py from ori_sledge_tests --- .../meet_deadline_percentage.py | 219 ------------------ .../tests/ori_sledge_tests/parse_single.py | 58 ----- 2 files changed, 277 deletions(-) delete mode 100644 runtime/tests/ori_sledge_tests/meet_deadline_percentage.py delete mode 100644 runtime/tests/ori_sledge_tests/parse_single.py diff --git a/runtime/tests/ori_sledge_tests/meet_deadline_percentage.py b/runtime/tests/ori_sledge_tests/meet_deadline_percentage.py deleted file mode 100644 index d685673da..000000000 --- a/runtime/tests/ori_sledge_tests/meet_deadline_percentage.py +++ /dev/null @@ -1,219 +0,0 @@ -import sys -import json -from collections import defaultdict -import numpy as np - -def def_list_value(): - return [0, 0, 0, 0, 0] -def def_value(): - return 0 - -def count_miss_or_meet_deadline_requests(file_dir, percentage): - throughput = 0; - max_exe_time = 0 - ### each time for a request - request_times_dict = defaultdict(def_list_value) - #### get execution time - running_time_dict = defaultdict(def_value) - queuing_times_dict = defaultdict(def_value) - total_times_dict = defaultdict(def_value) - runnable_times_dict = defaultdict(def_value) - blocked_times_dict = defaultdict(def_value) - initializing_times_dict = defaultdict(def_value) - execution_times_dict = defaultdict(def_value) - - ### init overhead - ### queuelength - queuelength_dict = defaultdict(list) - ### - running_times = defaultdict(list) - queuing_times = defaultdict(list) - thread_running_times = defaultdict(list) - total_times = defaultdict(list) - thread_times = defaultdict(list) - thread_throughput = defaultdict(list) - t2_cleanup = defaultdict(list) - runnable_times = defaultdict(list) - blocked_times = defaultdict(list) - initializing_times = defaultdict(list) - execution_times = defaultdict(list) - #### - request_counter = defaultdict(def_value) - total_time_dist = defaultdict(list) - total_time_list = [] - total_slow_down = [] - total_workload_dist = defaultdict(def_value) - total_real_time_workload_dist = defaultdict(def_value) - real_time_workload_times_dist = defaultdict(list) - real_time_workload_workloads_dist = defaultdict(list) - real_time_workload_requests_dist = defaultdict(list) - min_time = sys.maxsize - # list[0] is meet deadline number, list[1] is miss deadline number - delays_dict = defaultdict(list) - max_latency_dist = defaultdict(def_value) - total_deadline = 0 - miss_deadline_dist = defaultdict(def_value) - meet_deadline_dist = defaultdict(def_value) - meet_deadline = 0 - miss_deadline = 0 - max_sc = 0 - total_interrupts = 0; - fo = open(file_dir, "r+") - for line in fo: - line = line.strip() - if "meet" in line: - meet_deadline += 1 - name = line.split(" ")[7] - cleanup = line.split(" ")[9] - deadline = int(line.split(" ")[10]) - name = name[1:] - tid = line.split(" ")[1] - request_counter[name] += 1 - total_time = int(line.split(" ")[4]) - total_time_dist[name].append(total_time) - if name == "fib": - total_slow_down.append(round((float(total_time) / deadline), 2)) - else: - total_slow_down.append(round((float(total_time) / deadline), 2)) - total_time_list.append(total_time) - thread_times[tid].append(total_time) - if total_time > max_latency_dist[name]: - max_latency_dist[name] = total_time - meet_deadline_dist[name] += 1 - exe_time = int(line.split(" ")[5]) - if exe_time > max_exe_time: - max_exe_time = exe_time - running_times[name].append(exe_time); - queue_time = int(line.split(" ")[6]) - queuing_times[name].append(queue_time); - thread_running_times[tid].append(exe_time); - t2_cleanup[tid].append(cleanup) - if "miss" in line: - miss_deadline += 1 - name = line.split(" ")[7] - cleanup = line.split(" ")[9] - deadline = int(line.split(" ")[10]) - name = name[1:] - tid = line.split(" ")[1] - total_time = int(line.split(" ")[4]) - if total_time > max_latency_dist[name]: - max_latency_dist[name] = total_time - request_counter[name] += 1 - total_time_dist[name].append(total_time) - total_time_list.append(total_time) - if name == "fib": - total_slow_down.append(round((float(total_time) / deadline), 2)) - else: - total_slow_down.append(round((float(total_time) / deadline), 2)) - thread_times[tid].append(total_time) - miss_deadline_dist[name] += 1 - exe_time = line.split(" ")[5] - exe_time = int(line.split(" ")[5]) - if exe_time > max_exe_time: - max_exe_time = exe_time - running_times[name].append(exe_time); - queue_time = int(line.split(" ")[6]) - queuing_times[name].append(queue_time); - thread_running_times[tid].append(exe_time); - t2_cleanup[tid].append(cleanup) - #print("name:", name) - if "throughput" in line: - throughput = line.split(" ")[1] - interrupt = line.split(" ")[15] - total_interrupts += int(interrupt); - ### calculate the execution time - #if "memory" in line or "total_time" in line or "min" in line or "miss" in line or "meet" in line or "time " in line or "scheduling count" in line or "thread id" in line: - # continue - if "pthroughput" in line: - tid = line.split(" ")[2] - throughput = line.split(" ")[3] - thread_throughput[tid].append(throughput) - - miss_deadline_percentage = (miss_deadline * 100) / (miss_deadline + meet_deadline) - print("meet deadline num:", meet_deadline) - print("miss deadline num:", miss_deadline) - print("total requests:", meet_deadline + miss_deadline) - print("miss deadline percentage:", miss_deadline_percentage) - print("throughput:", throughput) - print("total interrupts:", total_interrupts) - - for key,value in request_counter.items(): - print(key, ":", str(value), "proportion:", (100*value)/(meet_deadline + miss_deadline)) - for key,value in total_time_dist.items(): - a = np.array(value) - p = np.percentile(a, int(percentage)) - print(key + " " + percentage + " percentile is:" + str(p) + " mean is:" + str(np.mean(value)) + " max latency is:" + str(max_latency_dist[key])) - #total_cpu_times = 0 - for key,value in meet_deadline_dist.items(): - # total_cpu_times += value * fun_execution_time[key] - miss_value = miss_deadline_dist[key] - total_request = miss_value + value - miss_rate = (miss_value * 100) / total_request - - print(key + " miss deadline rate:" + str(miss_rate)); - # print(func_name_dict[key] + " miss deadline rate:" + str(miss_rate) + " miss count is:" + str(miss_value) + " total request:" + str(total_request)) - #print("effective total cpu times:", total_cpu_times) - #for key,value in real_time_workload_times_dist.items(): - # real_time_workload_times_dist[key] = [x - min_time for x in value] - - for key,value in running_times.items(): - #print("function times:", func_name_with_id[key], np.median(total_times[key]), np.median(running_times[key]), np.median(queuing_times[key]), np.median(runnable_times[key]), np.median(blocked_times[key]), np.median(initializing_times[key])) - print("function :", key, "median total:", np.median(total_time_dist[key]), "exec:", np.median(running_times[key]), "queue:", np.median(queuing_times[key])) - print(len(value)) - print(len(queuing_times[key])) - print(len(total_time_dist[key])) - total_time_array = np.array(total_time_list) - p_99 = np.percentile(total_time_array, 99) - p_99_9 = np.percentile(total_time_array, 99.9) - p_99_99 = np.percentile(total_time_array, 99.99) - print("99 percentile latency is ", p_99) - print("99.9 percentile latency is ", p_99_9) - print("99.99 percentile latency is ", p_99_99) - total_time_slow_down = np.array(total_slow_down) - p_99_slow_down = np.percentile(total_time_slow_down, 99) - p_99_9_slow_down = np.percentile(total_time_slow_down, 99.9) - p_99_99_slow_down = np.percentile(total_time_slow_down, 99.99) - print("99 percentile slow down is ", p_99_slow_down) - print("99.9 percentile slow down is ", p_99_9_slow_down) - print("99.99 percentile slow down is ", p_99_99_slow_down) - print("max exe time:", max_exe_time) - js_latency = json.dumps(total_time_list) - f_latency = open("total_time_list.txt", 'w') - f_latency.write(js_latency) - f_latency.close() - js = json.dumps(total_time_dist) - f = open("total_time.txt", 'w') - f.write(js) - f.close() - - js1 = json.dumps(queuing_times) - f1 = open("queuing_time.txt", 'w') - f1.write(js1) - f1.close() - - js5 = json.dumps(thread_running_times) - f5 = open("running_time.txt", 'w') - f5.write(js5) - f5.close() - - js2 = json.dumps(thread_times) - f2 = open("thread_time.txt", 'w') - f2.write(js2) - f2.close() - - js3 = json.dumps(thread_throughput) - f3 = open("thread_throughput.txt", 'w') - f3.write(js3) - f3.close() - - js4 = json.dumps(t2_cleanup) - f4 = open("cleanup.txt", 'w') - f4.write(js4) - f4.close() - -if __name__ == "__main__": - argv = sys.argv[1:] - if len(argv) < 1: - print("usage ", sys.argv[0], " " " ") - sys.exit() - count_miss_or_meet_deadline_requests(argv[0], argv[1]) diff --git a/runtime/tests/ori_sledge_tests/parse_single.py b/runtime/tests/ori_sledge_tests/parse_single.py deleted file mode 100644 index c7107adb4..000000000 --- a/runtime/tests/ori_sledge_tests/parse_single.py +++ /dev/null @@ -1,58 +0,0 @@ -import re -import os -import sys -from collections import defaultdict - -#get all file names which contain key_str -def file_name(file_dir, key_str): - throughput_table = defaultdict(list) - errors_table = defaultdict(list) - for root, dirs, files in os.walk(file_dir): - if root != os.getcwd(): - continue - for file_i in files: - if file_i.find(key_str) >= 0: - segs = file_i.split('-') - if len(segs) < 3: - continue - #print(file_i) - cores_num = segs[1] - concurrency = segs[3].split(".")[0] - print("core:", cores_num, " concurrency:", concurrency) - get_values(cores_num, concurrency, file_i, throughput_table, errors_table) - #file_table[key].append(file_i) - s_result = sorted(throughput_table.items()) - for i in range(len(s_result)): - print(s_result[i], "errors request:", errors_table[s_result[i][0]]) - for i in range(len(s_result)): - print(int(float(((s_result[i][1][0])))),end=" ") - print(); - #sys.exit() - -def get_values(core, concurrency, file_name, throughput_table, errors_table): - fo = open(file_name, "r+") - total_throughput = 0 - for line in fo: - line = line.strip() - if "throughput is" in line: - print("line is ", line); - i_th = float(line.split(" ")[2]) - total_throughput += i_th - throughput_table[int(core)].append(total_throughput) - break; - - print("throughput:", total_throughput) - - -if __name__ == "__main__": - import json - argv = sys.argv[1:] - if len(argv) < 1: - print("usage ", sys.argv[0], " file containing key word") - sys.exit() - - file_name(os.getcwd(), argv[0]) - - for key, value in files_tables.items(): - get_values(key, value, miss_deadline_rate, total_latency, running_times, preemption_count, total_miss_deadline_rate) - From c5f482706874921fbb29bb7ee28a997e773425e8 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 16 Apr 2024 15:36:53 -0600 Subject: [PATCH 097/198] rename parase_cost.py to parse_cost.py --- runtime/tests/ori_sledge_tests/parse_cost.py | 35 ++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 runtime/tests/ori_sledge_tests/parse_cost.py diff --git a/runtime/tests/ori_sledge_tests/parse_cost.py b/runtime/tests/ori_sledge_tests/parse_cost.py new file mode 100644 index 000000000..9131478b8 --- /dev/null +++ b/runtime/tests/ori_sledge_tests/parse_cost.py @@ -0,0 +1,35 @@ +import sys + +if len(sys.argv) != 2: + print("Usage: python script.py ") + sys.exit(1) + +filename = sys.argv[1] + +try: + with open(filename, "r") as file: + lines = file.readlines() +except FileNotFoundError: + print("File not found:", filename) + sys.exit(1) + +total_cold_time = 0 +total_warm_time = 0 +count = 0 + +for i in range(0, len(lines), 2): + time_str_1 = lines[i].split(": ")[1].strip() + time_str_2 = lines[i+1].split(": ")[1].strip() + time_value_1 = float(time_str_1[:-1]) + time_value_2 = float(time_str_2[:-1]) + + total_cold_time += time_value_1 + total_warm_time += time_value_2 + count += 1 + +average_cold_time = total_cold_time / count +average_warm_time = total_warm_time / count + +print("Average cold time:", average_cold_time, "s") +print("Average warm time:", average_warm_time, "s") + From b1a37ce159418cc45cc7840c33e7f5660a99a8d5 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 16 Apr 2024 16:27:58 -0600 Subject: [PATCH 098/198] update curl.sh and parse_cost.py in ori_sledge_tests --- runtime/tests/ori_sledge_tests/curl.sh | 2 +- runtime/tests/ori_sledge_tests/parse_cost.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/runtime/tests/ori_sledge_tests/curl.sh b/runtime/tests/ori_sledge_tests/curl.sh index b557a1d27..5ea14ad74 100755 --- a/runtime/tests/ori_sledge_tests/curl.sh +++ b/runtime/tests/ori_sledge_tests/curl.sh @@ -1,2 +1,2 @@ #curl -I -w "Total time: %{time_total}s\n" http://10.10.1.1:31850/empty -curl -w "Total time: %{time_total}s\n" http://10.10.1.1:31850/empty http://10.10.1.1:31850/empty +curl -w "Total time: %{time_total}s\n" http://10.10.1.1:31850/empty http://10.10.1.1:31850/empty http://10.10.1.1:31850/empty http://10.10.1.1:31850/empty diff --git a/runtime/tests/ori_sledge_tests/parse_cost.py b/runtime/tests/ori_sledge_tests/parse_cost.py index 9131478b8..976e4c07f 100644 --- a/runtime/tests/ori_sledge_tests/parse_cost.py +++ b/runtime/tests/ori_sledge_tests/parse_cost.py @@ -17,9 +17,9 @@ total_warm_time = 0 count = 0 -for i in range(0, len(lines), 2): +for i in range(0, len(lines), 4): time_str_1 = lines[i].split(": ")[1].strip() - time_str_2 = lines[i+1].split(": ")[1].strip() + time_str_2 = lines[i+3].split(": ")[1].strip() time_value_1 = float(time_str_1[:-1]) time_value_2 = float(time_str_2[:-1]) From e68a6e3d9407a98a236a845f20f7f4bd7bc257f2 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 16 Apr 2024 17:37:48 -0600 Subject: [PATCH 099/198] update start.sh: --- runtime/tests/start.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/runtime/tests/start.sh b/runtime/tests/start.sh index 3a5672fbf..968a8a442 100755 --- a/runtime/tests/start.sh +++ b/runtime/tests/start.sh @@ -29,7 +29,7 @@ export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=true export SLEDGE_FIRST_WORKER_COREID=$first_worker_core_id export SLEDGE_NWORKERS=$worker_num export SLEDGE_NLISTENERS=$listener_num -export SLEDGE_WORKER_GROUP_SIZE=9 +export SLEDGE_WORKER_GROUP_SIZE=1 export SLEDGE_SCHEDULER=EDF #export SLEDGE_DISPATCHER=DARC #export SLEDGE_DISPATCHER=SHINJUKU @@ -45,8 +45,8 @@ cd $project_path/runtime/bin #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/mulitple_linear_chain.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing3.json -#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/fib.json -LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/hash.json +LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/fib.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/hash.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/empty.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/my_fibonacci.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_sodresize.json From 6247388e7a718732eb82a49dda9d8f14967da217 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 25 Apr 2024 16:15:16 -0600 Subject: [PATCH 100/198] 1. use request type id to locate object route and module. 2. Increase MODULE_DATABASE_CAPACITY from 128 to 1024. 3. Change log of sandbox_perf_log.h 4. Commend code 'explicit_bzero(wasm_stack->low, wasm_stack->capacity)' when reclaim sandbox stack memory because it will hurt performance too much as it access every bit of the memory --- runtime/include/http_router.h | 18 ++++++++++++++++-- runtime/include/listener_thread.h | 2 +- runtime/include/module_database.h | 2 +- runtime/include/sandbox_perf_log.h | 25 ++++++++++++++++++------- runtime/include/wasm_stack.h | 5 +++-- 5 files changed, 39 insertions(+), 13 deletions(-) diff --git a/runtime/include/http_router.h b/runtime/include/http_router.h index 8bbe7cba2..39e1bb753 100644 --- a/runtime/include/http_router.h +++ b/runtime/include/http_router.h @@ -13,6 +13,7 @@ #include "vec.h" #include "dispatcher_options.h" +extern struct route *route_array; typedef struct route route_t; VEC(route_t) @@ -22,6 +23,10 @@ static inline void http_router_init(http_router_t *router, size_t capacity) { vec_route_t_init(router, capacity); + /* Use the request type as the array index, so skip index 0 since request index + starts from 1 + */ + route_array = (struct route*) calloc(capacity + 1, sizeof(struct route)); } static inline int @@ -67,6 +72,7 @@ http_router_add_route(http_router_t *router, struct route_config *config, struct route.relative_deadline); int rc = vec_route_t_push(router, route); + route_array[config->request_type] = route; if (unlikely(rc == -1)) { return -1; } return 0; @@ -87,13 +93,21 @@ http_router_match_route(http_router_t *router, char *route) static inline struct route * http_router_match_request_type(http_router_t *router, uint8_t request_type) { - for (int i = 0; i < router->length; i++) { + /* + for (int i = 0; i < router->length; i++) { if (request_type == router->buffer[i].request_type) { return &router->buffer[i]; } } - return NULL; + return NULL; + */ + + if (route_array[request_type].request_type == request_type) { + return &route_array[request_type]; + } else { + return NULL; + } } static inline void diff --git a/runtime/include/listener_thread.h b/runtime/include/listener_thread.h index b4886a959..55f954aa6 100644 --- a/runtime/include/listener_thread.h +++ b/runtime/include/listener_thread.h @@ -13,7 +13,7 @@ #define GLOBAL_QUEUE_ERROR "Failed to add sandbox to global queue" #define MAX_DISPATCHER 10 -#define MAX_REQUEST_TYPE 10 +#define MAX_REQUEST_TYPE MODULE_DATABASE_CAPACITY extern thread_local pthread_t listener_thread_id; diff --git a/runtime/include/module_database.h b/runtime/include/module_database.h index 0c09ec55d..24d1b4605 100644 --- a/runtime/include/module_database.h +++ b/runtime/include/module_database.h @@ -2,7 +2,7 @@ #include "module.h" -#define MODULE_DATABASE_CAPACITY 128 +#define MODULE_DATABASE_CAPACITY 1024 struct module_database { struct module *modules[MODULE_DATABASE_CAPACITY]; diff --git a/runtime/include/sandbox_perf_log.h b/runtime/include/sandbox_perf_log.h index 671349593..7ea71d6b7 100644 --- a/runtime/include/sandbox_perf_log.h +++ b/runtime/include/sandbox_perf_log.h @@ -5,6 +5,7 @@ #include "sandbox_types.h" #include "memlogging.h" +extern _Atomic uint32_t local_queue_length[1024]; extern FILE *sandbox_perf_log; extern thread_local int global_worker_thread_idx; @@ -15,9 +16,7 @@ static inline void sandbox_perf_log_print_header() { if (sandbox_perf_log == NULL) { perror("sandbox perf log"); } - fprintf(sandbox_perf_log, "id,tenant,route,state,deadline,actual,queued,uninitialized,allocated,initialized," - "runnable,interrupted,preempted," - "running_sys,running_user,asleep,returned,complete,error,proc_MHz,memory\n"); + fprintf(sandbox_perf_log, "tid,rid,total,execution,queued,route,init,cleanup,deadline,queuelen\n"); } /** @@ -55,11 +54,23 @@ sandbox_perf_log_print_entry(struct sandbox *sandbox) uint64_t init_time = sandbox->duration_of_state[SANDBOX_INITIALIZED] / runtime_processor_speed_MHz; if (miss_deadline) { - mem_log("tid %d %u miss %lu %lu %lu %s %lu %lu %lu f%d %lu %lu %lu %lu %lu %lu\n", global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route, - init_time, cleanup, deadline, sandbox->context_switch_to, other, t1,t2,t3,t4,t5); + /*mem_log("tid %d %u miss %lu %lu %lu %s %lu %lu %lu f%d %lu %lu %lu %lu %lu %lu\n", + global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, + sandbox->route->route,init_time, cleanup, deadline, sandbox->context_switch_to, other, t1,t2,t3,t4,t5); + */ + mem_log("tid %d %u miss %lu %lu %lu %s %lu %lu %lu %u\n", + global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, + sandbox->route->route,init_time, cleanup, deadline,local_queue_length[global_worker_thread_idx]); + } else { - mem_log("tid %d %u meet %lu %lu %lu %s %lu %lu %lu f%d %lu %lu %lu %lu %lu %lu\n", global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route, - init_time, cleanup, deadline, sandbox->context_switch_to, other, t1,t2,t3,t4,t5); + /*mem_log("tid %d %u meet %lu %lu %lu %s %lu %lu %lu f%d %lu %lu %lu %lu %lu %lu\n", + global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, + sandbox->route->route,init_time, cleanup, deadline, sandbox->context_switch_to, other, t1,t2,t3,t4,t5); + */ + mem_log("tid %d %u meet %lu %lu %lu %s %lu %lu %lu %lu\n", + global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, + sandbox->route->route,init_time, cleanup, deadline,deadline,local_queue_length[global_worker_thread_idx]); + } /* * Assumption: A sandbox is never able to free pages. If linear memory management diff --git a/runtime/include/wasm_stack.h b/runtime/include/wasm_stack.h index 95d5ac3a9..c87c18512 100644 --- a/runtime/include/wasm_stack.h +++ b/runtime/include/wasm_stack.h @@ -124,7 +124,8 @@ wasm_stack_reinit(struct wasm_stack *wasm_stack) assert(wasm_stack->buffer != NULL); assert(wasm_stack->low == wasm_stack->buffer + /* guard page */ PAGE_SIZE); assert(wasm_stack->high == wasm_stack->low + wasm_stack->capacity); - - explicit_bzero(wasm_stack->low, wasm_stack->capacity); + /* comment this line because it will access all bits of the memory + and hurt the performance too much */ + //explicit_bzero(wasm_stack->low, wasm_stack->capacity); ps_list_init_d(wasm_stack); } From 80eed1c9f18431ddf9d12eebec48e2749f8a182c Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 25 Apr 2024 23:38:31 -0600 Subject: [PATCH 101/198] set sandbox stack pointer to sandbox->wasm_stack to let it only free the correct size of stack --- runtime/include/wasm_stack.h | 6 +++--- runtime/src/sandbox.c | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/runtime/include/wasm_stack.h b/runtime/include/wasm_stack.h index c87c18512..4926a41d2 100644 --- a/runtime/include/wasm_stack.h +++ b/runtime/include/wasm_stack.h @@ -28,6 +28,7 @@ struct wasm_stack { uint8_t *high; /* The highest address of the stack. Grows down from here */ uint8_t *low; /* The address of the lowest useabe address. Above guard page */ uint8_t *buffer; /* Points base address of backing heap allocation (Guard Page) */ + uint8_t *sp; /* Stack pointer */ }; static struct wasm_stack *wasm_stack_alloc(uint64_t capacity); @@ -60,6 +61,7 @@ wasm_stack_init(struct wasm_stack *wasm_stack, uint64_t capacity) wasm_stack->low = wasm_stack->buffer + /* guard page */ PAGE_SIZE; wasm_stack->capacity = capacity; wasm_stack->high = wasm_stack->low + capacity; + wasm_stack->sp = wasm_stack->low; /* Set the initial bytes to read / write */ rc = mprotect(wasm_stack->low, capacity, PROT_READ | PROT_WRITE); @@ -124,8 +126,6 @@ wasm_stack_reinit(struct wasm_stack *wasm_stack) assert(wasm_stack->buffer != NULL); assert(wasm_stack->low == wasm_stack->buffer + /* guard page */ PAGE_SIZE); assert(wasm_stack->high == wasm_stack->low + wasm_stack->capacity); - /* comment this line because it will access all bits of the memory - and hurt the performance too much */ - //explicit_bzero(wasm_stack->low, wasm_stack->capacity); + explicit_bzero(wasm_stack->sp, wasm_stack->high - wasm_stack->sp); ps_list_init_d(wasm_stack); } diff --git a/runtime/src/sandbox.c b/runtime/src/sandbox.c index a6b377093..769675049 100644 --- a/runtime/src/sandbox.c +++ b/runtime/src/sandbox.c @@ -80,7 +80,9 @@ sandbox_free_stack(struct sandbox *sandbox) { assert(sandbox); - //return module_free_stack(sandbox->module, sandbox->stack); + //return module_free_stack(sandbox->module, sandbox->stack); + //set SP to sandbox->stack + sandbox->stack->sp = (uint8_t*)sandbox->ctxt.regs[UREG_SP]; uint64_t t = module_free_stack(sandbox->module, sandbox->stack); return t; } From 08f6f0a661c920b8e37c5487d0794182939c3781 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 26 Apr 2024 15:56:36 -0600 Subject: [PATCH 102/198] upload increase_req_type.patch --- runtime/increase_req_type.patch | 191 ++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 runtime/increase_req_type.patch diff --git a/runtime/increase_req_type.patch b/runtime/increase_req_type.patch new file mode 100644 index 000000000..a2f8514d9 --- /dev/null +++ b/runtime/increase_req_type.patch @@ -0,0 +1,191 @@ +diff --git a/awsm b/awsm +index 69c8b61..f0b35e7 160000 +--- a/awsm ++++ b/awsm +@@ -1 +1 @@ +-Subproject commit 69c8b6116664d65a851cc459601bef6af3caeaea ++Subproject commit f0b35e756395f79b06be8dd2660eecac94506e94 +diff --git a/runtime/Makefile b/runtime/Makefile +index 607870e..5e01e67 100644 +--- a/runtime/Makefile ++++ b/runtime/Makefile +@@ -16,10 +16,10 @@ CFLAGS+=-D_GNU_SOURCE + # Enable SLEDGE macro for erpc c interface build + CFLAGS+=-DSLEDGE + # Release Flags +-CFLAGS+=-O3 -flto ++#CFLAGS+=-O3 -flto + + # Debugging Flags +-# CFLAGS+=-O0 -g3 ++ CFLAGS+=-O0 -g3 + + # CFI Sanitizer + # CFLAGS+=-fvisibility=default -fsanitize=cfi +diff --git a/runtime/include/erpc_handler.h b/runtime/include/erpc_handler.h +index 7442ea1..04de7fa 100644 +--- a/runtime/include/erpc_handler.h ++++ b/runtime/include/erpc_handler.h +@@ -1,6 +1,6 @@ + #pragma once + + #include +-void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); ++void edf_interrupt_req_handler(void *req_handle, uint16_t req_type, uint8_t *msg, size_t size, uint16_t port); + void darc_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); + void shinjuku_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); +diff --git a/runtime/include/http_router.h b/runtime/include/http_router.h +index 39e1bb7..4da6948 100644 +--- a/runtime/include/http_router.h ++++ b/runtime/include/http_router.h +@@ -54,7 +54,7 @@ http_router_add_route(http_router_t *router, struct route_config *config, struct + /* Register RPC request handler */ + if (dispatcher == DISPATCHER_EDF_INTERRUPT) { + if (erpc_register_req_func(config->request_type, edf_interrupt_req_handler, 0) != 0) { +- panic("register erpc function for EDF_INTERRUPT dispatcher failed\n"); ++ panic("register erpc function %u for EDF_INTERRUPT dispatcher failed\n", config->request_type); + } + } else if (dispatcher == DISPATCHER_DARC) { + if (erpc_register_req_func(config->request_type, darc_req_handler, 0) != 0) { +@@ -91,7 +91,7 @@ http_router_match_route(http_router_t *router, char *route) + } + + static inline struct route * +-http_router_match_request_type(http_router_t *router, uint8_t request_type) ++http_router_match_request_type(http_router_t *router, uint16_t request_type) + { + /* + for (int i = 0; i < router->length; i++) { +diff --git a/runtime/include/json_parse.h b/runtime/include/json_parse.h +index c99aa2a..4c5b3c4 100644 +--- a/runtime/include/json_parse.h ++++ b/runtime/include/json_parse.h +@@ -7,7 +7,7 @@ + + #include "tenant_config_parse.h" + +-#define JSON_TOKENS_CAPACITY 16384 ++#define JSON_TOKENS_CAPACITY 65535 + + /** + * Parses a JSON file into an array of tenant configs +diff --git a/runtime/include/route.h b/runtime/include/route.h +index 3fffc08..3127055 100644 +--- a/runtime/include/route.h ++++ b/runtime/include/route.h +@@ -11,7 +11,7 @@ + /* Assumption: entrypoint is always _start. This should be enhanced later */ + struct route { + char *route; +- uint8_t request_type; ++ uint16_t request_type; + struct http_route_total metrics; + struct module *module; + /* HTTP State */ +diff --git a/runtime/include/route_config.h b/runtime/include/route_config.h +index 337389f..1904f7c 100644 +--- a/runtime/include/route_config.h ++++ b/runtime/include/route_config.h +@@ -23,7 +23,7 @@ enum route_config_member + + struct route_config { + char *route; +- uint8_t request_type; ++ uint16_t request_type; + uint32_t n_resas; + char *path; + uint8_t admissions_percentile; +@@ -48,8 +48,7 @@ static inline void + route_config_print(struct route_config *config) + { + printf("[Route] Route: %s\n", config->route); +- printf("[Route] Request type: %hhu\n", config->request_type); +- printf("[Route] Request type: %hhu\n", config->request_type); ++ printf("[Route] Request type: %u\n", config->request_type); + printf("[Route] Path: %s\n", config->path); + printf("[Route] Admissions Percentile: %hhu\n", config->admissions_percentile); + printf("[Route] Expected Execution (us): %u\n", config->expected_execution_us); +diff --git a/runtime/include/route_config_parse.h b/runtime/include/route_config_parse.h +index 522f3db..4b68008 100644 +--- a/runtime/include/route_config_parse.h ++++ b/runtime/include/route_config_parse.h +@@ -63,7 +63,7 @@ route_config_parse(struct route_config *config, const char *json_buf, jsmntok_t + if (route_config_set_key_once(did_set, route_config_member_request_type) == -1) + return -1; + +- int rc = parse_uint8_t(tokens[i], json_buf, ++ int rc = parse_uint16_t(tokens[i], json_buf, + route_config_json_keys[route_config_member_request_type], + &config->request_type); + if (rc < 0) return -1; +diff --git a/runtime/include/tenant_functions.h b/runtime/include/tenant_functions.h +index f4e02c1..4aa7842 100644 +--- a/runtime/include/tenant_functions.h ++++ b/runtime/include/tenant_functions.h +@@ -21,7 +21,7 @@ extern thread_local uint32_t n_rtypes; + extern thread_local struct request_typed_queue *request_type_queue[MAX_REQUEST_TYPE]; + extern thread_local struct request_typed_deque *request_type_deque[MAX_REQUEST_TYPE]; + extern thread_local uint8_t dispatcher_thread_idx; +-extern thread_local struct perf_window perf_window_per_thread[1024]; ++extern thread_local struct perf_window perf_window_per_thread[MODULE_DATABASE_CAPACITY]; + extern thread_local int global_worker_thread_idx; + + int tenant_database_add(struct tenant *tenant); +diff --git a/runtime/src/admissions_info.c b/runtime/src/admissions_info.c +index 77c3417..e204bbc 100644 +--- a/runtime/src/admissions_info.c ++++ b/runtime/src/admissions_info.c +@@ -1,9 +1,10 @@ + #include "admissions_control.h" + #include "admissions_info.h" ++#include "module_database.h" + #include "debuglog.h" + #include "perf_window.h" + +-extern thread_local struct perf_window perf_window_per_thread[1024]; ++extern thread_local struct perf_window perf_window_per_thread[MODULE_DATABASE_CAPACITY]; + /** + * Initializes perf window + * @param admissions_info +diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c +index 35c1420..038c9be 100644 +--- a/runtime/src/listener_thread.c ++++ b/runtime/src/listener_thread.c +@@ -471,7 +471,7 @@ on_client_socket_epoll_event(struct epoll_event *evt) + * @param msg the payload of the rpc request. It is the input parameter fot the function + * @param size the size of the msg + */ +-void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { ++void edf_interrupt_req_handler(void *req_handle, uint16_t req_type, uint8_t *msg, size_t size, uint16_t port) { + + if (first_request_comming == false){ + t_start = time(NULL); +diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c +index b11b7a0..78e3fa5 100644 +--- a/runtime/src/worker_thread.c ++++ b/runtime/src/worker_thread.c +@@ -24,15 +24,15 @@ + * Worker Thread State * + **************************/ + +-extern pthread_mutex_t mutexs[1024]; +-extern pthread_cond_t conds[1024]; +-extern sem_t semlock[1024]; +- +-_Atomic uint32_t local_queue_length[1024] = {0}; +-uint32_t max_local_queue_length[1024] = {0}; +-extern struct perf_window * worker_perf_windows[1024]; +-thread_local struct perf_window perf_window_per_thread[1024]; +-struct sandbox* current_sandboxes[1024] = { NULL }; ++extern pthread_mutex_t mutexs[1024]; // maximum index is number of threads ++extern pthread_cond_t conds[1024]; // maximum index is number of threads ++extern sem_t semlock[1024]; //maximum index is number of threads ++ ++_Atomic uint32_t local_queue_length[1024] = {0}; // maximum index is number of threads ++uint32_t max_local_queue_length[1024] = {0}; // maximum index is number of threads ++extern struct perf_window * worker_perf_windows[1024]; // maximum index is number of threads ++thread_local struct perf_window perf_window_per_thread[MODULE_DATABASE_CAPACITY]; // maximum index is the number of modules ++struct sandbox* current_sandboxes[1024] = { NULL }; // maximum index is number of threads + extern uint32_t runtime_worker_group_size; + + extern FILE *sandbox_perf_log; From 372ab41218f7098ad8d42730d73a387be647d805 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 26 Apr 2024 16:35:51 -0600 Subject: [PATCH 103/198] update increase_req_type.patch --- runtime/increase_req_type.patch | 68 +++++++++++++++++---------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/runtime/increase_req_type.patch b/runtime/increase_req_type.patch index a2f8514d9..182b8ded0 100644 --- a/runtime/increase_req_type.patch +++ b/runtime/increase_req_type.patch @@ -1,27 +1,3 @@ -diff --git a/awsm b/awsm -index 69c8b61..f0b35e7 160000 ---- a/awsm -+++ b/awsm -@@ -1 +1 @@ --Subproject commit 69c8b6116664d65a851cc459601bef6af3caeaea -+Subproject commit f0b35e756395f79b06be8dd2660eecac94506e94 -diff --git a/runtime/Makefile b/runtime/Makefile -index 607870e..5e01e67 100644 ---- a/runtime/Makefile -+++ b/runtime/Makefile -@@ -16,10 +16,10 @@ CFLAGS+=-D_GNU_SOURCE - # Enable SLEDGE macro for erpc c interface build - CFLAGS+=-DSLEDGE - # Release Flags --CFLAGS+=-O3 -flto -+#CFLAGS+=-O3 -flto - - # Debugging Flags --# CFLAGS+=-O0 -g3 -+ CFLAGS+=-O0 -g3 - - # CFI Sanitizer - # CFLAGS+=-fvisibility=default -fsanitize=cfi diff --git a/runtime/include/erpc_handler.h b/runtime/include/erpc_handler.h index 7442ea1..04de7fa 100644 --- a/runtime/include/erpc_handler.h @@ -69,6 +45,19 @@ index c99aa2a..4c5b3c4 100644 /** * Parses a JSON file into an array of tenant configs +diff --git a/runtime/include/module_database.h b/runtime/include/module_database.h +index 24d1b46..7cbc088 100644 +--- a/runtime/include/module_database.h ++++ b/runtime/include/module_database.h +@@ -2,7 +2,7 @@ + + #include "module.h" + +-#define MODULE_DATABASE_CAPACITY 1024 ++#define MODULE_DATABASE_CAPACITY 2048 + + struct module_database { + struct module *modules[MODULE_DATABASE_CAPACITY]; diff --git a/runtime/include/route.h b/runtime/include/route.h index 3fffc08..3127055 100644 --- a/runtime/include/route.h @@ -119,23 +108,24 @@ index 522f3db..4b68008 100644 &config->request_type); if (rc < 0) return -1; diff --git a/runtime/include/tenant_functions.h b/runtime/include/tenant_functions.h -index f4e02c1..4aa7842 100644 +index f4e02c1..84f69a2 100644 --- a/runtime/include/tenant_functions.h +++ b/runtime/include/tenant_functions.h -@@ -21,7 +21,7 @@ extern thread_local uint32_t n_rtypes; +@@ -21,7 +21,8 @@ extern thread_local uint32_t n_rtypes; extern thread_local struct request_typed_queue *request_type_queue[MAX_REQUEST_TYPE]; extern thread_local struct request_typed_deque *request_type_deque[MAX_REQUEST_TYPE]; extern thread_local uint8_t dispatcher_thread_idx; -extern thread_local struct perf_window perf_window_per_thread[1024]; -+extern thread_local struct perf_window perf_window_per_thread[MODULE_DATABASE_CAPACITY]; ++//extern thread_local struct perf_window perf_window_per_thread[MODULE_DATABASE_CAPACITY]; ++extern thread_local struct perf_window *perf_window_per_thread; extern thread_local int global_worker_thread_idx; int tenant_database_add(struct tenant *tenant); diff --git a/runtime/src/admissions_info.c b/runtime/src/admissions_info.c -index 77c3417..e204bbc 100644 +index 77c3417..a5901a0 100644 --- a/runtime/src/admissions_info.c +++ b/runtime/src/admissions_info.c -@@ -1,9 +1,10 @@ +@@ -1,9 +1,11 @@ #include "admissions_control.h" #include "admissions_info.h" +#include "module_database.h" @@ -143,7 +133,8 @@ index 77c3417..e204bbc 100644 #include "perf_window.h" -extern thread_local struct perf_window perf_window_per_thread[1024]; -+extern thread_local struct perf_window perf_window_per_thread[MODULE_DATABASE_CAPACITY]; ++//extern thread_local struct perf_window perf_window_per_thread[MODULE_DATABASE_CAPACITY]; ++extern thread_local struct perf_window *perf_window_per_thread; /** * Initializes perf window * @param admissions_info @@ -161,10 +152,10 @@ index 35c1420..038c9be 100644 if (first_request_comming == false){ t_start = time(NULL); diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c -index b11b7a0..78e3fa5 100644 +index b11b7a0..03f78f5 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c -@@ -24,15 +24,15 @@ +@@ -24,15 +24,16 @@ * Worker Thread State * **************************/ @@ -184,8 +175,19 @@ index b11b7a0..78e3fa5 100644 +_Atomic uint32_t local_queue_length[1024] = {0}; // maximum index is number of threads +uint32_t max_local_queue_length[1024] = {0}; // maximum index is number of threads +extern struct perf_window * worker_perf_windows[1024]; // maximum index is number of threads -+thread_local struct perf_window perf_window_per_thread[MODULE_DATABASE_CAPACITY]; // maximum index is the number of modules ++//thread_local struct perf_window perf_window_per_thread[MODULE_DATABASE_CAPACITY]; // maximum index is the number of modules ++thread_local struct perf_window *perf_window_per_thread = NULL; // maximum index is the number of modules +struct sandbox* current_sandboxes[1024] = { NULL }; // maximum index is number of threads extern uint32_t runtime_worker_group_size; extern FILE *sandbox_perf_log; +@@ -100,7 +101,8 @@ worker_thread_main(void *argument) + // runtime_set_pthread_prio(pthread_self(), 2); + pthread_setschedprio(pthread_self(), -20); + +- preallocate_memory(); ++ perf_window_per_thread = (struct perf_window*) malloc(sizeof(struct perf_window) * MODULE_DATABASE_CAPACITY); ++ //preallocate_memory(); + perf_window_init(); + condition_variable_init(); + semaphore_init(); From ab5df83268efcf05b3863309155a6f956eb8028e Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 26 Apr 2024 16:38:21 -0600 Subject: [PATCH 104/198] upload delete_patch.sh and apply_patch.sh --- runtime/apply_patch.sh | 1 + runtime/delete_patch.sh | 1 + 2 files changed, 2 insertions(+) create mode 100755 runtime/apply_patch.sh create mode 100755 runtime/delete_patch.sh diff --git a/runtime/apply_patch.sh b/runtime/apply_patch.sh new file mode 100755 index 000000000..2dcf8f81a --- /dev/null +++ b/runtime/apply_patch.sh @@ -0,0 +1 @@ +git apply increase_req_type.patch diff --git a/runtime/delete_patch.sh b/runtime/delete_patch.sh new file mode 100755 index 000000000..27c4ce593 --- /dev/null +++ b/runtime/delete_patch.sh @@ -0,0 +1 @@ +git apply -R increase_req_type.patch From 472425a1d3299fb60888bc6afd5cef647c8b6547 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 26 Apr 2024 16:49:10 -0600 Subject: [PATCH 105/198] upload http_router.c,copy_func_so.sh,and generate_json.py --- runtime/src/http_router.c | 3 +++ runtime/tests/copy_func_so.sh | 16 +++++++++++++ runtime/tests/generate_json.py | 42 ++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 runtime/src/http_router.c create mode 100644 runtime/tests/copy_func_so.sh create mode 100644 runtime/tests/generate_json.py diff --git a/runtime/src/http_router.c b/runtime/src/http_router.c new file mode 100644 index 000000000..be04584dd --- /dev/null +++ b/runtime/src/http_router.c @@ -0,0 +1,3 @@ +#include + +struct route *route_array = NULL; diff --git a/runtime/tests/copy_func_so.sh b/runtime/tests/copy_func_so.sh new file mode 100644 index 000000000..d7a5164ad --- /dev/null +++ b/runtime/tests/copy_func_so.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +if [ $# -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +num_copies=$1 +func_name="fibonacci" + +for i in $(seq $num_copies); do + cp $func_name".wasm.so" $func_name$i.wasm.so +done + +echo "Files copied successfully." + diff --git a/runtime/tests/generate_json.py b/runtime/tests/generate_json.py new file mode 100644 index 000000000..0836e8410 --- /dev/null +++ b/runtime/tests/generate_json.py @@ -0,0 +1,42 @@ +import sys +import json + +def generate_config(num_routes): + config = [] + for i in range(1, num_routes + 1): + route = { + "route": f"/fib{i}", + "request-type": i, + "n-resas": 2, + "path": f"fibonacci{i}.wasm.so", + #"path": "fibonacci.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + } + config.append(route) + return config + +def main(): + if len(sys.argv) != 2: + print("Usage: python script.py ") + return + + num_routes = int(sys.argv[1]) + routes = generate_config(num_routes) + + config = [{ + "name": "gwu", + "port": 31850, + "replenishment-period-us": 0, + "max-budget-us": 0, + "routes": routes + }] + + with open('config.json', 'w') as f: + json.dump(config, f, indent=4) + +if __name__ == "__main__": + main() + From eeea5a9911689769bfda19b201aeab1e0c37509e Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Sat, 27 Apr 2024 00:40:28 -0600 Subject: [PATCH 106/198] upload start_func_density_test.sh --- runtime/tests/start_func_density_test.sh | 55 ++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100755 runtime/tests/start_func_density_test.sh diff --git a/runtime/tests/start_func_density_test.sh b/runtime/tests/start_func_density_test.sh new file mode 100755 index 000000000..a97b942dd --- /dev/null +++ b/runtime/tests/start_func_density_test.sh @@ -0,0 +1,55 @@ +#!/bin/bash +ulimit -n 655350 + +function usage { + echo "$0 [worker num] [listener num] [first worker core id]" + exit 1 +} + +if [ $# != 3 ] ; then + usage + exit 1; +fi + +worker_num=$1 +listener_num=$2 +first_worker_core_id=$3 + +declare project_path="$( + cd "$(dirname "$0")/../.." + pwd +)" +echo $project_path +path=`pwd` +export SLEDGE_DISABLE_PREEMPTION=true +export SLEDGE_DISABLE_BUSY_LOOP=true +export SLEDGE_DISABLE_AUTOSCALING=true +export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=true +#export SLEDGE_SIGALRM_HANDLER=TRIAGED +export SLEDGE_FIRST_WORKER_COREID=$first_worker_core_id +export SLEDGE_NWORKERS=$worker_num +export SLEDGE_NLISTENERS=$listener_num +export SLEDGE_WORKER_GROUP_SIZE=1 +export SLEDGE_SCHEDULER=EDF +#export SLEDGE_DISPATCHER=DARC +#export SLEDGE_DISPATCHER=SHINJUKU +export SLEDGE_DISPATCHER=EDF_INTERRUPT +export SLEDGE_SANDBOX_PERF_LOG=$path/server.log +#echo $SLEDGE_SANDBOX_PERF_LOG +cd $project_path/runtime/bin +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_fibonacci.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_big_fibonacci.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_armcifar10.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_png2bmp.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_image_processing.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/mulitple_linear_chain.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing3.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/fib.json +LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/config.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/hash.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/empty.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/my_fibonacci.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_sodresize.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/my_sodresize.json + From 2b6bfcf7fd9ce61f7fe007eea7ff1c279a2adfc0 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Sat, 27 Apr 2024 00:55:35 -0600 Subject: [PATCH 107/198] update start_test.sh --- runtime/tests/start_test.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/runtime/tests/start_test.sh b/runtime/tests/start_test.sh index f4a94ece5..f7b9b4f0a 100755 --- a/runtime/tests/start_test.sh +++ b/runtime/tests/start_test.sh @@ -30,7 +30,7 @@ export SLEDGE_DISABLE_PREEMPTION=true export SLEDGE_DISABLE_BUSY_LOOP=$disable_busy_loop export SLEDGE_DISABLE_AUTOSCALING=$disable_autoscaling #export SLEDGE_SIGALRM_HANDLER=TRIAGED -export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=false +export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=true export SLEDGE_FIRST_WORKER_COREID=$first_worker_core_id export SLEDGE_NWORKERS=$worker_num export SLEDGE_NLISTENERS=$listener_num @@ -50,8 +50,9 @@ cd $project_path/runtime/bin #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/mulitple_linear_chain.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing3.json -LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/hash.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/hash.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/empty.json +LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/fib.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/my_fibonacci.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_sodresize.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/my_sodresize.json From c6d65aa63c1ba40a7d8beb79051e7492896c6a2b Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 30 Apr 2024 12:15:14 -0600 Subject: [PATCH 108/198] update Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 809428a17..4ff4ab7f2 100644 --- a/Makefile +++ b/Makefile @@ -52,7 +52,7 @@ applications.clean: # Instead of having two copies of wasm_apps, just link to the awsm repo's copy wasm_apps: - ln -sr awsm/applications/wasm_apps/ applications/ + cd awsm/applications/wasm_apps && git checkout master && cd ../../../ && ln -sr awsm/applications/wasm_apps/ applications/ # Tests .PHONY: test From b6878ab3abb70e552861e021cb899644057d873a Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 1 May 2024 16:06:28 -0600 Subject: [PATCH 109/198] 1.commend explicit_bzero stack memory when sandbox exit 2. update start_test.sh --- runtime/include/wasm_stack.h | 2 +- runtime/tests/start_test.sh | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/runtime/include/wasm_stack.h b/runtime/include/wasm_stack.h index 4926a41d2..b471f5e28 100644 --- a/runtime/include/wasm_stack.h +++ b/runtime/include/wasm_stack.h @@ -126,6 +126,6 @@ wasm_stack_reinit(struct wasm_stack *wasm_stack) assert(wasm_stack->buffer != NULL); assert(wasm_stack->low == wasm_stack->buffer + /* guard page */ PAGE_SIZE); assert(wasm_stack->high == wasm_stack->low + wasm_stack->capacity); - explicit_bzero(wasm_stack->sp, wasm_stack->high - wasm_stack->sp); + //explicit_bzero(wasm_stack->sp, wasm_stack->high - wasm_stack->sp); ps_list_init_d(wasm_stack); } diff --git a/runtime/tests/start_test.sh b/runtime/tests/start_test.sh index f7b9b4f0a..d11cf4a19 100755 --- a/runtime/tests/start_test.sh +++ b/runtime/tests/start_test.sh @@ -2,11 +2,11 @@ ulimit -n 655350 function usage { - echo "$0 [worker num] [listener num] [first worker core id] [dispatcher policy, SHINJUKU or EDF_INTERRUPT or DARC] [server log file] [disable busy loop] [disable autoscaling]" + echo "$0 [worker num] [listener num] [first worker core id] [dispatcher policy, SHINJUKU or EDF_INTERRUPT or DARC] [server log file] [disable busy loop] [disable autoscaling] [disable service time simulation] [json config]" exit 1 } -if [ $# != 7 ] ; then +if [ $# != 9 ] ; then usage exit 1; fi @@ -18,6 +18,9 @@ dispatcher_policy=$4 server_log=$5 disable_busy_loop=$6 disable_autoscaling=$7 +disable_service_ts_simulation=$8 +json_config=$9 + worker_group_size=$((worker_num / listener_num)) declare project_path="$( @@ -30,7 +33,7 @@ export SLEDGE_DISABLE_PREEMPTION=true export SLEDGE_DISABLE_BUSY_LOOP=$disable_busy_loop export SLEDGE_DISABLE_AUTOSCALING=$disable_autoscaling #export SLEDGE_SIGALRM_HANDLER=TRIAGED -export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=true +export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=$disable_service_ts_simulation export SLEDGE_FIRST_WORKER_COREID=$first_worker_core_id export SLEDGE_NWORKERS=$worker_num export SLEDGE_NLISTENERS=$listener_num @@ -52,7 +55,8 @@ cd $project_path/runtime/bin #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing3.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/hash.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/empty.json -LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/fib.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/fib.json +LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/$json_config #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/my_fibonacci.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_sodresize.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/my_sodresize.json From 9218209b4cc577046603f9df4d06af8cd1e5cda6 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Mon, 6 May 2024 15:44:20 -0600 Subject: [PATCH 110/198] fix DARC bug: the long requests and short requests share cpu cores and not seperate --- runtime/include/scheduler.h | 4 +--- runtime/include/tenant_functions.h | 15 ++++++++---- runtime/src/listener_thread.c | 6 +++-- runtime/src/local_preempted_fifo_queue.c | 3 --- runtime/src/request_typed_queue.c | 30 ++++++++++++++---------- 5 files changed, 34 insertions(+), 24 deletions(-) diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index 9366b6410..fb7f8a271 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -326,7 +326,7 @@ scheduler_process_policy_specific_updates_on_interrupts(struct sandbox *interrup } /** - * Called by the SIGALRM handler after a quantum + * Called by the SIGALRM handler after a quantum, this function can only be called by SHINJUKU or EDF_INTERRUPT * Assumes the caller validates that there is something to preempt * @param interrupted_context - The context of our user-level Worker thread * @returns the sandbox that the scheduler chose to run @@ -572,12 +572,10 @@ scheduler_cooperative_sched(bool add_to_cleanup_queue) /* Logging this sandbox to memory */ sandbox_perf_log_print_entry(exiting_sandbox); - if (next_sandbox != NULL) { next_sandbox->context_switch_to = 2; scheduler_cooperative_switch_to(exiting_context, next_sandbox); } else { - //if (dispatcher == DISPATCHER_DARC || dispatcher == DISPATCHER_SHINJUKU) { if (dispatcher == DISPATCHER_DARC) { int virtual_id = global_worker_thread_idx - dispatcher_id * runtime_worker_group_size; atomic_fetch_or(&free_workers[dispatcher_id], 1 << virtual_id); diff --git a/runtime/include/tenant_functions.h b/runtime/include/tenant_functions.h index f4e02c19d..396dddc83 100644 --- a/runtime/include/tenant_functions.h +++ b/runtime/include/tenant_functions.h @@ -192,12 +192,19 @@ tenant_perf_window_init(struct tenant *tenant, void *arg1, void *arg2) { static inline void tenant_request_typed_queue_init(struct tenant *tenant, void *arg1, void *arg2) { - for(int i = 0; i < tenant->routes_len; i++) { + + if (dispatcher == DISPATCHER_SHINJUKU) { + for(int i = 0; i < tenant->routes_len; i++) { + request_type_deque[tenant->routes_config[i].request_type - 1] = + request_typed_deque_init(tenant->routes_config[i].request_type, 4096); + } + + } else if (dispatcher == DISPATCHER_DARC) { + for(int i = 0; i < tenant->routes_len; i++) { request_type_queue[tenant->routes_config[i].request_type - 1] = request_typed_queue_init(tenant->routes_config[i].request_type, tenant->routes_config[i].n_resas); - request_type_deque[tenant->routes_config[i].request_type - 1] = - request_typed_deque_init(tenant->routes_config[i].request_type, 4096); - } + } + } n_rtypes = tenant->routes_len; } diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 35c142086..70293b595 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -19,7 +19,7 @@ #include "request_typed_deque.h" #include "local_preempted_fifo_queue.h" -#define INTERRUPT_INTERVAL 50 +#define INTERRUPT_INTERVAL 15 #define BASE_SERVICE_TIME 10 #define LOSS_PERCENTAGE 0.11 @@ -56,6 +56,7 @@ extern _Atomic uint64_t request_index; extern uint32_t runtime_worker_group_size; extern struct sandbox* current_sandboxes[1024]; +thread_local uint32_t current_reserved = 0; thread_local uint32_t dispatcher_try_interrupts = 0; thread_local uint32_t worker_start_id; thread_local uint32_t worker_end_id; @@ -780,6 +781,7 @@ void drain_queue(struct request_typed_queue *rtype) { } // No peer found if (worker_id == MAX_WORKERS + 1) { + //printf("No availabe worker\n"); return; } @@ -925,8 +927,8 @@ void shinjuku_dispatch() { while(preempted_sandbox != NULL) { uint8_t req_type = preempted_sandbox->route->request_type; insertfront(request_type_deque[req_type - 1], preempted_sandbox, tsc); - global_queue_length++; //insertrear(request_type_deque[req_type - 1], preempted_sandbox, tsc); + global_queue_length++; preempted_sandbox = pop_worker_preempted_queue(worker_list[true_idx], preempted_queue, &tsc); } /* core is idle */ diff --git a/runtime/src/local_preempted_fifo_queue.c b/runtime/src/local_preempted_fifo_queue.c index 0c346ef27..21f587025 100644 --- a/runtime/src/local_preempted_fifo_queue.c +++ b/runtime/src/local_preempted_fifo_queue.c @@ -10,9 +10,6 @@ extern thread_local int global_worker_thread_idx; extern struct request_fifo_queue * worker_preempted_queue[1024]; thread_local static struct request_fifo_queue * local_preempted_queue = NULL; -/* - * n_resas the number of reserved workers. Leaving the last n_resas workers as the reserved workers - */ struct request_fifo_queue * request_fifo_queue_init() { struct request_fifo_queue * queue = (struct request_fifo_queue*) malloc(sizeof(struct request_fifo_queue)); diff --git a/runtime/src/request_typed_queue.c b/runtime/src/request_typed_queue.c index 00135cf65..e4e4c4c5f 100644 --- a/runtime/src/request_typed_queue.c +++ b/runtime/src/request_typed_queue.c @@ -1,10 +1,14 @@ #include #include +#include #include "panic.h" #include "likely.h" #include "request_typed_queue.h" +extern thread_local uint32_t current_reserved; +extern thread_local uint8_t dispatcher_thread_idx; + struct request_typed_queue * request_typed_queue_init(uint8_t type, uint32_t n_resas) { struct request_typed_queue *queue = malloc(sizeof(struct request_typed_queue)); @@ -15,16 +19,21 @@ request_typed_queue_init(uint8_t type, uint32_t n_resas) { queue->rqueue_head = 0; queue->n_resas = n_resas; for (unsigned int i = 0; i < n_resas; ++i) { - queue->res_workers[i] = i; + queue->res_workers[i] = current_reserved++; } - queue->n_stealable = runtime_worker_group_size - n_resas; - int index = 0; - for (unsigned int i = n_resas; i < runtime_worker_group_size; i++) { - queue->stealable_workers[index] = i; - index++; + for (unsigned int i = current_reserved; i < runtime_worker_group_size; i++) { + queue->stealable_workers[queue->n_stealable++] = i; } + if (queue->n_stealable == 0) { + printf("Listener %u reserve %u cores (from %u to %u) to request type %u, can steal 0 core\n", + dispatcher_thread_idx, n_resas, queue->res_workers[0], queue->res_workers[n_resas-1], type); + } else { + printf("Listener %u reserve %u cores (from %u to %u) to request type %u, can steal cores %u(from %u to %u)\n", + dispatcher_thread_idx, n_resas, queue->res_workers[0], queue->res_workers[n_resas-1], type, + queue->n_stealable, queue->stealable_workers[0], queue->stealable_workers[queue->n_stealable-1]); + } memset(queue->rqueue, 0, RQUEUE_LEN * sizeof(struct sandbox*)); return queue; @@ -34,15 +43,12 @@ request_typed_queue_init(uint8_t type, uint32_t n_resas) { int push_to_rqueue(struct sandbox *sandbox, struct request_typed_queue *rtype, uint64_t tsc) { assert(sandbox != NULL); - uint32_t head = rtype->rqueue_head; - - if (unlikely(head - rtype->rqueue_tail == RQUEUE_LEN)) { + if (unlikely(rtype->rqueue_head - rtype->rqueue_tail == RQUEUE_LEN)) { panic("Dispatcher dropped request as type %hhu because queue is full\n", rtype->type); return -1; } else { - rtype->tsqueue[head & (RQUEUE_LEN - 1)] = tsc; - rtype->rqueue[head & (RQUEUE_LEN - 1)] = sandbox; - rtype->rqueue_head++; + rtype->tsqueue[rtype->rqueue_head & (RQUEUE_LEN - 1)] = tsc; + rtype->rqueue[rtype->rqueue_head++ & (RQUEUE_LEN - 1)] = sandbox; return 0; } } From 7f54a2cb346acc040731f05119ae172aa1746841 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Mon, 6 May 2024 15:52:16 -0600 Subject: [PATCH 111/198] update fib.json --- runtime/tests/fib.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/tests/fib.json b/runtime/tests/fib.json index 47604108a..e8bf8fb67 100644 --- a/runtime/tests/fib.json +++ b/runtime/tests/fib.json @@ -8,7 +8,7 @@ { "route": "/fib", "request-type": 1, - "n-resas": 2, + "n-resas": 1, "path": "fibonacci.wasm.so", "admissions-percentile": 70, "expected-execution-us": 5, @@ -18,7 +18,7 @@ { "route": "/fib2", "request-type": 2, - "n-resas": 1, + "n-resas": 2, "path": "fibonacci.wasm.so", "admissions-percentile": 70, "expected-execution-us": 6480, From b91e4a71c3924e35a6331e79cbd956fec3e46ff3 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 8 May 2024 12:06:33 -0600 Subject: [PATCH 112/198] upload dummy_func_DARC.json dummy_func_EDF_SHINJUKU.json --- runtime/tests/dummy_func_DARC.json | 43 +++++++++++++++ runtime/tests/dummy_func_EDF_SHINJUKU.json | 64 ++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 runtime/tests/dummy_func_DARC.json create mode 100644 runtime/tests/dummy_func_EDF_SHINJUKU.json diff --git a/runtime/tests/dummy_func_DARC.json b/runtime/tests/dummy_func_DARC.json new file mode 100644 index 000000000..803f31c75 --- /dev/null +++ b/runtime/tests/dummy_func_DARC.json @@ -0,0 +1,43 @@ +[ + { + "name": "gwu", + "port": 31850, + "replenishment-period-us": 0, + "max-budget-us": 0, + "routes": [ + { + "route": "/Payment-OrderStatus", + "request-type": 1, + "n-resas": 1, + "path": "dummy_func.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 5, + "relative-deadline-us": 50, + "http-resp-content-type": "text/plain" + }, + { + "route": "/NewOrder", + "request-type": 2, + "n-resas": 2, + "path": "dummy_func.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 5, + "relative-deadline-us": 50, + "http-resp-content-type": "text/plain" + }, + { + "route": "/Delivery-StockLevel", + "request-type": 3, + "n-resas": 2, + "path": "dummy_func.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 5, + "relative-deadline-us": 50, + "http-resp-content-type": "text/plain" + } + ] + + } + +] + diff --git a/runtime/tests/dummy_func_EDF_SHINJUKU.json b/runtime/tests/dummy_func_EDF_SHINJUKU.json new file mode 100644 index 000000000..1776dedc4 --- /dev/null +++ b/runtime/tests/dummy_func_EDF_SHINJUKU.json @@ -0,0 +1,64 @@ +[ + { + "name": "gwu", + "port": 31850, + "replenishment-period-us": 0, + "max-budget-us": 0, + "routes": [ + { + "route": "/Payment", + "request-type": 1, + "n-resas": 1, + "path": "dummy_func.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 6, + "relative-deadline-us": 60, + "http-resp-content-type": "text/plain" + }, + { + "route": "/OrderStatus", + "request-type": 2, + "n-resas": 1, + "path": "dummy_func.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 6, + "relative-deadline-us": 60, + "http-resp-content-type": "text/plain" + }, + { + "route": "/NewOrder", + "request-type": 3, + "n-resas": 1, + "path": "dummy_func.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 20, + "relative-deadline-us": 200, + "http-resp-content-type": "text/plain" + }, + { + "route": "/Delivery", + "request-type": 4, + "n-resas": 1, + "path": "dummy_func.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 88, + "relative-deadline-us": 880, + "http-resp-content-type": "text/plain" + }, + { + "route": "/StockLevel", + "request-type": 5, + "n-resas": 1, + "path": "dummy_func.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 100, + "relative-deadline-us": 1000, + "http-resp-content-type": "text/plain" + } + + ] + + } + +] + From 2d0c985bda982db313eee9ebb0f40b014c5a3b8f Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 9 May 2024 16:55:36 -0600 Subject: [PATCH 113/198] upload tests/config.json --- runtime/tests/config.json | 330 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 330 insertions(+) create mode 100644 runtime/tests/config.json diff --git a/runtime/tests/config.json b/runtime/tests/config.json new file mode 100644 index 000000000..3605cfb76 --- /dev/null +++ b/runtime/tests/config.json @@ -0,0 +1,330 @@ +[ + { + "name": "gwu", + "port": 31850, + "replenishment-period-us": 0, + "max-budget-us": 0, + "routes": [ + { + "route": "/fib1", + "request-type": 1, + "n-resas": 2, + "path": "fibonacci1.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib2", + "request-type": 2, + "n-resas": 2, + "path": "fibonacci2.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib3", + "request-type": 3, + "n-resas": 2, + "path": "fibonacci3.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib4", + "request-type": 4, + "n-resas": 2, + "path": "fibonacci4.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib5", + "request-type": 5, + "n-resas": 2, + "path": "fibonacci5.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib6", + "request-type": 6, + "n-resas": 2, + "path": "fibonacci6.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib7", + "request-type": 7, + "n-resas": 2, + "path": "fibonacci7.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib8", + "request-type": 8, + "n-resas": 2, + "path": "fibonacci8.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib9", + "request-type": 9, + "n-resas": 2, + "path": "fibonacci9.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib10", + "request-type": 10, + "n-resas": 2, + "path": "fibonacci10.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib11", + "request-type": 11, + "n-resas": 2, + "path": "fibonacci11.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib12", + "request-type": 12, + "n-resas": 2, + "path": "fibonacci12.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib13", + "request-type": 13, + "n-resas": 2, + "path": "fibonacci13.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib14", + "request-type": 14, + "n-resas": 2, + "path": "fibonacci14.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib15", + "request-type": 15, + "n-resas": 2, + "path": "fibonacci15.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib16", + "request-type": 16, + "n-resas": 2, + "path": "fibonacci16.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib17", + "request-type": 17, + "n-resas": 2, + "path": "fibonacci17.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib18", + "request-type": 18, + "n-resas": 2, + "path": "fibonacci18.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib19", + "request-type": 19, + "n-resas": 2, + "path": "fibonacci19.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib20", + "request-type": 20, + "n-resas": 2, + "path": "fibonacci20.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib21", + "request-type": 21, + "n-resas": 2, + "path": "fibonacci21.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib22", + "request-type": 22, + "n-resas": 2, + "path": "fibonacci22.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib23", + "request-type": 23, + "n-resas": 2, + "path": "fibonacci23.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib24", + "request-type": 24, + "n-resas": 2, + "path": "fibonacci24.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib25", + "request-type": 25, + "n-resas": 2, + "path": "fibonacci25.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib26", + "request-type": 26, + "n-resas": 2, + "path": "fibonacci26.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib27", + "request-type": 27, + "n-resas": 2, + "path": "fibonacci27.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib28", + "request-type": 28, + "n-resas": 2, + "path": "fibonacci28.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib29", + "request-type": 29, + "n-resas": 2, + "path": "fibonacci29.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib30", + "request-type": 30, + "n-resas": 2, + "path": "fibonacci30.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib31", + "request-type": 31, + "n-resas": 2, + "path": "fibonacci31.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + }, + { + "route": "/fib32", + "request-type": 32, + "n-resas": 2, + "path": "fibonacci32.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 1, + "relative-deadline-us": 10, + "http-resp-content-type": "text/plain" + } + ] + } +] \ No newline at end of file From d40bce8be89decaf85c0d0348bf4ad2acc2ef892 Mon Sep 17 00:00:00 2001 From: xiaosuGW Date: Sat, 11 May 2024 20:41:51 -0600 Subject: [PATCH 114/198] fix implementation bug: not use binary search tree property to search the node --- runtime/include/binary_search_tree.h | 222 +++++++++++++++-------- runtime/src/local_runqueue_binary_tree.c | 8 +- 2 files changed, 151 insertions(+), 79 deletions(-) diff --git a/runtime/include/binary_search_tree.h b/runtime/include/binary_search_tree.h index 9543f618a..bd654a7b7 100644 --- a/runtime/include/binary_search_tree.h +++ b/runtime/include/binary_search_tree.h @@ -16,6 +16,8 @@ struct TreeNode { struct TreeNode *right; struct TreeNode *next; // pointing to the next node, this is used for nodePool // to find next available node + struct TreeNode *dup_next; // pointing to next duplicate key item + uint64_t left_subtree_sum; void *data; // sandbox }; @@ -32,6 +34,7 @@ struct binary_tree { lock_t lock; bool use_lock; int id; + int queue_length; }; // Initialize the node pool @@ -46,6 +49,8 @@ void initNodePool(struct TreeNodePool *nodePool, int pool_size) { nodes[i].next = &nodes[i + 1]; // Set the next pointer of each node to the next node nodes[i].left = NULL; nodes[i].right = NULL; + nodes[i].dup_next = NULL; + nodes[i].left_subtree_sum = 0; nodes[i].data = NULL; } nodes[MAX_NODES - 1].next = NULL; @@ -63,30 +68,17 @@ struct binary_tree * init_binary_tree(bool use_lock, binary_tree_get_priority_fn binary_tree->get_execution_cost_fn = get_execution_cost_fn; binary_tree->use_lock = use_lock; binary_tree->id = id; + binary_tree->queue_length = 0; if (binary_tree->use_lock) lock_init(&binary_tree->lock); return binary_tree; } -// Helper function for counting non-deleted nodes in the binary tree -static int countNonDeletedNodesRec(struct TreeNode* root) { - if (root == NULL) { - return 0; - } - - // Only count nodes that are not marked as deleted - if (root->data != NULL) { - return 1 + countNonDeletedNodesRec(root->left) + countNonDeletedNodesRec(root->right); - } else { - return countNonDeletedNodesRec(root->left) + countNonDeletedNodesRec(root->right); - } -} - // Function to get the total number of non-deleted nodes in the binary tree int getNonDeletedNodeCount(struct binary_tree *binary_tree) { assert(binary_tree != NULL); - return countNonDeletedNodesRec(binary_tree->root); + return binary_tree->queue_length; } // Get a new node from the pool @@ -105,6 +97,8 @@ struct TreeNode* newNode(struct binary_tree *binary_tree, void *data) { new_node_t->data = data; new_node_t->left = NULL; new_node_t->right = NULL; + new_node_t->dup_next = NULL; + new_node_t->left_subtree_sum = 0; return new_node_t; } } @@ -130,9 +124,15 @@ void print_in_order(struct TreeNode* node) { // Print the data in the current node if (node->data) { - mem_log("%lu(%lu) ", ((struct sandbox *)node->data)->absolute_deadline, ((struct sandbox *)node->data)->estimated_cost); + mem_log("%lu(%lu) ", ((struct sandbox *)node->data)->absolute_deadline, ((struct sandbox *)node->data)->estimated_cost); } - + //Print data in the dup_next list + struct TreeNode* cur = node->dup_next; + while(cur) { + mem_log("%lu(%lu) ", ((struct sandbox *)cur->data)->absolute_deadline, ((struct sandbox *)cur->data)->estimated_cost); + cur = cur->dup_next; + } + // Recursively traverse the right subtree print_in_order(node->right); } @@ -146,6 +146,18 @@ void print_tree_in_order(struct binary_tree* bst) { } } +//get the total execute time of a node. +uint64_t get_sum_exe_time_of_node(struct binary_tree *binary_tree, struct TreeNode* node, int thread_id){ + uint64_t total = 0; + struct TreeNode* curNode = node; + while (curNode!=NULL) { + total += binary_tree->get_execution_cost_fn(curNode->data, thread_id); + curNode = curNode->dup_next; + } + + return total; +} + // Return a node to the pool void deleteNode(struct binary_tree *binary_tree, struct TreeNode* node) { @@ -156,6 +168,8 @@ void deleteNode(struct binary_tree *binary_tree, struct TreeNode* node) { node->left = NULL; node->right = NULL; node->data = NULL; + node->left_subtree_sum = 0; + node->dup_next = NULL; node->next = binary_tree->nodePool.head; binary_tree->nodePool.head = node; } @@ -171,18 +185,34 @@ int findHeight(struct TreeNode *root) } // Function to insert a value into a binary search tree -struct TreeNode* insert(struct binary_tree *binary_tree, struct TreeNode* root, void *data) { +struct TreeNode* insert(struct binary_tree *binary_tree, struct TreeNode* root, void *data, int thread_id) { assert(binary_tree != NULL); if (root == NULL) { + binary_tree->queue_length++; return newNode(binary_tree, data); // Create a new node for an empty tree } - if (binary_tree->get_priority_fn(data) <= binary_tree->get_priority_fn(root->data)) { - root->left = insert(binary_tree, root->left, data); // Insert into the left subtree + if (binary_tree->get_priority_fn(data) == binary_tree->get_priority_fn(root->data)) { + //go to the tail of clone chain + struct TreeNode* tail = root; + while (tail->dup_next != NULL){ + tail = tail->dup_next; + } + + //append the new node to the chain + struct TreeNode* new_node = newNode(binary_tree, data); + tail->dup_next = new_node; + binary_tree->queue_length++; + return root; + } + + if (binary_tree->get_priority_fn(data) < binary_tree->get_priority_fn(root->data)) { + root->left = insert(binary_tree, root->left, data, thread_id); // Insert into the left subtree + root->left_subtree_sum += binary_tree->get_execution_cost_fn(data, thread_id); } else { - root->right = insert(binary_tree, root->right, data); // Insert into the right subtree + root->right = insert(binary_tree, root->right, data, thread_id); // Insert into the right subtree } return root; } @@ -220,54 +250,109 @@ struct TreeNode* findMax(struct binary_tree *binary_tree, struct TreeNode *root) return root; } +struct TreeNode* remove_node_from_dup_list(struct binary_tree *binary_tree, struct TreeNode* root, void *data, bool *deleted) { + if (root->data == data) { + root->dup_next->left = root->left; + root->dup_next->right = root->right; + root->dup_next->left_subtree_sum = root->left_subtree_sum; + //free old root + struct TreeNode* new_root = root->dup_next; + deleteNode(binary_tree, root); + *deleted = true; + binary_tree->queue_length--; + return new_root; + } else { + struct TreeNode* cur = root->dup_next; + struct TreeNode* pre = root; + while(cur) { + if (cur->data == data) { + pre->dup_next = cur->dup_next; + //free cur + deleteNode(binary_tree, cur); + *deleted = true; + binary_tree->queue_length--; + return root; + } else { + pre = cur; + cur = cur->dup_next; + } + } + *deleted = false; + return root; + } +} + // Function to delete a value from a binary search tree -struct TreeNode* delete_i(struct binary_tree *binary_tree, struct TreeNode* root, void *data, bool *deleted) { +struct TreeNode* delete_i(struct binary_tree *binary_tree, struct TreeNode* root, void *data, bool *deleted, int thread_id) { assert(binary_tree != NULL); if (root == NULL) { - *deleted = false; + *deleted = false; return NULL; } int64_t cmp_result = binary_tree->get_priority_fn(data) - binary_tree->get_priority_fn(root->data); if (cmp_result < 0) { - root->left = delete_i(binary_tree, root->left, data, deleted); + root->left_subtree_sum -= binary_tree->get_execution_cost_fn(data, thread_id); + root->left = delete_i(binary_tree, root->left, data, deleted, thread_id); + return root; } else if (cmp_result > 0) { - root->right = delete_i(binary_tree, root->right, data, deleted); + root->right = delete_i(binary_tree, root->right, data, deleted, thread_id); + return root; } else { // cmp_result == 0 - if (root->data == data) { - if (root->left == NULL) { - struct TreeNode* temp = root->right; - deleteNode(binary_tree, root); - *deleted = true; - return temp; - } else if (root->right == NULL) { - struct TreeNode* temp = root->left; - deleteNode(binary_tree, root); - *deleted = true; - return temp; - } else { - struct TreeNode* successor = root->right; - while (successor->left != NULL) { - successor = successor->left; - } - root->data = successor->data; - root->right = delete_i(binary_tree, root->right, successor->data, deleted); - return root; - } + // The deleted node might either be the root or in the dup_next list + if (root->dup_next != NULL) { + struct TreeNode* new_root = remove_node_from_dup_list(binary_tree, root, data, deleted); + return new_root; + } + // If key is same as root's key, then this is the node to be deleted + // Node with only one child or no child + if (root->left == NULL) { + struct TreeNode* temp = root->right; + deleteNode(binary_tree, root); + *deleted = true; + binary_tree->queue_length--; + return temp; + } else if (root->right == NULL) { + struct TreeNode* temp = root->left; + deleteNode(binary_tree, root); + *deleted = true; + binary_tree->queue_length--; + return temp; } else { - // Continue searching for the node with the same data pointer - if (root->left != NULL) { - root->left = delete_i(binary_tree, root->left, data, deleted); + // Node with two children: Get the inorder successor(smallest in the right subtree) + struct TreeNode* succParent = root; + struct TreeNode* succ = root->right; + while (succ->left != NULL) { + succParent = succ; + succ = succ->left; + } + // Copy the inorder successor's content to this node, left_subtree_sum is not changed + root->data = succ->data; + root->dup_next = succ->dup_next; + //update the sum_less_than of the nodes affected by the removed node. + int removed_exe_time = get_sum_exe_time_of_node(binary_tree, succ, thread_id); + struct TreeNode* temp = root->right; + while (temp->left != NULL) { + temp->left_subtree_sum -= removed_exe_time; + temp = temp->left; } - if (*deleted == false && root->right != NULL) { - root->right = delete_i(binary_tree, root->right, data, deleted); + // Delete the inorder successor + if (succParent->left == succ) { + succParent->left = succ->right; + } else { + succParent->right = succ->right; } + + deleteNode(binary_tree, succ); + *deleted = true; + binary_tree->queue_length--; + return root; } - } - return root; + + } } @@ -301,34 +386,21 @@ void inorder(struct binary_tree *binary_tree, struct TreeNode* root) printf("%lu ", binary_tree->get_priority_fn(root->data)); inorder(binary_tree, root->right); } - -struct TreeNode* findMaxValueLessThan(struct binary_tree *binary_tree, struct TreeNode* root, void *target, uint64_t *sum, int thread_id) { - +// return the sum of nodes' execution time that less than the target priority +uint64_t findMaxValueLessThan(struct binary_tree *binary_tree, struct TreeNode* root, void *target, int thread_id) { assert(binary_tree != NULL); - + if (root == NULL) { - return NULL; // Base case: empty node, return NULL - } - - struct TreeNode* maxNode = NULL; // Initialize the node containing the maximum value to NULL - - // In-order traversal of the binary tree - struct TreeNode* leftMaxNode = findMaxValueLessThan(binary_tree, root->left, target, sum, thread_id); // Traverse left subtree - if (binary_tree->get_priority_fn(root->data) <= binary_tree->get_priority_fn(target)) { - *sum += binary_tree->get_execution_cost_fn(root->data, thread_id); // Add the current node's value to the sum - maxNode = root; // Update the maximum node - } - struct TreeNode* rightMaxNode = findMaxValueLessThan(binary_tree, root->right, target, sum, thread_id); // Traverse right subtree - - // Update the maximum node with the maximum node from left and right subtrees - if (leftMaxNode != NULL && (maxNode == NULL || binary_tree->get_priority_fn(leftMaxNode->data) > binary_tree->get_priority_fn(maxNode->data))) { - maxNode = leftMaxNode; + return 0; } - if (rightMaxNode != NULL && (maxNode == NULL || binary_tree->get_priority_fn(rightMaxNode->data) > binary_tree->get_priority_fn(maxNode->data))) { - maxNode = rightMaxNode; + if (binary_tree->get_priority_fn(target) == binary_tree->get_priority_fn(root->data)) { + return root->left_subtree_sum; + } else if (binary_tree->get_priority_fn(target) < binary_tree->get_priority_fn(root->data)) { + return findMaxValueLessThan(binary_tree, root->left, target, thread_id); + } else { + return get_sum_exe_time_of_node(binary_tree, root, thread_id) + root->left_subtree_sum + findMaxValueLessThan(binary_tree, root->right, target, thread_id); } - return maxNode; } struct TreeNode* makeEmpty(struct binary_tree *binary_tree, struct TreeNode* root) diff --git a/runtime/src/local_runqueue_binary_tree.c b/runtime/src/local_runqueue_binary_tree.c index 4062ec83e..486ccd2d7 100644 --- a/runtime/src/local_runqueue_binary_tree.c +++ b/runtime/src/local_runqueue_binary_tree.c @@ -62,7 +62,7 @@ local_runqueue_binary_tree_add(struct sandbox *sandbox) lock_node_t node_lock = {}; lock_lock(&local_runqueue_binary_tree->lock, &node_lock); - local_runqueue_binary_tree->root = insert(local_runqueue_binary_tree, local_runqueue_binary_tree->root, sandbox); + local_runqueue_binary_tree->root = insert(local_runqueue_binary_tree, local_runqueue_binary_tree->root, sandbox, global_worker_thread_idx); lock_unlock(&local_runqueue_binary_tree->lock, &node_lock); } @@ -74,7 +74,7 @@ local_runqueue_binary_tree_add_index(int index, struct sandbox *sandbox) struct binary_tree *binary_tree = worker_binary_trees[index]; lock_node_t node_lock = {}; lock_lock(&binary_tree->lock, &node_lock); - binary_tree->root = insert(binary_tree, binary_tree->root, sandbox); + binary_tree->root = insert(binary_tree, binary_tree->root, sandbox, index); lock_unlock(&binary_tree->lock, &node_lock); atomic_fetch_add(&local_queue_length[index], 1); @@ -125,7 +125,7 @@ local_runqueue_binary_tree_delete(struct sandbox *sandbox) lock_node_t node_lock = {}; lock_lock(&local_runqueue_binary_tree->lock, &node_lock); bool deleted = false; - local_runqueue_binary_tree->root = delete_i(local_runqueue_binary_tree, local_runqueue_binary_tree->root, sandbox, &deleted); + local_runqueue_binary_tree->root = delete_i(local_runqueue_binary_tree, local_runqueue_binary_tree->root, sandbox, &deleted, global_worker_thread_idx); lock_unlock(&local_runqueue_binary_tree->lock, &node_lock); if (deleted == false) { panic("Tried to delete sandbox %lu state %d from runqueue %p, but was not present\n", @@ -186,7 +186,7 @@ local_runqueue_binary_tree_try_add_index(int index, struct sandbox *sandbox, boo uint64_t waiting_serving_time = 0; lock_node_t node_lock = {}; lock_lock(&binary_tree->lock, &node_lock); - struct TreeNode* node = findMaxValueLessThan(binary_tree, binary_tree->root, sandbox, &waiting_serving_time, index); + waiting_serving_time = findMaxValueLessThan(binary_tree, binary_tree->root, sandbox, index); lock_unlock(&binary_tree->lock, &node_lock); return waiting_serving_time; } From 9b247cd69709b0f795b1286fff9d69f8d90b2d1f Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Sat, 11 May 2024 21:38:04 -0600 Subject: [PATCH 115/198] rename dummy_func_DARC.json to dummy_tpcc_DARC.json, dummy_func_EDF_SHINJUKU.json to dummy_tpcc_EDF_SHINJUKU.json --- .../{dummy_func_DARC.json => dummy_tpcc_DARC.json} | 10 +++++----- ..._EDF_SHINJUKU.json => dummy_tpcc_EDF_SHINJUKU.json} | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) rename runtime/tests/{dummy_func_DARC.json => dummy_tpcc_DARC.json} (85%) rename runtime/tests/{dummy_func_EDF_SHINJUKU.json => dummy_tpcc_EDF_SHINJUKU.json} (88%) diff --git a/runtime/tests/dummy_func_DARC.json b/runtime/tests/dummy_tpcc_DARC.json similarity index 85% rename from runtime/tests/dummy_func_DARC.json rename to runtime/tests/dummy_tpcc_DARC.json index 803f31c75..5a7c1a1e6 100644 --- a/runtime/tests/dummy_func_DARC.json +++ b/runtime/tests/dummy_tpcc_DARC.json @@ -9,7 +9,7 @@ "route": "/Payment-OrderStatus", "request-type": 1, "n-resas": 1, - "path": "dummy_func.wasm.so", + "path": "dummy_tpcc.wasm.so", "admissions-percentile": 70, "expected-execution-us": 5, "relative-deadline-us": 50, @@ -18,8 +18,8 @@ { "route": "/NewOrder", "request-type": 2, - "n-resas": 2, - "path": "dummy_func.wasm.so", + "n-resas": 3, + "path": "dummy_tpcc.wasm.so", "admissions-percentile": 70, "expected-execution-us": 5, "relative-deadline-us": 50, @@ -28,8 +28,8 @@ { "route": "/Delivery-StockLevel", "request-type": 3, - "n-resas": 2, - "path": "dummy_func.wasm.so", + "n-resas": 3, + "path": "dummy_tpcc.wasm.so", "admissions-percentile": 70, "expected-execution-us": 5, "relative-deadline-us": 50, diff --git a/runtime/tests/dummy_func_EDF_SHINJUKU.json b/runtime/tests/dummy_tpcc_EDF_SHINJUKU.json similarity index 88% rename from runtime/tests/dummy_func_EDF_SHINJUKU.json rename to runtime/tests/dummy_tpcc_EDF_SHINJUKU.json index 1776dedc4..206651aee 100644 --- a/runtime/tests/dummy_func_EDF_SHINJUKU.json +++ b/runtime/tests/dummy_tpcc_EDF_SHINJUKU.json @@ -9,7 +9,7 @@ "route": "/Payment", "request-type": 1, "n-resas": 1, - "path": "dummy_func.wasm.so", + "path": "dummy_tpcc.wasm.so", "admissions-percentile": 70, "expected-execution-us": 6, "relative-deadline-us": 60, @@ -19,7 +19,7 @@ "route": "/OrderStatus", "request-type": 2, "n-resas": 1, - "path": "dummy_func.wasm.so", + "path": "dummy_tpcc.wasm.so", "admissions-percentile": 70, "expected-execution-us": 6, "relative-deadline-us": 60, @@ -29,7 +29,7 @@ "route": "/NewOrder", "request-type": 3, "n-resas": 1, - "path": "dummy_func.wasm.so", + "path": "dummy_tpcc.wasm.so", "admissions-percentile": 70, "expected-execution-us": 20, "relative-deadline-us": 200, @@ -39,7 +39,7 @@ "route": "/Delivery", "request-type": 4, "n-resas": 1, - "path": "dummy_func.wasm.so", + "path": "dummy_tpcc.wasm.so", "admissions-percentile": 70, "expected-execution-us": 88, "relative-deadline-us": 880, @@ -49,7 +49,7 @@ "route": "/StockLevel", "request-type": 5, "n-resas": 1, - "path": "dummy_func.wasm.so", + "path": "dummy_tpcc.wasm.so", "admissions-percentile": 70, "expected-execution-us": 100, "relative-deadline-us": 1000, From 023e7cadb640c65bf27ffa4a0f665df34fd48570 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Sat, 11 May 2024 21:42:17 -0600 Subject: [PATCH 116/198] add some debug code --- runtime/src/local_runqueue_binary_tree.c | 6 ++++++ runtime/src/software_interrupt.c | 7 +++++-- runtime/src/worker_thread.c | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/runtime/src/local_runqueue_binary_tree.c b/runtime/src/local_runqueue_binary_tree.c index 486ccd2d7..e40d4c3fe 100644 --- a/runtime/src/local_runqueue_binary_tree.c +++ b/runtime/src/local_runqueue_binary_tree.c @@ -17,6 +17,7 @@ extern thread_local uint8_t dispatcher_thread_idx; extern _Atomic uint32_t local_queue_length[1024]; extern uint32_t max_local_queue_length[1024]; +extern uint32_t max_local_queue_height[1024]; extern bool runtime_exponential_service_time_simulation_enabled; extern thread_local int global_worker_thread_idx; extern struct sandbox* current_sandboxes[1024]; @@ -76,6 +77,11 @@ local_runqueue_binary_tree_add_index(int index, struct sandbox *sandbox) lock_lock(&binary_tree->lock, &node_lock); binary_tree->root = insert(binary_tree, binary_tree->root, sandbox, index); lock_unlock(&binary_tree->lock, &node_lock); + + /*int height = findHeight(binary_tree->root); + if ( height > max_local_queue_height[index]) { + max_local_queue_height[index] = height; + }*/ atomic_fetch_add(&local_queue_length[index], 1); if (local_queue_length[index] > max_local_queue_length[index]) { diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index f00b14878..9106eb409 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -34,6 +34,7 @@ extern uint32_t worker_old_sandbox[1024]; extern uint32_t worker_new_sandbox[1024]; extern thread_local uint64_t total_requests; extern uint32_t max_local_queue_length[1024]; +extern uint32_t max_local_queue_height[1024]; extern thread_local uint32_t max_queue_length; extern thread_local uint32_t dispatcher_try_interrupts; thread_local uint32_t interrupts = 0; @@ -271,8 +272,10 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void atomic_load(&sandbox_state_totals[SANDBOX_ALLOCATED]), total_complete_requests, interrupts, preemptable_interrupts, max_local_queue_length[global_worker_thread_idx]); dump_log_to_file(); - printf("id %d max local queue %u new %u old %u current length %u real length %d total complete request %u\n", global_worker_thread_idx, max_local_queue_length[global_worker_thread_idx], - worker_new_sandbox[global_worker_thread_idx], worker_old_sandbox[global_worker_thread_idx], local_runqueue_count[global_worker_thread_idx], + printf("id %d max local queue %u new %u old %u current length %u real length %d total complete request %u\n", + global_worker_thread_idx, max_local_queue_length[global_worker_thread_idx], + worker_new_sandbox[global_worker_thread_idx], worker_old_sandbox[global_worker_thread_idx], + local_runqueue_count[global_worker_thread_idx], local_runqueue_get_length(), total_complete_requests); pthread_stop = true; /* Wake up worker so it can check if pthread_stop is true, othewise, it will block at condition wait */ diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c index b11b7a03f..dd356a48b 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c @@ -30,6 +30,7 @@ extern sem_t semlock[1024]; _Atomic uint32_t local_queue_length[1024] = {0}; uint32_t max_local_queue_length[1024] = {0}; +uint32_t max_local_queue_height[1024] = {0}; extern struct perf_window * worker_perf_windows[1024]; thread_local struct perf_window perf_window_per_thread[1024]; struct sandbox* current_sandboxes[1024] = { NULL }; From ba18177c76839313b169e7a4136ad8d0f825d510 Mon Sep 17 00:00:00 2001 From: xiaosuGW Date: Thu, 16 May 2024 00:25:55 -0600 Subject: [PATCH 117/198] update debug.sh --- runtime/tests/debug.sh | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/runtime/tests/debug.sh b/runtime/tests/debug.sh index 3e87c2bbd..f073be052 100755 --- a/runtime/tests/debug.sh +++ b/runtime/tests/debug.sh @@ -11,13 +11,15 @@ declare project_path="$( path=`pwd` echo $project_path cd $project_path/runtime/bin +export SLEDGE_DISABLE_BUSY_LOOP=true +export SLEDGE_DISABLE_AUTOSCALING=true export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=true export SLEDGE_DISABLE_PREEMPTION=true -export SLEDGE_SANDBOX_PERF_LOG=$path/srsf.log -export SLEDGE_NWORKERS=9 +export SLEDGE_SANDBOX_PERF_LOG=$path/server.log +export SLEDGE_NWORKERS=1 export SLEDGE_FIRST_WORKER_COREID=4 -export SLEDGE_NLISTENERS=3 -export SLEDGE_WORKER_GROUP_SIZE=3 +export SLEDGE_NLISTENERS=1 +export SLEDGE_WORKER_GROUP_SIZE=1 #export SLEDGE_DISPATCHER=DARC export SLEDGE_DISPATCHER=EDF_INTERRUPT #export SLEDGE_DISPATCHER=SHINJUKU From 084bc7497de24e1b62936dda8d990c6ed73c2ea9 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 16 May 2024 00:34:00 -0600 Subject: [PATCH 118/198] update increase_req_type.patch --- runtime/increase_req_type.patch | 53 +++++++++++++-------------------- 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/runtime/increase_req_type.patch b/runtime/increase_req_type.patch index 182b8ded0..ec3850efe 100644 --- a/runtime/increase_req_type.patch +++ b/runtime/increase_req_type.patch @@ -11,18 +11,9 @@ index 7442ea1..04de7fa 100644 void darc_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); void shinjuku_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); diff --git a/runtime/include/http_router.h b/runtime/include/http_router.h -index 39e1bb7..4da6948 100644 +index 39e1bb7..e6c877c 100644 --- a/runtime/include/http_router.h +++ b/runtime/include/http_router.h -@@ -54,7 +54,7 @@ http_router_add_route(http_router_t *router, struct route_config *config, struct - /* Register RPC request handler */ - if (dispatcher == DISPATCHER_EDF_INTERRUPT) { - if (erpc_register_req_func(config->request_type, edf_interrupt_req_handler, 0) != 0) { -- panic("register erpc function for EDF_INTERRUPT dispatcher failed\n"); -+ panic("register erpc function %u for EDF_INTERRUPT dispatcher failed\n", config->request_type); - } - } else if (dispatcher == DISPATCHER_DARC) { - if (erpc_register_req_func(config->request_type, darc_req_handler, 0) != 0) { @@ -91,7 +91,7 @@ http_router_match_route(http_router_t *router, char *route) } @@ -72,7 +63,7 @@ index 3fffc08..3127055 100644 struct module *module; /* HTTP State */ diff --git a/runtime/include/route_config.h b/runtime/include/route_config.h -index 337389f..1904f7c 100644 +index 337389f..fcc4c3a 100644 --- a/runtime/include/route_config.h +++ b/runtime/include/route_config.h @@ -23,7 +23,7 @@ enum route_config_member @@ -80,7 +71,7 @@ index 337389f..1904f7c 100644 struct route_config { char *route; - uint8_t request_type; -+ uint16_t request_type; ++ uint16_t request_type; uint32_t n_resas; char *path; uint8_t admissions_percentile; @@ -108,41 +99,36 @@ index 522f3db..4b68008 100644 &config->request_type); if (rc < 0) return -1; diff --git a/runtime/include/tenant_functions.h b/runtime/include/tenant_functions.h -index f4e02c1..84f69a2 100644 +index 396dddc..033e125 100644 --- a/runtime/include/tenant_functions.h +++ b/runtime/include/tenant_functions.h -@@ -21,7 +21,8 @@ extern thread_local uint32_t n_rtypes; +@@ -21,7 +21,7 @@ extern thread_local uint32_t n_rtypes; extern thread_local struct request_typed_queue *request_type_queue[MAX_REQUEST_TYPE]; extern thread_local struct request_typed_deque *request_type_deque[MAX_REQUEST_TYPE]; extern thread_local uint8_t dispatcher_thread_idx; -extern thread_local struct perf_window perf_window_per_thread[1024]; -+//extern thread_local struct perf_window perf_window_per_thread[MODULE_DATABASE_CAPACITY]; +extern thread_local struct perf_window *perf_window_per_thread; extern thread_local int global_worker_thread_idx; int tenant_database_add(struct tenant *tenant); diff --git a/runtime/src/admissions_info.c b/runtime/src/admissions_info.c -index 77c3417..a5901a0 100644 +index 77c3417..f9837df 100644 --- a/runtime/src/admissions_info.c +++ b/runtime/src/admissions_info.c -@@ -1,9 +1,11 @@ - #include "admissions_control.h" - #include "admissions_info.h" -+#include "module_database.h" +@@ -3,7 +3,7 @@ #include "debuglog.h" #include "perf_window.h" -extern thread_local struct perf_window perf_window_per_thread[1024]; -+//extern thread_local struct perf_window perf_window_per_thread[MODULE_DATABASE_CAPACITY]; +extern thread_local struct perf_window *perf_window_per_thread; /** * Initializes perf window * @param admissions_info diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c -index 35c1420..038c9be 100644 +index 70293b5..987473a 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c -@@ -471,7 +471,7 @@ on_client_socket_epoll_event(struct epoll_event *evt) +@@ -472,7 +472,7 @@ on_client_socket_epoll_event(struct epoll_event *evt) * @param msg the payload of the rpc request. It is the input parameter fot the function * @param size the size of the msg */ @@ -152,10 +138,10 @@ index 35c1420..038c9be 100644 if (first_request_comming == false){ t_start = time(NULL); diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c -index b11b7a0..03f78f5 100644 +index dd356a4..26ce73b 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c -@@ -24,15 +24,16 @@ +@@ -24,16 +24,16 @@ * Worker Thread State * **************************/ @@ -165,23 +151,24 @@ index b11b7a0..03f78f5 100644 - -_Atomic uint32_t local_queue_length[1024] = {0}; -uint32_t max_local_queue_length[1024] = {0}; +-uint32_t max_local_queue_height[1024] = {0}; -extern struct perf_window * worker_perf_windows[1024]; -thread_local struct perf_window perf_window_per_thread[1024]; -struct sandbox* current_sandboxes[1024] = { NULL }; -+extern pthread_mutex_t mutexs[1024]; // maximum index is number of threads -+extern pthread_cond_t conds[1024]; // maximum index is number of threads ++extern pthread_mutex_t mutexs[1024]; //maximum index is number of threads ++extern pthread_cond_t conds[1024]; //maximum index is number of threads +extern sem_t semlock[1024]; //maximum index is number of threads + -+_Atomic uint32_t local_queue_length[1024] = {0}; // maximum index is number of threads -+uint32_t max_local_queue_length[1024] = {0}; // maximum index is number of threads -+extern struct perf_window * worker_perf_windows[1024]; // maximum index is number of threads -+//thread_local struct perf_window perf_window_per_thread[MODULE_DATABASE_CAPACITY]; // maximum index is the number of modules ++_Atomic uint32_t local_queue_length[1024] = {0}; //maximum index is number of threads ++uint32_t max_local_queue_length[1024] = {0}; //maximum index is number of threads ++uint32_t max_local_queue_height[1024] = {0}; //maximum index is number of threads ++extern struct perf_window * worker_perf_windows[1024]; //maximum index is the number of modules +thread_local struct perf_window *perf_window_per_thread = NULL; // maximum index is the number of modules -+struct sandbox* current_sandboxes[1024] = { NULL }; // maximum index is number of threads ++struct sandbox* current_sandboxes[1024] = { NULL }; //maximum index is number of threads extern uint32_t runtime_worker_group_size; extern FILE *sandbox_perf_log; -@@ -100,7 +101,8 @@ worker_thread_main(void *argument) +@@ -101,7 +101,8 @@ worker_thread_main(void *argument) // runtime_set_pthread_prio(pthread_self(), 2); pthread_setschedprio(pthread_self(), -20); From 422c8f48fe20152d4aac50161df7da8d2ba0a5c6 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 17 May 2024 10:46:47 -0600 Subject: [PATCH 119/198] replace the memory pool in each module with a global shared reused memory pool, so different typs of requests can reuse the claimed sandboxs' memory --- runtime/include/lock.h | 2 +- runtime/include/module.h | 37 ++++------------------------ runtime/include/runtime.h | 51 +++++++++++++++++++++++++++++++++++++++ runtime/src/module.c | 5 ---- runtime/src/runtime.c | 7 ++++++ 5 files changed, 64 insertions(+), 38 deletions(-) diff --git a/runtime/include/lock.h b/runtime/include/lock.h index 1ff0242c0..7e454762d 100644 --- a/runtime/include/lock.h +++ b/runtime/include/lock.h @@ -4,8 +4,8 @@ #include #include +#include "types.h" #include "arch/getcycles.h" -#include "runtime.h" /* A linked list of nodes */ diff --git a/runtime/include/module.h b/runtime/include/module.h index 28b583015..544e2a080 100644 --- a/runtime/include/module.h +++ b/runtime/include/module.h @@ -9,7 +9,6 @@ #include "admissions_info.h" #include "current_wasm_module_instance.h" #include "panic.h" -#include "pool.h" #include "sledge_abi_symbols.h" #include "tcp_server.h" #include "types.h" @@ -17,17 +16,10 @@ #include "wasm_stack.h" #include "wasm_memory.h" #include "wasm_table.h" +#include "runtime.h" extern thread_local int global_worker_thread_idx; -INIT_POOL(wasm_memory, wasm_memory_free) -INIT_POOL(wasm_stack, wasm_stack_free) - -struct module_pool { - struct wasm_memory_pool memory; - struct wasm_stack_pool stack; -} CACHE_PAD_ALIGNED; - struct module { char *path; uint32_t stack_size; /* a specification? */ @@ -38,7 +30,6 @@ struct module { _Atomic uint32_t reference_count; /* ref count how many instances exist here. */ struct sledge_abi__wasm_table *indirect_table; - struct module_pool *pools; } CACHE_PAD_ALIGNED; /******************************** @@ -112,24 +103,6 @@ module_alloc_table(struct module *module) return 0; } -static inline void -module_initialize_pools(struct module *module) -{ - for (int i = 0; i < runtime_worker_threads_count; i++) { - wasm_memory_pool_init(&module->pools[i].memory, false); - wasm_stack_pool_init(&module->pools[i].stack, false); - } -} - -static inline void -module_deinitialize_pools(struct module *module) -{ - for (int i = 0; i < runtime_worker_threads_count; i++) { - wasm_memory_pool_deinit(&module->pools[i].memory); - wasm_stack_pool_deinit(&module->pools[i].stack); - } -} - /** * Invoke a module's initialize_memory * @param module - the module whose memory we are initializing @@ -168,7 +141,7 @@ module_allocate_stack(struct module *module) { assert(module != NULL); - struct wasm_stack *stack = wasm_stack_pool_remove_nolock(&module->pools[global_worker_thread_idx].stack); + struct wasm_stack *stack = runtime_stack_pool_remove(global_worker_thread_idx); if (stack == NULL) { stack = wasm_stack_alloc(module->stack_size); @@ -184,7 +157,7 @@ module_free_stack(struct module *module, struct wasm_stack *stack) uint64_t now = __getcycles(); wasm_stack_reinit(stack); uint64_t d = __getcycles() - now; - wasm_stack_pool_add_nolock(&module->pools[global_worker_thread_idx].stack, stack); + runtime_stack_pool_add(global_worker_thread_idx, stack); return d; } @@ -202,7 +175,7 @@ module_allocate_linear_memory(struct module *module) assert(starting_bytes <= (uint64_t)UINT32_MAX + 1); assert(max_bytes <= (uint64_t)UINT32_MAX + 1); - struct wasm_memory *linear_memory = wasm_memory_pool_remove_nolock(&module->pools[global_worker_thread_idx].memory); + struct wasm_memory *linear_memory = runtime_linear_memory_pool_remove(global_worker_thread_idx); if (linear_memory == NULL) { linear_memory = wasm_memory_alloc(starting_bytes, max_bytes); if (unlikely(linear_memory == NULL)) return NULL; @@ -215,7 +188,7 @@ static inline void module_free_linear_memory(struct module *module, struct wasm_memory *memory) { wasm_memory_reinit(memory, module->abi.starting_pages * WASM_PAGE_SIZE); - wasm_memory_pool_add_nolock(&module->pools[global_worker_thread_idx].memory, memory); + runtime_linear_memory_pool_add(global_worker_thread_idx, memory); } static inline void diff --git a/runtime/include/runtime.h b/runtime/include/runtime.h index 3d031166a..2fce5d64b 100644 --- a/runtime/include/runtime.h +++ b/runtime/include/runtime.h @@ -7,9 +7,23 @@ #include #include +#include "types.h" +#include "pool.h" +#include "wasm_stack.h" +#include "wasm_memory.h" #include "likely.h" #include "types.h" +INIT_POOL(wasm_memory, wasm_memory_free) +INIT_POOL(wasm_stack, wasm_stack_free) + +struct memory_pool { + struct wasm_memory_pool memory; + struct wasm_stack_pool stack; +} CACHE_PAD_ALIGNED; + + +extern struct memory_pool *memory_pools; /** * Optimizing compilers and modern CPUs reorder instructions however it sees fit. This means that the resulting * execution order may differ from the order of our source code. If there is a variable protecting a critical section, @@ -84,3 +98,40 @@ request_index_increment() return atomic_fetch_add(&request_index, 1); } +static inline void +runtime_initialize_pools() +{ + for (int i = 0; i < runtime_worker_threads_count; i++) { + wasm_memory_pool_init(&memory_pools[i].memory, false); + wasm_stack_pool_init(&memory_pools[i].stack, false); + } +} + +static inline void +runtime_deinitialize_pools() +{ + for (int i = 0; i < runtime_worker_threads_count; i++) { + wasm_memory_pool_deinit(&memory_pools[i].memory); + wasm_stack_pool_deinit(&memory_pools[i].stack); + } +} + +static inline struct wasm_stack * +runtime_stack_pool_remove(int thread_id) { + return wasm_stack_pool_remove_nolock(&memory_pools[thread_id].stack); +} + +static inline void +runtime_stack_pool_add(int thread_id, struct wasm_stack * stack) { + wasm_stack_pool_add_nolock(&memory_pools[thread_id].stack, stack); +} + +static inline struct wasm_memory * +runtime_linear_memory_pool_remove(int thread_id) { + return wasm_memory_pool_remove_nolock(&memory_pools[thread_id].memory); +} + +static inline void +runtime_linear_memory_pool_add(int thread_id, struct wasm_memory * memory) { + wasm_memory_pool_add_nolock(&memory_pools[thread_id].memory, memory); +} diff --git a/runtime/src/module.c b/runtime/src/module.c index 093106f65..602ba75a6 100644 --- a/runtime/src/module.c +++ b/runtime/src/module.c @@ -44,14 +44,11 @@ module_init(struct module *module, char *path) rc = sledge_abi_symbols_init(&module->abi, path); if (rc != 0) goto err; - module->pools = calloc(runtime_worker_threads_count, sizeof(struct module_pool)); - module->path = path; module->stack_size = ((uint32_t)(round_up_to_page(stack_size == 0 ? WASM_STACK_SIZE : stack_size))); module_alloc_table(module); - module_initialize_pools(module); done: return rc; err: @@ -68,8 +65,6 @@ module_deinit(struct module *module) free(module->path); sledge_abi_symbols_deinit(&module->abi); /* TODO: Free indirect_table */ - module_deinitialize_pools(module); - free(module->pools); } /*************************************** diff --git a/runtime/src/runtime.c b/runtime/src/runtime.c index 429c52474..27ee25ab2 100644 --- a/runtime/src/runtime.c +++ b/runtime/src/runtime.c @@ -40,6 +40,8 @@ int *runtime_listener_threads_argument; uint64_t *runtime_worker_threads_deadline; uint64_t wakeup_thread_cycles; +struct memory_pool *memory_pools = NULL; + /****************************************** * Shared Process / Listener Thread Logic * *****************************************/ @@ -62,6 +64,8 @@ runtime_cleanup() } software_interrupt_cleanup(); + runtime_deinitialize_pools(); + free(memory_pools); exit(EXIT_SUCCESS); } @@ -129,6 +133,9 @@ runtime_initialize(void) sandbox_state_totals_initialize(); worker_queuing_cost_initialize(); + memory_pools = calloc(runtime_worker_threads_count, sizeof(struct memory_pool)); + runtime_initialize_pools(); + /* Setup Scheduler */ scheduler_initialize(); From 912454116fbdaffbc2af17fe660f5ea87604cd95 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Sat, 18 May 2024 23:06:09 -0600 Subject: [PATCH 120/198] update tests/start_func_density_test.sh --- runtime/tests/start_func_density_test.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runtime/tests/start_func_density_test.sh b/runtime/tests/start_func_density_test.sh index a97b942dd..66ea5d56c 100755 --- a/runtime/tests/start_func_density_test.sh +++ b/runtime/tests/start_func_density_test.sh @@ -14,6 +14,7 @@ fi worker_num=$1 listener_num=$2 first_worker_core_id=$3 +worker_group_size=$((worker_num / listener_num)) declare project_path="$( cd "$(dirname "$0")/../.." @@ -29,7 +30,7 @@ export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=true export SLEDGE_FIRST_WORKER_COREID=$first_worker_core_id export SLEDGE_NWORKERS=$worker_num export SLEDGE_NLISTENERS=$listener_num -export SLEDGE_WORKER_GROUP_SIZE=1 +export SLEDGE_WORKER_GROUP_SIZE=$worker_group_size export SLEDGE_SCHEDULER=EDF #export SLEDGE_DISPATCHER=DARC #export SLEDGE_DISPATCHER=SHINJUKU From 9b5625d5c8256a7cb48d07f95075fd6e375ef046 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Mon, 20 May 2024 15:43:23 -0600 Subject: [PATCH 121/198] update start_func_density_test.sh and upload generate_json_with_replica_field.py --- .../tests/generate_json_with_replica_field.py | 42 +++++++++++++++++++ runtime/tests/start_func_density_test.sh | 14 +++++-- 2 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 runtime/tests/generate_json_with_replica_field.py diff --git a/runtime/tests/generate_json_with_replica_field.py b/runtime/tests/generate_json_with_replica_field.py new file mode 100644 index 000000000..b2c68fa7b --- /dev/null +++ b/runtime/tests/generate_json_with_replica_field.py @@ -0,0 +1,42 @@ +import json +import argparse + +def generate_json(route_replicas): + data = [ + { + "name": "gwu", + "port": 31850, + "replenishment-period-us": 0, + "max-budget-us": 0, + "route-replicas": route_replicas, + "routes": [ + { + "route": "/fib", + "request-type": 1, + "n-resas": 1, + "path": "fibonacci.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 5, + "relative-deadline-us": 50, + "http-resp-content-type": "text/plain" + } + ] + } + ] + return data + +def main(): + parser = argparse.ArgumentParser(description='Generate JSON file.') + parser.add_argument('route_replicas', type=int, help='Value for route-replicas') + parser.add_argument('output_file', type=str, help='Output JSON file') + + args = parser.parse_args() + + json_data = generate_json(args.route_replicas) + + with open(args.output_file, 'w') as f: + json.dump(json_data, f, indent=4) + +if __name__ == "__main__": + main() + diff --git a/runtime/tests/start_func_density_test.sh b/runtime/tests/start_func_density_test.sh index 66ea5d56c..dab7ea141 100755 --- a/runtime/tests/start_func_density_test.sh +++ b/runtime/tests/start_func_density_test.sh @@ -1,12 +1,16 @@ #!/bin/bash + ulimit -n 655350 +ulimit -s unlimited +ulimit -m unlimited +sudo sysctl -w vm.max_map_count=262144 function usage { - echo "$0 [worker num] [listener num] [first worker core id]" + echo "$0 [worker num] [listener num] [first worker core id] [json file] [server log]" exit 1 } -if [ $# != 3 ] ; then +if [ $# != 5 ] ; then usage exit 1; fi @@ -14,6 +18,8 @@ fi worker_num=$1 listener_num=$2 first_worker_core_id=$3 +json_file=$4 +server_log=$5 worker_group_size=$((worker_num / listener_num)) declare project_path="$( @@ -35,7 +41,7 @@ export SLEDGE_SCHEDULER=EDF #export SLEDGE_DISPATCHER=DARC #export SLEDGE_DISPATCHER=SHINJUKU export SLEDGE_DISPATCHER=EDF_INTERRUPT -export SLEDGE_SANDBOX_PERF_LOG=$path/server.log +export SLEDGE_SANDBOX_PERF_LOG=$path/$server_log #echo $SLEDGE_SANDBOX_PERF_LOG cd $project_path/runtime/bin #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_fibonacci.json @@ -47,7 +53,7 @@ cd $project_path/runtime/bin #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing3.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/fib.json -LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/config.json +LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/$json_file #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/hash.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/empty.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/my_fibonacci.json From 71cb67f477f31237b10418539e2a6097abe0a078 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Mon, 20 May 2024 15:50:41 -0600 Subject: [PATCH 122/198] update increase_req_type.patch --- runtime/increase_req_type.patch | 246 +++++++++++++++++++++++++++++++- 1 file changed, 243 insertions(+), 3 deletions(-) diff --git a/runtime/increase_req_type.patch b/runtime/increase_req_type.patch index ec3850efe..0f2db52ea 100644 --- a/runtime/increase_req_type.patch +++ b/runtime/increase_req_type.patch @@ -37,7 +37,7 @@ index c99aa2a..4c5b3c4 100644 /** * Parses a JSON file into an array of tenant configs diff --git a/runtime/include/module_database.h b/runtime/include/module_database.h -index 24d1b46..7cbc088 100644 +index 24d1b46..32902dc 100644 --- a/runtime/include/module_database.h +++ b/runtime/include/module_database.h @@ -2,7 +2,7 @@ @@ -45,7 +45,7 @@ index 24d1b46..7cbc088 100644 #include "module.h" -#define MODULE_DATABASE_CAPACITY 1024 -+#define MODULE_DATABASE_CAPACITY 2048 ++#define MODULE_DATABASE_CAPACITY 20000 struct module_database { struct module *modules[MODULE_DATABASE_CAPACITY]; @@ -98,8 +98,86 @@ index 522f3db..4b68008 100644 route_config_json_keys[route_config_member_request_type], &config->request_type); if (rc < 0) return -1; +diff --git a/runtime/include/tenant.h b/runtime/include/tenant.h +index 113fdca..e33aacc 100644 +--- a/runtime/include/tenant.h ++++ b/runtime/include/tenant.h +@@ -38,6 +38,7 @@ struct tenant { + uint16_t port; + struct route_config *routes_config; + size_t routes_len; ++ size_t route_replicas; + struct tcp_server tcp_server; + http_router_t router; + struct module_database module_db; +diff --git a/runtime/include/tenant_config.h b/runtime/include/tenant_config.h +index d907718..8bedede 100644 +--- a/runtime/include/tenant_config.h ++++ b/runtime/include/tenant_config.h +@@ -14,6 +14,7 @@ enum tenant_config_member + tenant_config_member_port, + tenant_config_member_replenishment_period_us, + tenant_config_member_max_budget_us, ++ tenant_config_member_route_replicas, + tenant_config_member_routes, + tenant_config_member_len + }; +@@ -23,6 +24,7 @@ struct tenant_config { + uint16_t port; + uint32_t replenishment_period_us; + uint32_t max_budget_us; ++ uint32_t route_replicas; + struct route_config *routes; + size_t routes_len; + }; +@@ -37,6 +39,7 @@ tenant_config_deinit(struct tenant_config *config) + for (int i = 0; i < config->routes_len; i++) { route_config_deinit(&config->routes[i]); } + free(config->routes); + config->routes = NULL; ++ config->route_replicas = 0; + config->routes_len = 0; + } + +@@ -47,6 +50,7 @@ tenant_config_print(struct tenant_config *config) + printf("[Tenant] Path: %d\n", config->port); + printf("[Tenant] Replenishment Period (us): %u\n", config->replenishment_period_us); + printf("[Tenant] Max Budget (us): %u\n", config->max_budget_us); ++ printf("[Tenant] Route replicas (us): %u\n", config->route_replicas); + printf("[Tenant] Routes Size: %zu\n", config->routes_len); + for (int i = 0; i < config->routes_len; i++) { route_config_print(&config->routes[i]); } + } +diff --git a/runtime/include/tenant_config_parse.h b/runtime/include/tenant_config_parse.h +index 14b7aef..6515015 100644 +--- a/runtime/include/tenant_config_parse.h ++++ b/runtime/include/tenant_config_parse.h +@@ -10,7 +10,7 @@ + #include "tenant_config.h" + + static const char *tenant_config_json_keys[tenant_config_member_len] = { "name", "port", "replenishment-period-us", +- "max-budget-us", "routes" }; ++ "max-budget-us", "route-replicas", "routes" }; + + static inline int + tenant_config_set_key_once(bool *did_set, enum tenant_config_member member) +@@ -79,7 +79,15 @@ tenant_config_parse(struct tenant_config *config, const char *json_buf, jsmntok_ + tenant_config_json_keys[tenant_config_member_max_budget_us], + &config->max_budget_us); + if (rc < 0) return -1; +- } else if (strcmp(key, tenant_config_json_keys[tenant_config_member_routes]) == 0) { ++ } else if (strcmp(key, tenant_config_json_keys[tenant_config_member_route_replicas]) == 0) { ++ if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1; ++ if (tenant_config_set_key_once(did_set, tenant_config_member_route_replicas) == -1) return -1; ++ ++ int rc = parse_uint32_t(tokens[i], json_buf, ++ tenant_config_json_keys[tenant_config_member_route_replicas], ++ &config->route_replicas); ++ if (rc < 0) return -1; ++ } else if (strcmp(key, tenant_config_json_keys[tenant_config_member_routes]) == 0) { + if (!has_valid_type(tokens[i], key, JSMN_ARRAY, json_buf)) return -1; + if (tenant_config_set_key_once(did_set, tenant_config_member_routes) == -1) return -1; + diff --git a/runtime/include/tenant_functions.h b/runtime/include/tenant_functions.h -index 396dddc..033e125 100644 +index 396dddc..919fd8c 100644 --- a/runtime/include/tenant_functions.h +++ b/runtime/include/tenant_functions.h @@ -21,7 +21,7 @@ extern thread_local uint32_t n_rtypes; @@ -111,6 +189,168 @@ index 396dddc..033e125 100644 extern thread_local int global_worker_thread_idx; int tenant_database_add(struct tenant *tenant); +@@ -84,6 +84,105 @@ tenant_policy_specific_init(struct tenant *tenant, struct tenant_config *config) + return 0; + } + ++static inline char* ++generate_new_path(const char* full_name, int number, const char* fixed_part) { ++ const char* suffix_position = strstr(full_name, fixed_part); ++ if (!suffix_position) { ++ panic("Wrong path name"); ++ } ++ ++ size_t name_length = suffix_position - full_name; ++ ++ char number_str[6]; ++ snprintf(number_str, sizeof(number_str), "%d", number); ++ size_t number_length = strlen(number_str); ++ ++ size_t new_length = name_length + number_length + strlen(fixed_part) + 1; ++ char* new_name = (char*)malloc(new_length); ++ if (!new_name) { ++ panic("Failed to allocate memory for path"); ++ } ++ ++ strncpy(new_name, full_name, name_length); ++ new_name[name_length] = '\0'; ++ ++ strcat(new_name, number_str); ++ strcat(new_name, fixed_part); ++ ++ return new_name; ++} ++ ++static inline struct route_config * ++duplicate_route(int index, struct route_config *src_route) { ++ struct route_config *dup_route = (struct route_config *)malloc(sizeof(struct route_config)); ++ ++ // Allocate memory for route with additional space for index ++ size_t route_len = strlen(src_route->route) + 6; // 20 is enough to hold the index as string ++ dup_route->route = (char *)malloc(route_len); ++ strcpy(dup_route->route, src_route->route); ++ sprintf(dup_route->route + strlen(dup_route->route), "%d", index); ++ ++ // Allocate memory for path with additional space for index ++ dup_route->path = generate_new_path(src_route->path, index, ".wasm.so"); ++ ++ // Copy other fields ++ dup_route->request_type = index; ++ dup_route->n_resas = src_route->n_resas; ++ dup_route->admissions_percentile = src_route->admissions_percentile; ++ dup_route->expected_execution_us = src_route->expected_execution_us; ++ dup_route->expected_execution_cycle = src_route->expected_execution_cycle; ++ dup_route->relative_deadline_us = src_route->relative_deadline_us; ++ ++ if (src_route->http_resp_content_type != NULL) { ++ dup_route->http_resp_content_type = strdup(src_route->http_resp_content_type); ++ } else { ++ dup_route->http_resp_content_type = NULL; ++ } ++ ++ return dup_route; ++} ++ ++static inline void ++create_replica_routes(struct tenant *tenant, struct tenant_config *config) ++{ ++ for (int i = 0; i < config->routes_len; i++) { ++ struct module *module = module_database_find_by_path(&tenant->module_db, config->routes[i].path); ++ if (module == NULL) { ++ for (int j = 1; j <= config->route_replicas; j++) { ++ struct route_config *route_cfg = duplicate_route(j, &config->routes[i]); ++ //printf("name %s type %d route %s path %s\n", config->name, route_cfg->request_type, route_cfg->route, route_cfg->path); ++ assert(module_database_find_by_path(&tenant->module_db, route_cfg->path) == NULL); ++ ++ /* Ownership of path moves here */ ++ struct module * new_module = module_alloc(route_cfg->path); ++ ++ if (new_module != NULL) { ++ module_database_add(&tenant->module_db, new_module); ++ route_cfg->path = NULL; ++ } ++ /* Ownership of config's route and http_resp_content_type move here */ ++ int rc = http_router_add_route(&tenant->router, route_cfg, new_module); ++ if (unlikely(rc != 0)) { ++ panic("Tenant %s defined %lu routes, but router failed to grow beyond %lu\n", tenant->name, ++ config->routes_len, tenant->router.capacity); ++ } ++ ++ route_cfg->route = NULL; ++ route_cfg->http_resp_content_type = NULL; ++ } ++ } else { ++ panic("No allowed duplicate route path when route_replicas is larger then 1\n"); ++ } ++ ++ free(config->routes[i].path); ++ config->routes[i].path = NULL; ++ free(config->routes[i].http_resp_content_type); ++ config->routes[i].http_resp_content_type = NULL; ++ free(config->routes[i].route); ++ config->routes[i].route = NULL; ++ } ++} ++ + static inline struct tenant * + tenant_alloc(struct tenant_config *config) + { +@@ -94,26 +193,36 @@ tenant_alloc(struct tenant_config *config) + struct tenant *tenant = (struct tenant *)calloc(1, sizeof(struct tenant)); + + /* Move name */ +- tenant->tag = EPOLL_TAG_TENANT_SERVER_SOCKET; +- tenant->name = config->name; +- tenant->port = config->port; +- tenant->routes_config = config->routes; +- tenant->routes_len = config->routes_len; +- config->name = NULL; ++ tenant->tag = EPOLL_TAG_TENANT_SERVER_SOCKET; ++ tenant->name = config->name; ++ tenant->port = config->port; ++ tenant->routes_config = config->routes; ++ tenant->routes_len = config->routes_len; ++ tenant->route_replicas = config->route_replicas; ++ config->name = NULL; + + tcp_server_init(&tenant->tcp_server, config->port); +- http_router_init(&tenant->router, config->routes_len); ++ if (config->route_replicas > 1) { ++ http_router_init(&tenant->router, config->route_replicas); ++ } else { ++ http_router_init(&tenant->router, config->routes_len); ++ } ++ + module_database_init(&tenant->module_db); + map_init(&tenant->scratch_storage); + + /* Deferrable Server init */ + tenant_policy_specific_init(tenant, config); + +- for (int i = 0; i < config->routes_len; i++) { ++ if (config->route_replicas > 1) { ++ create_replica_routes(tenant, config); ++ } else { ++ for (int i = 0; i < config->routes_len; i++) { + struct module *module = module_database_find_by_path(&tenant->module_db, config->routes[i].path); + if (module == NULL) { + /* Ownership of path moves here */ + module = module_alloc(config->routes[i].path); ++ //printf("name %s type %d route %s path %s\n", config->name, config->routes[i].request_type, config->routes[i].route, config->routes[i].path); + if (module != NULL) { + module_database_add(&tenant->module_db, module); + config->routes[i].path = NULL; +@@ -134,8 +243,9 @@ tenant_alloc(struct tenant_config *config) + + config->routes[i].route = NULL; + config->routes[i].http_resp_content_type = NULL; +- } ++ } + ++ } + return tenant; + } + diff --git a/runtime/src/admissions_info.c b/runtime/src/admissions_info.c index 77c3417..f9837df 100644 --- a/runtime/src/admissions_info.c From 1ebc7d86e3f9ee8a8e0c3349adfeabac3331d304 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 22 May 2024 12:49:13 -0600 Subject: [PATCH 123/198] upload binary_search_tree.h_redblacktree local_runqueue_binary_tree.c_redblacktree --- .../include/binary_search_tree.h_redblacktree | 656 ++++++++++++++++++ .../local_runqueue_binary_tree.c_redblacktree | 250 +++++++ 2 files changed, 906 insertions(+) create mode 100644 runtime/include/binary_search_tree.h_redblacktree create mode 100644 runtime/src/local_runqueue_binary_tree.c_redblacktree diff --git a/runtime/include/binary_search_tree.h_redblacktree b/runtime/include/binary_search_tree.h_redblacktree new file mode 100644 index 000000000..c0cd86df5 --- /dev/null +++ b/runtime/include/binary_search_tree.h_redblacktree @@ -0,0 +1,656 @@ +#include +#include +#include + +#include "memlogging.h" +#include "lock.h" + +#define MAX_NODES 4096 // Maximum number of nodes in the pool + +typedef uint64_t (*binary_tree_get_priority_fn_t)(void *data); +typedef uint64_t (*binary_tree_get_execution_cost_fn_t)(void *data, int thread_id); + +// Define the colors for Red-Black Tree +typedef enum { RED, BLACK } Color; + +// Definition of a binary search tree node +struct TreeNode { + struct TreeNode *left; + struct TreeNode *right; + struct TreeNode *next; // pointing to the next node, this is used for nodePool + // to find next available node + struct TreeNode *dup_next; // pointing to next duplicate key item + struct TreeNode *parent; + Color color; + uint64_t left_subtree_sum; + void *data; // sandbox +}; + +// Definition of TreeNode memory pool +struct TreeNodePool { + struct TreeNode* head; +}; + +struct binary_tree { + struct TreeNode *root; + struct TreeNodePool nodePool; + binary_tree_get_priority_fn_t get_priority_fn; + binary_tree_get_execution_cost_fn_t get_execution_cost_fn; + lock_t lock; + bool use_lock; + int id; + int queue_length; +}; + +// Initialize the node pool +void initNodePool(struct TreeNodePool *nodePool, int pool_size) { + + assert(nodePool != NULL); + + struct TreeNode *nodes = (struct TreeNode*)malloc(pool_size * sizeof(struct TreeNode)); + nodePool->head = nodes; // Initialize head to the beginning of the node array + + for (int i = 0; i < MAX_NODES - 1; ++i) { + nodes[i].next = &nodes[i + 1]; // Set the next pointer of each node to the next node + nodes[i].left = NULL; + nodes[i].right = NULL; + nodes[i].dup_next = NULL; + nodes[i].parent = NULL; + nodes[i].color = RED; + nodes[i].left_subtree_sum = 0; + nodes[i].data = NULL; + } + nodes[MAX_NODES - 1].next = NULL; +} + +struct binary_tree * init_binary_tree(bool use_lock, binary_tree_get_priority_fn_t get_priority_fn, + binary_tree_get_execution_cost_fn_t get_execution_cost_fn, int id, int queue_size) { + + assert(get_priority_fn != NULL); + + struct binary_tree *binary_tree = (struct binary_tree *)calloc(1, sizeof(struct binary_tree)); + initNodePool(&binary_tree->nodePool, queue_size); + binary_tree->root = NULL; + binary_tree->get_priority_fn = get_priority_fn; + binary_tree->get_execution_cost_fn = get_execution_cost_fn; + binary_tree->use_lock = use_lock; + binary_tree->id = id; + binary_tree->queue_length = 0; + + if (binary_tree->use_lock) lock_init(&binary_tree->lock); + + return binary_tree; +} + +// Function to get the total number of non-deleted nodes in the binary tree +int getNonDeletedNodeCount(struct binary_tree *binary_tree) { + assert(binary_tree != NULL); + return binary_tree->queue_length; +} + +// Get a new node from the pool +struct TreeNode* newNode(struct binary_tree *binary_tree, Color color, struct TreeNode* left, + struct TreeNode* right, struct TreeNode* parent, void *data) { + + assert(binary_tree != NULL); + + if (binary_tree->nodePool.head == NULL) { + panic("Binary search tree queue %d is full\n", binary_tree->id); + return NULL; + } else { + // Remove a node from the head of the memory pool + struct TreeNode* new_node_t = binary_tree->nodePool.head; + binary_tree->nodePool.head = new_node_t->next; + new_node_t->next = NULL; // Reset the next pointer of the new node + new_node_t->data = data; + new_node_t->left = left; + new_node_t->right = right; + new_node_t->parent = parent; + new_node_t->color = color; + new_node_t->dup_next = NULL; + new_node_t->left_subtree_sum = 0; + return new_node_t; + } +} + +void getAvailableCapacity(struct binary_tree *binary_tree) { + + assert(binary_tree != NULL); + + int size = 0; + struct TreeNode* start = binary_tree->nodePool.head; + while(start) { + size++; + start = start->next; + } + + printf("available capacity of the queue is %d\n", size); +} + +void print_in_order(struct TreeNode* node) { + if (node != NULL) { + // Recursively traverse the left subtree + print_in_order(node->left); + + // Print the data in the current node + if (node->data) { + mem_log("%lu(%lu) ", ((struct sandbox *)node->data)->absolute_deadline, ((struct sandbox *)node->data)->estimated_cost); + } + //Print data in the dup_next list + struct TreeNode* cur = node->dup_next; + while(cur) { + mem_log("%lu(%lu) ", ((struct sandbox *)cur->data)->absolute_deadline, ((struct sandbox *)cur->data)->estimated_cost); + cur = cur->dup_next; + } + + // Recursively traverse the right subtree + print_in_order(node->right); + } +} + +// Function to print the items in the binary search tree in order +void print_tree_in_order(struct binary_tree* bst) { + if (bst != NULL) { + print_in_order(bst->root); + mem_log("\n"); + } +} + +//get the total execute time of a node. +uint64_t get_sum_exe_time_of_node(struct binary_tree *binary_tree, struct TreeNode* node, int thread_id){ + uint64_t total = 0; + struct TreeNode* curNode = node; + while (curNode!=NULL) { + total += binary_tree->get_execution_cost_fn(curNode->data, thread_id); + curNode = curNode->dup_next; + } + + return total; +} + +//get the total execute time of a node's subtree, including left and right subtree +uint64_t get_sum_exe_time_of_subtree(struct binary_tree *binary_tree, struct TreeNode* root, int thread_id) { + if (root == NULL) { + return 0; + } + + return get_sum_exe_time_of_node(binary_tree, root, thread_id) + + root->left_subtree_sum + get_sum_exe_time_of_subtree(binary_tree, root->right, thread_id); +} + + +// Return a node to the pool +void deleteNode(struct binary_tree *binary_tree, struct TreeNode* node) { + + assert(binary_tree != NULL); + assert(node != NULL); + + // Insert the node back to the head of the memory pool + node->left = NULL; + node->right = NULL; + node->parent = NULL; + node->color = RED; + node->data = NULL; + node->left_subtree_sum = 0; + node->dup_next = NULL; + node->next = binary_tree->nodePool.head; + binary_tree->nodePool.head = node; +} + +int findHeight(struct TreeNode *root) +{ + int lefth, righth; + if(root == NULL) + return 0; + lefth = findHeight(root->left); + righth = findHeight(root->right); + return (lefth > righth ? lefth : righth)+1; +} + +// Update root if rotating. +void leftRotate(struct binary_tree *binary_tree, struct TreeNode *x, int thread_id) { + struct TreeNode *y = x->right; + x->right = y->left; + if (y->left != NULL) + y->left->parent = x; + + y->parent = x->parent; + + if (x->parent == NULL) + binary_tree->root = y; + else if (x == x->parent->left) + x->parent->left = y; + else + x->parent->right = y; + y->left = x; + x->parent = y; + y->left_subtree_sum += binary_tree->get_execution_cost_fn(x->data, thread_id) + x->left_subtree_sum; +} + +// Update root if rotatiing +void rightRotate(struct binary_tree *binary_tree, struct TreeNode *x, int thread_id) { + struct TreeNode *y = x->left; + x->left = y->right; + + int new_sum_left = 0; + if (y->right != NULL) { + y->right->parent = x; + new_sum_left = get_sum_exe_time_of_subtree(binary_tree, y->right, thread_id); //y->right->exe_time + y->right->sum_left; + } + + x->left_subtree_sum = new_sum_left; + y->parent = x->parent; + if (x->parent == NULL) + binary_tree->root = y; + else if (x == x->parent->right) + x->parent->right = y; + else + x->parent->left = y; + y->right = x; + x->parent = y; +} + +void insertFixup(struct binary_tree *binary_tree, struct TreeNode *z, int thread_id) { + while (z->parent != NULL && z->parent->color == RED) { + if (z->parent == z->parent->parent->left) { + struct TreeNode *y = z->parent->parent->right; + if (y != NULL && y->color == RED) { + z->parent->color = BLACK; + y->color = BLACK; + z->parent->parent->color = RED; + z = z->parent->parent; + } else { + if (z == z->parent->right) { + z = z->parent; + leftRotate(binary_tree, z, thread_id); + } + z->parent->color = BLACK; + z->parent->parent->color = RED; + rightRotate(binary_tree, z->parent->parent, thread_id); + } + } else { + struct TreeNode *y = z->parent->parent->left; + if (y != NULL && y->color == RED) { + z->parent->color = BLACK; + y->color = BLACK; + z->parent->parent->color = RED; + z = z->parent->parent; + } else { + if (z == z->parent->left) { + z = z->parent; + rightRotate(binary_tree, z, thread_id); + } + z->parent->color = BLACK; + z->parent->parent->color = RED; + leftRotate(binary_tree, z->parent->parent, thread_id); + } + } + } + binary_tree->root->color = BLACK; +} + +// Function to insert a value into a binary search tree. Tree root might be changed after inserting a new node +void insert(struct binary_tree *binary_tree, void *data, int thread_id) { + assert(binary_tree != NULL); + + struct TreeNode *z = newNode(binary_tree, RED, NULL, NULL, NULL, data); + binary_tree->queue_length++; + struct TreeNode *y = NULL; + struct TreeNode *x = binary_tree->root; + while (x != NULL) { + y = x; + + //if found a dup_next deadline, inserted the node + //at the end of the linklist + if (binary_tree->get_priority_fn(z->data) == binary_tree->get_priority_fn(x->data)) { + //find the tail the link list; + struct TreeNode* tail = x; + while (tail->dup_next != NULL) { + tail = tail->dup_next; + } + //append the new node at the end of the list; + tail->dup_next = z; + z->color = x->color; + z->left_subtree_sum = x->left_subtree_sum; + return; + } else if (binary_tree->get_priority_fn(z->data) < binary_tree->get_priority_fn(x->data)) { + x->left_subtree_sum += binary_tree->get_execution_cost_fn(data, thread_id); + x = x->left; + } else { + x = x->right; + } + } + + z->parent = y; + if (y == NULL) { + binary_tree->root = z; + } else if (binary_tree->get_priority_fn(z->data) < binary_tree->get_priority_fn(y->data)) { + y->left = z; + } else { + y->right = z; + } + + insertFixup(binary_tree, z, thread_id); +} + +// Helper function to find the minimum value in a binary search tree +struct TreeNode* findMin(struct binary_tree *binary_tree) { + + assert(binary_tree != NULL); + + struct TreeNode *curNode = binary_tree->root; + if (curNode == NULL) { + return NULL; + } + + while (curNode->left != NULL) { + curNode = curNode->left; // Keep traversing to the left until the leftmost node is reached + } + return curNode; +} + +// Helper function to find the maximum value in a binary search tree +struct TreeNode* findMax(struct binary_tree *binary_tree) { + + assert(binary_tree != NULL); + + struct TreeNode *curNode = binary_tree->root; + if (curNode == NULL) { + return NULL; + } + + while (curNode->right != NULL) { + curNode = curNode->right; // Keep traversing to the right until the rightmost node is reached + } + return curNode; +} + +struct TreeNode* searchByKey(struct binary_tree *binary_tree, void *data) { + struct TreeNode* current = binary_tree->root; + + while (current != NULL && binary_tree->get_priority_fn(current->data) != binary_tree->get_priority_fn(data)) { + if (binary_tree->get_priority_fn(data) < binary_tree->get_priority_fn(current->data)) { + current = current->left; + } else { + current = current->right; + } + } + + return current; +} + +void transplant(struct binary_tree *binary_tree, struct TreeNode *u, struct TreeNode *v) { + if (u->parent == NULL) + binary_tree->root = v; + else if (u == u->parent->left) + u->parent->left = v; + else + u->parent->right = v; + if (v != NULL) + v->parent = u->parent; +} + +struct TreeNode* minimum(struct TreeNode *node) { + while (node->left != NULL) { + node = node->left; + } + return node; +} + +void deleteFixup(struct binary_tree *binary_tree, struct TreeNode *x, int thread_id) { + while (x != binary_tree->root && (x == NULL || x->color == BLACK)) { + + if (x == NULL){ + break; + } + + if ( x == x->parent->left) { + struct TreeNode *w = x->parent->right; + if (w->color == RED) { + w->color = BLACK; + x->parent->color = RED; + leftRotate(binary_tree, x->parent, thread_id); + w = x->parent->right; + } + if ((w->left == NULL || w->left->color == BLACK) && (w->right == NULL || w->right->color == BLACK)) { + w->color = RED; + x = x->parent; + } else { + if (w->right == NULL || w->right->color == BLACK) { + if (w->left != NULL) w->left->color = BLACK; + w->color = RED; + rightRotate(binary_tree, w, thread_id); + w = x->parent->right; + } + w->color = x->parent->color; + x->parent->color = BLACK; + if (w->right != NULL) w->right->color = BLACK; + leftRotate(binary_tree, x->parent, thread_id); + x = binary_tree->root; + } + } else { + struct TreeNode *w = x->parent->left; + if (w->color == RED) { + w->color = BLACK; + x->parent->color = RED; + rightRotate(binary_tree, x->parent, thread_id); + w = x->parent->left; + } + if ((w->right == NULL || w->right->color == BLACK) && (w->left == NULL || w->left->color == BLACK)) { + w->color = RED; + x = x->parent; + } else { + if (w->left == NULL || w->left->color == BLACK) { + if (w->right != NULL) w->right->color = BLACK; + w->color = RED; + leftRotate(binary_tree, w, thread_id); + w = x->parent->left; + } + w->color = x->parent->color; + x->parent->color = BLACK; + if (w->left != NULL) w->left->color = BLACK; + rightRotate(binary_tree, x->parent, thread_id); + x = binary_tree->root; + } + } + } + if (x != NULL) x->color = BLACK; +} + +void removeNode(struct binary_tree *binary_tree, struct TreeNode *z, int thread_id) { + struct TreeNode *y = z; + struct TreeNode *x = NULL; + Color y_original_color = y->color; + + if ( z->left != NULL && z->right != NULL ) { + y = minimum(z->right); + + int diff = get_sum_exe_time_of_node(binary_tree, y, thread_id) - get_sum_exe_time_of_node(binary_tree, z, thread_id); + struct TreeNode* cur = z->right; + while (cur != y) { + cur->left_subtree_sum -= diff; + cur = cur->left; + } + + void *remove_data = z->data; + z->data = y->data; + z->dup_next = y->dup_next; + y->data = remove_data; + y->dup_next = NULL; + + removeNode(binary_tree, y, thread_id); + return; + } + + //now the node to be removed has only no children + //or only one child, update the sum_left value of + //all the node along the path from root to z. + struct TreeNode* current = z; + struct TreeNode* p = current->parent; + while (p != NULL) { + if (p->left == current) + { + p->left_subtree_sum -= binary_tree->get_execution_cost_fn(z->data, thread_id); + } + current = p; + p = current->parent; + } + + if (z->left == NULL) { + x = z->right; + transplant(binary_tree, z, z->right); + + } else if (z->right == NULL) { + x = z->left; + transplant(binary_tree, z, z->left); + + } + + deleteNode(binary_tree, z); + if (y_original_color == BLACK) { + deleteFixup(binary_tree, x, thread_id); + } +} + +// Function to delete a value from a binary search tree +void delete_i(struct binary_tree *binary_tree, void *data, bool *deleted, int thread_id) { + + assert(binary_tree != NULL); + *deleted = false; + + struct TreeNode *z = searchByKey(binary_tree, data); + if (z != NULL) { + //if there are duplicated nodes in Z, + //we just need to remove duplicated one. + if (z->dup_next != NULL) { + struct TreeNode* cur = z; + struct TreeNode* prev = NULL; + while (cur && cur->data != data) { + prev = cur; + cur = cur->dup_next; + } + + //if the target node has been found + if (cur != NULL) { + //update the sumLeft in all of its parent node. + struct TreeNode* current = z; + struct TreeNode* p = current->parent; + while (p != NULL) { + if (p->left == current) + { + p->left_subtree_sum -= binary_tree->get_execution_cost_fn(data, thread_id); + } + current = p; + p = current->parent; + } + } else { + *deleted = false; + printf("1 not found the node when deleting\n"); + return; + } + + //if the removed node is the head of the linkedlist; + if (cur == z) { + //copy the data from the removed node. + struct TreeNode* newroot = z->dup_next; + newroot->color = z->color; + newroot->left_subtree_sum = z->left_subtree_sum; + newroot->left = z->left; + if (newroot->left != NULL) { + newroot->left->parent = newroot; + } + newroot->right = z->right; + if (newroot->right != NULL) { + newroot->right->parent = newroot; + } + + newroot->parent = z->parent; + + if (z->parent) { + if (z->parent->left == z) { + z->parent->left = newroot; + } else { + z->parent->right = newroot; + } + } + binary_tree->queue_length--; + *deleted = true; + deleteNode(binary_tree, z); + } else { //remove the node from the link list; + prev->dup_next = cur->dup_next; + } + } else{ + if (z->data == data) { + removeNode(binary_tree, z, thread_id); + binary_tree->queue_length--; + *deleted = true; + } else { + *deleted = false; + printf("2 not found the node when deleting\n"); + } + } + } else { + *deleted = false; + printf("3 not found the node when deleting\n"); + } +} + +// Function to find a value in a binary search tree (non-recursive) +/*struct TreeNode* find(struct TreeNode* root, int val) { + while (root != NULL) { + if (val == root->val) { + return root; // Return the node if value is found + } else if (val < root->val) { + root = root->left; // Move to left subtree if value is less + } else { + root = root->right; // Move to right subtree if value is greater + } + } + return NULL; // Return NULL if value is not found or if the tree is empty +}*/ + +bool is_empty(struct binary_tree *binary_tree) { + assert(binary_tree != NULL); + + return binary_tree->root == NULL; +} + +void inorder(struct binary_tree *binary_tree, struct TreeNode* root) +{ + assert(binary_tree != NULL); + + if(root == NULL) + return; + inorder(binary_tree, root->left); + printf("%lu ", binary_tree->get_priority_fn(root->data)); + inorder(binary_tree, root->right); +} +// return the sum of nodes' execution time that less than the target priority +uint64_t findMaxValueLessThan(struct binary_tree *binary_tree, struct TreeNode* root, void *target, int thread_id) { + assert(binary_tree != NULL); + + if (root == NULL) { + return 0; + } + if (binary_tree->get_priority_fn(target) == binary_tree->get_priority_fn(root->data)) { + return root->left_subtree_sum; + } else if (binary_tree->get_priority_fn(target) < binary_tree->get_priority_fn(root->data)) { + return findMaxValueLessThan(binary_tree, root->left, target, thread_id); + } else { + return get_sum_exe_time_of_node(binary_tree, root, thread_id) + root->left_subtree_sum + findMaxValueLessThan(binary_tree, root->right, target, thread_id); + } + +} + +struct TreeNode* makeEmpty(struct binary_tree *binary_tree, struct TreeNode* root) +{ + assert(binary_tree != NULL); + + if(root != NULL) { + makeEmpty(binary_tree, root->left); + makeEmpty(binary_tree, root->right); + deleteNode(binary_tree, root); + } + return NULL; +} + diff --git a/runtime/src/local_runqueue_binary_tree.c_redblacktree b/runtime/src/local_runqueue_binary_tree.c_redblacktree new file mode 100644 index 000000000..fa25e56c1 --- /dev/null +++ b/runtime/src/local_runqueue_binary_tree.c_redblacktree @@ -0,0 +1,250 @@ +#include +#include + +#include "software_interrupt.h" +#include "arch/context.h" +#include "current_sandbox.h" +#include "debuglog.h" +#include "global_request_scheduler.h" +#include "local_runqueue.h" +#include "local_runqueue_binary_tree.h" +#include "panic.h" +#include "binary_search_tree.h" +#include "sandbox_functions.h" +#include "runtime.h" +#include "memlogging.h" + +extern thread_local uint8_t dispatcher_thread_idx; +extern _Atomic uint32_t local_queue_length[1024]; +extern uint32_t max_local_queue_length[1024]; +extern uint32_t max_local_queue_height[1024]; +extern bool runtime_exponential_service_time_simulation_enabled; +extern thread_local int global_worker_thread_idx; +extern struct sandbox* current_sandboxes[1024]; +extern struct binary_tree *worker_binary_trees[1024]; +thread_local static struct binary_tree *local_runqueue_binary_tree = NULL; + + +/** + * Checks if the run queue is empty + * @returns true if empty. false otherwise + */ +bool +local_runqueue_binary_tree_is_empty() +{ + assert(local_runqueue_binary_tree != NULL); + + return is_empty(local_runqueue_binary_tree); +} + +/** + * Checks if the run queue is empty + * @returns true if empty. false otherwise + */ +bool +local_runqueue_binary_tree_is_empty_index(int index) +{ + struct binary_tree *binary_tree = worker_binary_trees[index]; + + assert(binary_tree != NULL); + + return is_empty(binary_tree); +} + +/** + * Adds a sandbox to the run queue + * @param sandbox + * @returns pointer to sandbox added + */ +void +local_runqueue_binary_tree_add(struct sandbox *sandbox) +{ + assert(sandbox != NULL); + + lock_node_t node_lock = {}; + lock_lock(&local_runqueue_binary_tree->lock, &node_lock); + insert(local_runqueue_binary_tree, sandbox, global_worker_thread_idx); + lock_unlock(&local_runqueue_binary_tree->lock, &node_lock); +} + +void +local_runqueue_binary_tree_add_index(int index, struct sandbox *sandbox) +{ + assert(sandbox != NULL); + + struct binary_tree *binary_tree = worker_binary_trees[index]; + lock_node_t node_lock = {}; + lock_lock(&binary_tree->lock, &node_lock); + insert(binary_tree, sandbox, index); + lock_unlock(&binary_tree->lock, &node_lock); + + /*int height = findHeight(binary_tree->root); + if ( height > max_local_queue_height[index]) { + max_local_queue_height[index] = height; + }*/ + + atomic_fetch_add(&local_queue_length[index], 1); + if (local_queue_length[index] > max_local_queue_length[index]) { + max_local_queue_length[index] = local_queue_length[index]; + /*mem_log("listener %d 1:%u 2:%u 3:%u 4:%u 5:%u 6:%u 7:%u 8:%u 9:%u\n", dispatcher_thread_idx, max_local_queue_length[0], + max_local_queue_length[1],max_local_queue_length[2], + max_local_queue_length[3],max_local_queue_length[4], max_local_queue_length[5], max_local_queue_length[6], + max_local_queue_length[7], max_local_queue_length[8]); + */ + } + + /* Set estimated exeuction time for the sandbox */ + if (runtime_exponential_service_time_simulation_enabled == false) { + uint32_t uid = sandbox->route->admissions_info.uid; + uint64_t estimated_execute_cost = perf_window_get_percentile(&worker_perf_windows[index][uid], + sandbox->route->admissions_info.percentile, + sandbox->route->admissions_info.control_index); + /* Use expected execution time in the configuration file as the esitmated execution time + if estimated_execute_cost is 0 + */ + if (estimated_execute_cost == 0) { + estimated_execute_cost = sandbox->route->expected_execution_cycle; + } + sandbox->estimated_cost = estimated_execute_cost; + sandbox->relative_deadline = sandbox->route->relative_deadline; + } + /* Record TS and calcuate RS. SRSF algo: + 1. When reqeust arrives to the queue, record TS and calcuate RS. RS = deadline - execution time + 2. When request starts running, update RS + 3. When request stops, update TS + 4. When request resumes, update RS + */ + sandbox->srsf_stop_running_ts = __getcycles(); + sandbox->srsf_remaining_slack = sandbox->relative_deadline - sandbox->estimated_cost; + worker_queuing_cost_increment(index, sandbox->estimated_cost); +} + +/** + * Deletes a sandbox from the runqueue + * @param sandbox to delete + */ +static void +local_runqueue_binary_tree_delete(struct sandbox *sandbox) +{ + assert(sandbox != NULL); + + lock_node_t node_lock = {}; + lock_lock(&local_runqueue_binary_tree->lock, &node_lock); + bool deleted = false; + delete_i(local_runqueue_binary_tree, sandbox, &deleted, global_worker_thread_idx); + lock_unlock(&local_runqueue_binary_tree->lock, &node_lock); + if (deleted == false) { + panic("Tried to delete sandbox %lu state %d from runqueue %p, but was not present\n", + sandbox->id, sandbox->state, local_runqueue_binary_tree); + } + + atomic_fetch_sub(&local_queue_length[global_worker_thread_idx], 1); + worker_queuing_cost_decrement(global_worker_thread_idx, sandbox->estimated_cost); +} + +/** + * This function determines the next sandbox to run. + * This is the head of the local runqueue + * + * Execute the sandbox at the head of the thread local runqueue + * @return the sandbox to execute or NULL if none are available + */ +struct sandbox * +local_runqueue_binary_tree_get_next() +{ + /* Get the minimum deadline of the sandbox of the local request queue */ + struct TreeNode *node = findMin(local_runqueue_binary_tree); + if (node != NULL) { + return node->data; + } else { + return NULL; + } +} + +/** + * Try but not real add a item to the local runqueue. + * @param index The worker thread id + * @param sandbox Try to add + * @returns The waiting serving time in cycles for this sandbox if adding it to the queue + */ +uint64_t +local_runqueue_binary_tree_try_add_index(int index, struct sandbox *sandbox, bool *need_interrupt) +{ + struct binary_tree *binary_tree = worker_binary_trees[index]; + assert(binary_tree != NULL); + + if (is_empty(binary_tree)) { + /* The worker is idle */ + *need_interrupt = false; + return 0; + } else if (current_sandboxes[index] != NULL && + current_sandboxes[index]->srsf_remaining_slack > 0 && + sandbox_is_preemptable(current_sandboxes[index]) == true && + sandbox_get_priority(sandbox) < sandbox_get_priority(current_sandboxes[index])) { + /* The new one has a higher priority than the current one, need to interrupt the current one */ + *need_interrupt = true; + return 0; + } else { + /* Current sandbox cannot be interrupted because its priority is higher or its RS is 0, just find + a right location to add the new sandbox to the tree + */ + need_interrupt = false; + uint64_t waiting_serving_time = 0; + lock_node_t node_lock = {}; + lock_lock(&binary_tree->lock, &node_lock); + waiting_serving_time = findMaxValueLessThan(binary_tree, binary_tree->root, sandbox, index); + lock_unlock(&binary_tree->lock, &node_lock); + return waiting_serving_time; + } + +} + +int local_runqueue_binary_tree_get_height() { + assert (local_runqueue_binary_tree != NULL); + return findHeight(local_runqueue_binary_tree->root); +} + +int local_runqueue_binary_tree_get_length() { + assert (local_runqueue_binary_tree != NULL); + return getNonDeletedNodeCount(local_runqueue_binary_tree); +} + +int local_runqueue_binary_tree_get_length_index(int index) { + struct binary_tree *binary_tree = worker_binary_trees[index]; + assert(binary_tree != NULL); + + return getNonDeletedNodeCount(binary_tree); +} + +void local_runqueue_print_in_order(int index) { + struct binary_tree *binary_tree = worker_binary_trees[index]; + assert(binary_tree != NULL); + print_tree_in_order(binary_tree); +} + +/** + * Registers the PS variant with the polymorphic interface + */ +void +local_runqueue_binary_tree_initialize() +{ + /* Initialize local state */ + local_runqueue_binary_tree = init_binary_tree(true, sandbox_get_priority, sandbox_get_execution_cost, global_worker_thread_idx, 4096); + + worker_binary_trees[global_worker_thread_idx] = local_runqueue_binary_tree; + /* Register Function Pointers for Abstract Scheduling API */ + struct local_runqueue_config config = { .add_fn = local_runqueue_binary_tree_add, + .add_fn_idx = local_runqueue_binary_tree_add_index, + .try_add_fn_idx = local_runqueue_binary_tree_try_add_index, + .is_empty_fn = local_runqueue_binary_tree_is_empty, + .is_empty_fn_idx = local_runqueue_binary_tree_is_empty_index, + .delete_fn = local_runqueue_binary_tree_delete, + .get_next_fn = local_runqueue_binary_tree_get_next, + .get_height_fn = local_runqueue_binary_tree_get_height, + .get_length_fn = local_runqueue_binary_tree_get_length, + .get_length_fn_idx = local_runqueue_binary_tree_get_length_index, + .print_in_order_fn_idx = local_runqueue_print_in_order + }; + + local_runqueue_initialize(&config); +} From 440058cb177686ff2583d5507d3d021b4e6f7c6e Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Sun, 26 May 2024 16:19:32 -0600 Subject: [PATCH 124/198] for binary search tree to get_next: when tree length is 1, then return root without locking directly --- runtime/include/binary_search_tree.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/runtime/include/binary_search_tree.h b/runtime/include/binary_search_tree.h index bd654a7b7..8116810ca 100644 --- a/runtime/include/binary_search_tree.h +++ b/runtime/include/binary_search_tree.h @@ -226,6 +226,10 @@ struct TreeNode* findMin(struct binary_tree *binary_tree, struct TreeNode *root) return NULL; } + if (binary_tree->queue_length == 1) { + return root; + } + lock_node_t node = {}; lock_lock(&binary_tree->lock, &node); while (root->left != NULL) { From 092c9f8bae2ee4a58c7717add8203eede0678b71 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Sun, 26 May 2024 16:46:55 -0600 Subject: [PATCH 125/198] update sandbox_perf_log.h --- runtime/include/sandbox_perf_log.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/include/sandbox_perf_log.h b/runtime/include/sandbox_perf_log.h index 7ea71d6b7..1526d12ac 100644 --- a/runtime/include/sandbox_perf_log.h +++ b/runtime/include/sandbox_perf_log.h @@ -58,7 +58,7 @@ sandbox_perf_log_print_entry(struct sandbox *sandbox) global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route,init_time, cleanup, deadline, sandbox->context_switch_to, other, t1,t2,t3,t4,t5); */ - mem_log("tid %d %u miss %lu %lu %lu %s %lu %lu %lu %u\n", + mem_log("%d %u miss %lu %lu %lu %s %lu %lu %lu %u\n", global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route,init_time, cleanup, deadline,local_queue_length[global_worker_thread_idx]); @@ -67,7 +67,7 @@ sandbox_perf_log_print_entry(struct sandbox *sandbox) global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route,init_time, cleanup, deadline, sandbox->context_switch_to, other, t1,t2,t3,t4,t5); */ - mem_log("tid %d %u meet %lu %lu %lu %s %lu %lu %lu %lu\n", + mem_log("%d %u meet %lu %lu %lu %s %lu %lu %lu %lu\n", global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route,init_time, cleanup, deadline,deadline,local_queue_length[global_worker_thread_idx]); From 7f373fb10f7a24067383405d917a0318bfdea680 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 29 May 2024 23:03:42 -0600 Subject: [PATCH 126/198] update ori_sledge_tests/start.sh --- runtime/tests/ori_sledge_tests/start.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/tests/ori_sledge_tests/start.sh b/runtime/tests/ori_sledge_tests/start.sh index c02f056c8..7f6560052 100755 --- a/runtime/tests/ori_sledge_tests/start.sh +++ b/runtime/tests/ori_sledge_tests/start.sh @@ -17,7 +17,7 @@ declare project_path="$( )" echo $project_path path=`pwd` -export SLEDGE_DISABLE_PREEMPTION=true +export SLEDGE_DISABLE_PREEMPTION=false #export SLEDGE_SIGALRM_HANDLER=TRIAGED export SLEDGE_SCHEDULER=EDF export SLEDGE_SANDBOX_PERF_LOG=$path/server.log From fc69b22efb5b97231b6b9449f4edf3daafc67a6a Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 29 May 2024 23:07:20 -0600 Subject: [PATCH 127/198] update ori_sledge_tests/start.sh --- runtime/tests/ori_sledge_tests/start.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/tests/ori_sledge_tests/start.sh b/runtime/tests/ori_sledge_tests/start.sh index 7f6560052..b11959c70 100755 --- a/runtime/tests/ori_sledge_tests/start.sh +++ b/runtime/tests/ori_sledge_tests/start.sh @@ -20,6 +20,7 @@ path=`pwd` export SLEDGE_DISABLE_PREEMPTION=false #export SLEDGE_SIGALRM_HANDLER=TRIAGED export SLEDGE_SCHEDULER=EDF +export SLEDGE_NWORKERS=1 export SLEDGE_SANDBOX_PERF_LOG=$path/server.log #echo $SLEDGE_SANDBOX_PERF_LOG cd $project_path/runtime/bin From daab9d454693f2eacd6a1e9946f1d3eeb000ff29 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 29 May 2024 23:56:31 -0600 Subject: [PATCH 128/198] update ori_sledge_tests/start.sh, upload measure_throughput.sh --- runtime/tests/ori_sledge_tests/measure_throughput.sh | 2 ++ 1 file changed, 2 insertions(+) create mode 100755 runtime/tests/ori_sledge_tests/measure_throughput.sh diff --git a/runtime/tests/ori_sledge_tests/measure_throughput.sh b/runtime/tests/ori_sledge_tests/measure_throughput.sh new file mode 100755 index 000000000..422ca3558 --- /dev/null +++ b/runtime/tests/ori_sledge_tests/measure_throughput.sh @@ -0,0 +1,2 @@ +ulimit -n 655350 +hey -disable-compression -disable-redirects -cpus 15 -z "20"s -c "400" -m POST "http://10.10.1.1:31850/empty" From 3724e18570daef29844293d94eb08b7dd879420f Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 29 May 2024 23:57:04 -0600 Subject: [PATCH 129/198] update ori_sledge_tests/start.sh --- runtime/tests/ori_sledge_tests/start.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/tests/ori_sledge_tests/start.sh b/runtime/tests/ori_sledge_tests/start.sh index b11959c70..ed37c86c3 100755 --- a/runtime/tests/ori_sledge_tests/start.sh +++ b/runtime/tests/ori_sledge_tests/start.sh @@ -17,7 +17,7 @@ declare project_path="$( )" echo $project_path path=`pwd` -export SLEDGE_DISABLE_PREEMPTION=false +export SLEDGE_DISABLE_PREEMPTION=true #export SLEDGE_SIGALRM_HANDLER=TRIAGED export SLEDGE_SCHEDULER=EDF export SLEDGE_NWORKERS=1 From aa3ad1c6367b045dfe759e0e968518c812445584 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 31 May 2024 10:58:20 -0600 Subject: [PATCH 130/198] upload sed_json.sh --- runtime/tests/sed_json.sh | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100755 runtime/tests/sed_json.sh diff --git a/runtime/tests/sed_json.sh b/runtime/tests/sed_json.sh new file mode 100755 index 000000000..ad2eadc3b --- /dev/null +++ b/runtime/tests/sed_json.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +if [ $# -ne 3 ]; then + echo "Usage: $0 " + exit 1 +fi + +FILENAME=$1 +NUMBER1=$2 +NUMBER2=$3 + +# Validate if file exists +if [ ! -f "$FILENAME" ]; then + echo "File $FILENAME does not exist." + exit 1 +fi + +# Replace the "n-resas" value in the 11th line with NUMBER1 +sed -i "11s/\(\"n-resas\": \)[0-9]\+/\1$NUMBER1/" "$FILENAME" + +# Replace the "n-resas" value in the 21st line with NUMBER2 +sed -i "21s/\(\"n-resas\": \)[0-9]\+/\1$NUMBER2/" "$FILENAME" + +echo "The file $FILENAME has been updated." + From 0bb205272ed008fd9b35017dc87c8d91b1821c34 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 31 May 2024 15:29:56 -0600 Subject: [PATCH 131/198] update hash.json --- runtime/tests/hash.json | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/runtime/tests/hash.json b/runtime/tests/hash.json index 8c6212132..396b8f926 100644 --- a/runtime/tests/hash.json +++ b/runtime/tests/hash.json @@ -8,23 +8,13 @@ { "route": "/hash", "request-type": 1, - "n-resas": 2, + "n-resas": 5, "path": "hash.wasm.so", "admissions-percentile": 70, "expected-execution-us": 5, "relative-deadline-us": 50, "http-resp-content-type": "text/plain" - }, - { - "route": "/hash2", - "request-type": 2, - "n-resas": 1, - "path": "hash.wasm.so", - "admissions-percentile": 70, - "expected-execution-us": 6480, - "relative-deadline-us": 64800, - "http-resp-content-type": "text/plain" - } + } ] } From f4d7995d6fffcc2e3a0184ec4c00a3d0f19a8911 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Sun, 2 Jun 2024 00:54:56 -0600 Subject: [PATCH 132/198] upload tests/hash_high_bimodal.json and update binary_search_tree.h_redblacktree, local_runqueue_binary_tree.c_redblacktree --- .../include/binary_search_tree.h_redblacktree | 76 +- runtime/include/sandbox_perf_log.h | 2 +- .../local_runqueue_binary_tree.c_redblacktree | 6 + runtime/src/software_interrupt.c | 7 + runtime/tests/binary_search_tree.c | 717 ++++++++++++++++++ runtime/tests/dummy_tpcc_DARC.json | 4 +- runtime/tests/hash_high_bimodal.json | 33 + runtime/tests/redblacktree.c | 617 +++++++++++++++ 8 files changed, 1408 insertions(+), 54 deletions(-) create mode 100644 runtime/tests/binary_search_tree.c create mode 100644 runtime/tests/hash_high_bimodal.json create mode 100644 runtime/tests/redblacktree.c diff --git a/runtime/include/binary_search_tree.h_redblacktree b/runtime/include/binary_search_tree.h_redblacktree index c0cd86df5..2b5936086 100644 --- a/runtime/include/binary_search_tree.h_redblacktree +++ b/runtime/include/binary_search_tree.h_redblacktree @@ -465,10 +465,10 @@ void removeNode(struct binary_tree *binary_tree, struct TreeNode *z, int thread_ if ( z->left != NULL && z->right != NULL ) { y = minimum(z->right); - int diff = get_sum_exe_time_of_node(binary_tree, y, thread_id) - get_sum_exe_time_of_node(binary_tree, z, thread_id); + int exe_time_y = get_sum_exe_time_of_node(binary_tree, y, thread_id); struct TreeNode* cur = z->right; while (cur != y) { - cur->left_subtree_sum -= diff; + cur->left_subtree_sum -= exe_time_y; cur = cur->left; } @@ -482,20 +482,6 @@ void removeNode(struct binary_tree *binary_tree, struct TreeNode *z, int thread_ return; } - //now the node to be removed has only no children - //or only one child, update the sum_left value of - //all the node along the path from root to z. - struct TreeNode* current = z; - struct TreeNode* p = current->parent; - while (p != NULL) { - if (p->left == current) - { - p->left_subtree_sum -= binary_tree->get_execution_cost_fn(z->data, thread_id); - } - current = p; - p = current->parent; - } - if (z->left == NULL) { x = z->right; transplant(binary_tree, z, z->right); @@ -518,7 +504,17 @@ void delete_i(struct binary_tree *binary_tree, void *data, bool *deleted, int th assert(binary_tree != NULL); *deleted = false; - struct TreeNode *z = searchByKey(binary_tree, data); + struct TreeNode* z = binary_tree->root; + while (z != NULL && binary_tree->get_priority_fn(z->data) != binary_tree->get_priority_fn(data)) { + if (binary_tree->get_priority_fn(data) < binary_tree->get_priority_fn(z->data)) { + z->left_subtree_sum -= binary_tree->get_execution_cost_fn(data, thread_id); + z = z->left; + } + else { + z = z->right; + } + } + if (z != NULL) { //if there are duplicated nodes in Z, //we just need to remove duplicated one. @@ -530,26 +526,7 @@ void delete_i(struct binary_tree *binary_tree, void *data, bool *deleted, int th cur = cur->dup_next; } - //if the target node has been found - if (cur != NULL) { - //update the sumLeft in all of its parent node. - struct TreeNode* current = z; - struct TreeNode* p = current->parent; - while (p != NULL) { - if (p->left == current) - { - p->left_subtree_sum -= binary_tree->get_execution_cost_fn(data, thread_id); - } - current = p; - p = current->parent; - } - } else { - *deleted = false; - printf("1 not found the node when deleting\n"); - return; - } - - //if the removed node is the head of the linkedlist; + //if the removed node is the head of the linkedlist; if (cur == z) { //copy the data from the removed node. struct TreeNode* newroot = z->dup_next; @@ -564,8 +541,8 @@ void delete_i(struct binary_tree *binary_tree, void *data, bool *deleted, int th newroot->right->parent = newroot; } - newroot->parent = z->parent; - + newroot->parent = z->parent; + if (z->parent) { if (z->parent->left == z) { z->parent->left = newroot; @@ -573,25 +550,22 @@ void delete_i(struct binary_tree *binary_tree, void *data, bool *deleted, int th z->parent->right = newroot; } } - binary_tree->queue_length--; - *deleted = true; - deleteNode(binary_tree, z); + deleteNode(binary_tree, z); + *deleted = true; } else { //remove the node from the link list; prev->dup_next = cur->dup_next; + deleteNode(binary_tree, cur); + *deleted = true; } } else{ - if (z->data == data) { + if (z->data == data) { removeNode(binary_tree, z, thread_id); - binary_tree->queue_length--; - *deleted = true; - } else { - *deleted = false; - printf("2 not found the node when deleting\n"); - } + *deleted = true; + } } } else { - *deleted = false; - printf("3 not found the node when deleting\n"); + *deleted = false; + return; } } diff --git a/runtime/include/sandbox_perf_log.h b/runtime/include/sandbox_perf_log.h index 1526d12ac..042da55f8 100644 --- a/runtime/include/sandbox_perf_log.h +++ b/runtime/include/sandbox_perf_log.h @@ -69,7 +69,7 @@ sandbox_perf_log_print_entry(struct sandbox *sandbox) */ mem_log("%d %u meet %lu %lu %lu %s %lu %lu %lu %lu\n", global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, - sandbox->route->route,init_time, cleanup, deadline,deadline,local_queue_length[global_worker_thread_idx]); + sandbox->route->route,init_time, cleanup, deadline,local_queue_length[global_worker_thread_idx]); } /* diff --git a/runtime/src/local_runqueue_binary_tree.c_redblacktree b/runtime/src/local_runqueue_binary_tree.c_redblacktree index fa25e56c1..5a5d88bbe 100644 --- a/runtime/src/local_runqueue_binary_tree.c_redblacktree +++ b/runtime/src/local_runqueue_binary_tree.c_redblacktree @@ -117,6 +117,12 @@ local_runqueue_binary_tree_add_index(int index, struct sandbox *sandbox) sandbox->srsf_stop_running_ts = __getcycles(); sandbox->srsf_remaining_slack = sandbox->relative_deadline - sandbox->estimated_cost; worker_queuing_cost_increment(index, sandbox->estimated_cost); + //------------------for test------------------------- + /*int high = findHeight(binary_tree->root); + if (high > max_local_queue_height[index]) { + max_local_queue_height[index] = high; + } */ + //---------------------end------------------------- } /** diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index 9106eb409..f097e94fc 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -260,6 +260,8 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void double arriving_rate = total_requests / seconds; printf("%d try preempts:%u max global queue %u arriving rate %f total requests %lu\n", dispatcher_thread_idx, dispatcher_try_interrupts, max_queue_length, arriving_rate, total_requests); + //mem_log("%d try preempts:%u max global queue %u arriving rate %f total requests %lu\n", dispatcher_thread_idx, + // dispatcher_try_interrupts, max_queue_length, arriving_rate, total_requests); dump_log_to_file(); break; } @@ -272,6 +274,11 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void atomic_load(&sandbox_state_totals[SANDBOX_ALLOCATED]), total_complete_requests, interrupts, preemptable_interrupts, max_local_queue_length[global_worker_thread_idx]); dump_log_to_file(); + //printf("id %d max local queue %u height %u new %u old %u current length %u real length %d total complete request %u\n", + // global_worker_thread_idx, max_local_queue_length[global_worker_thread_idx],max_local_queue_height[global_worker_thread_idx], + // worker_new_sandbox[global_worker_thread_idx], worker_old_sandbox[global_worker_thread_idx], + // local_runqueue_count[global_worker_thread_idx], + // local_runqueue_get_length(), total_complete_requests); printf("id %d max local queue %u new %u old %u current length %u real length %d total complete request %u\n", global_worker_thread_idx, max_local_queue_length[global_worker_thread_idx], worker_new_sandbox[global_worker_thread_idx], worker_old_sandbox[global_worker_thread_idx], diff --git a/runtime/tests/binary_search_tree.c b/runtime/tests/binary_search_tree.c new file mode 100644 index 000000000..3e7b53b74 --- /dev/null +++ b/runtime/tests/binary_search_tree.c @@ -0,0 +1,717 @@ +#include +#include +#include +#include +#include + +#define MAX_NODES 4096 // Maximum number of nodes in the pool + +// Define the colors for Red-Black Tree +typedef enum { RED, BLACK } Color; + +// Definition of a binary search tree node +struct TreeNode { + struct TreeNode *left; + struct TreeNode *right; + struct TreeNode *next; // pointing to the next node, this is used for nodePool + // to find next available node + struct TreeNode *dup_next; // pointing to next duplicate key item + struct TreeNode *parent; + Color color; + uint64_t left_subtree_sum; + uint64_t deadline; + uint64_t exe_time; +}; + +// Definition of TreeNode memory pool +struct TreeNodePool { + struct TreeNode* head; +}; + +struct binary_tree { + struct TreeNode *root; + struct TreeNodePool nodePool; + int id; + int queue_length; +}; + +// Initialize the node pool +void initNodePool(struct TreeNodePool *nodePool, int pool_size) { + + assert(nodePool != NULL); + + struct TreeNode *nodes = (struct TreeNode*)malloc(pool_size * sizeof(struct TreeNode)); + nodePool->head = nodes; // Initialize head to the beginning of the node array + + for (int i = 0; i < MAX_NODES - 1; ++i) { + nodes[i].next = &nodes[i + 1]; // Set the next pointer of each node to the next node + nodes[i].left = NULL; + nodes[i].right = NULL; + nodes[i].dup_next = NULL; + nodes[i].parent = NULL; + nodes[i].color = RED; + nodes[i].left_subtree_sum = 0; + nodes[i].deadline = 0; + nodes[i].exe_time = 0; + } + nodes[MAX_NODES - 1].next = NULL; +} + +struct binary_tree * init_binary_tree(int id, int queue_size) { + + struct binary_tree *binary_tree = (struct binary_tree *)calloc(1, sizeof(struct binary_tree)); + initNodePool(&binary_tree->nodePool, queue_size); + binary_tree->root = NULL; + binary_tree->id = id; + binary_tree->queue_length = 0; + + + return binary_tree; +} + +// Function to get the total number of non-deleted nodes in the binary tree +int getNonDeletedNodeCount(struct binary_tree *binary_tree) { + assert(binary_tree != NULL); + return binary_tree->queue_length; +} + +// Get a new node from the pool +struct TreeNode* newNode(struct binary_tree *binary_tree, Color color, struct TreeNode* left, + struct TreeNode* right, struct TreeNode* parent, uint64_t deadline, uint64_t exe_time) { + + assert(binary_tree != NULL); + + if (binary_tree->nodePool.head == NULL) { + printf("Binary search tree queue %d is full\n", binary_tree->id); + return NULL; + } else { + // Remove a node from the head of the memory pool + struct TreeNode* new_node_t = binary_tree->nodePool.head; + binary_tree->nodePool.head = new_node_t->next; + new_node_t->next = NULL; // Reset the next pointer of the new node + new_node_t->deadline = deadline; + new_node_t->exe_time = exe_time; + new_node_t->left = left; + new_node_t->right = right; + new_node_t->parent = parent; + new_node_t->color = color; + new_node_t->dup_next = NULL; + new_node_t->left_subtree_sum = 0; + return new_node_t; + } +} + +void getAvailableCapacity(struct binary_tree *binary_tree) { + + assert(binary_tree != NULL); + + int size = 0; + struct TreeNode* start = binary_tree->nodePool.head; + while(start) { + size++; + start = start->next; + } + + printf("available capacity of the queue is %d\n", size); +} + +void print_in_order(struct TreeNode* node) { + if (node != NULL) { + // Recursively traverse the left subtree + print_in_order(node->left); + + // Print the data in the current node + printf("%lu(%lu) ", node->deadline, node->exe_time); + //Print data in the dup_next list + struct TreeNode* cur = node->dup_next; + while(cur) { + printf("%lu(%lu) ", cur->deadline, cur->exe_time); + cur = cur->dup_next; + } + + // Recursively traverse the right subtree + print_in_order(node->right); + } +} + +// Function to print the items in the binary search tree in order +void print_tree_in_order(struct binary_tree* bst) { + if (bst != NULL) { + print_in_order(bst->root); + printf("\n"); + } +} + +//get the total execute time of a node. +uint64_t get_sum_exe_time_of_node(struct TreeNode* node){ + uint64_t total = 0; + struct TreeNode* curNode = node; + while (curNode!=NULL) { + total += curNode->exe_time; + curNode = curNode->dup_next; + } + + return total; +} + +//get the total execute time of a node's subtree, including left and right subtree +uint64_t get_sum_exe_time_of_subtree(struct TreeNode* root) { + if (root == NULL) { + return 0; + } + + return get_sum_exe_time_of_node(root) + root->left_subtree_sum + get_sum_exe_time_of_subtree(root->right); +} + +// Return a node to the pool +void deleteNode(struct binary_tree *binary_tree, struct TreeNode* node) { + + assert(binary_tree != NULL); + assert(node != NULL); + + // Insert the node back to the head of the memory pool + node->left = NULL; + node->right = NULL; + node->parent = NULL; + node->color = RED; + node->deadline = 0; + node->exe_time = 0; + node->left_subtree_sum = 0; + node->dup_next = NULL; + node->next = binary_tree->nodePool.head; + binary_tree->nodePool.head = node; +} + +int findHeight(struct TreeNode *root) +{ + int lefth, righth; + if(root == NULL) + return 0; + lefth = findHeight(root->left); + righth = findHeight(root->right); + return (lefth > righth ? lefth : righth)+1; +} +// Update root if rotating. +void leftRotate(struct binary_tree *binary_tree, struct TreeNode *x) { + struct TreeNode *y = x->right; + x->right = y->left; + if (y->left != NULL) + y->left->parent = x; + + y->parent = x->parent; + + if (x->parent == NULL) + binary_tree->root = y; + else if (x == x->parent->left) + x->parent->left = y; + else + x->parent->right = y; + y->left = x; + x->parent = y; + y->left_subtree_sum += x->exe_time + x->left_subtree_sum; +} + +// Update root if rotatiing +void rightRotate(struct binary_tree *binary_tree, struct TreeNode *x) { + struct TreeNode *y = x->left; + x->left = y->right; + + int new_sum_left = 0; + if (y->right != NULL) { + y->right->parent = x; + new_sum_left = get_sum_exe_time_of_subtree(y->right); //y->right->exe_time + y->right->sum_left; + } + + x->left_subtree_sum = new_sum_left; + y->parent = x->parent; + if (x->parent == NULL) + binary_tree->root = y; + else if (x == x->parent->right) + x->parent->right = y; + else + x->parent->left = y; + y->right = x; + x->parent = y; +} + +void insertFixup(struct binary_tree *binary_tree, struct TreeNode *z) { + while (z->parent != NULL && z->parent->color == RED) { + if (z->parent == z->parent->parent->left) { + struct TreeNode *y = z->parent->parent->right; + if (y != NULL && y->color == RED) { + z->parent->color = BLACK; + y->color = BLACK; + z->parent->parent->color = RED; + z = z->parent->parent; + } else { + if (z == z->parent->right) { + z = z->parent; + leftRotate(binary_tree, z); + } + z->parent->color = BLACK; + z->parent->parent->color = RED; + rightRotate(binary_tree, z->parent->parent); + } + } else { + struct TreeNode *y = z->parent->parent->left; + if (y != NULL && y->color == RED) { + z->parent->color = BLACK; + y->color = BLACK; + z->parent->parent->color = RED; + z = z->parent->parent; + } else { + if (z == z->parent->left) { + z = z->parent; + rightRotate(binary_tree, z); + } + z->parent->color = BLACK; + z->parent->parent->color = RED; + leftRotate(binary_tree, z->parent->parent); + } + } + } + binary_tree->root->color = BLACK; +} + +// Function to insert a value into a binary search tree. Tree root might be changed after inserting a new node +void insert(struct binary_tree *binary_tree, uint64_t deadline, uint64_t exe_time) { + struct TreeNode *z = newNode(binary_tree, RED, NULL, NULL, NULL, deadline, exe_time); + binary_tree->queue_length++; + struct TreeNode *y = NULL; + struct TreeNode *x = binary_tree->root; + while (x != NULL) { + y = x; + + //if found a dup_next deadline, inserted the node + //at the end of the linklist + if (z->deadline == x->deadline) { + //find the tail the link list; + struct TreeNode* tail = x; + while (tail->dup_next != NULL) { + tail = tail->dup_next; + } + //append the new node at the end of the list; + tail->dup_next = z; + z->color = x->color; + z->left_subtree_sum = x->left_subtree_sum; + return; + } else if (z->deadline < x->deadline) { + x->left_subtree_sum += z->exe_time; + x = x->left; + } else { + x = x->right; + } + } + + z->parent = y; + if (y == NULL) { + binary_tree->root = z; + } else if (z->deadline < y->deadline) { + y->left = z; + } else { + y->right = z; + } + + insertFixup(binary_tree, z); +} + +// Helper function to find the minimum value in a binary search tree +struct TreeNode* findMin(struct binary_tree *binary_tree) { + + assert(binary_tree != NULL); + + struct TreeNode *curNode = binary_tree->root; + if (curNode == NULL) { + return NULL; + } + + while (curNode->left != NULL) { + curNode = curNode->left; // Keep traversing to the left until the leftmost node is reached + } + return curNode; +} + +// Helper function to find the maximum value in a binary search tree +struct TreeNode* findMax(struct binary_tree *binary_tree) { + + assert(binary_tree != NULL); + + struct TreeNode *curNode = binary_tree->root; + if (curNode == NULL) { + return NULL; + } + + while (curNode->right != NULL) { + curNode = curNode->right; // Keep traversing to the right until the rightmost node is reached + } + return curNode; +} + +struct TreeNode* searchByKey(struct binary_tree *binary_tree, uint64_t deadline) { + struct TreeNode* current = binary_tree->root; + while (current != NULL && current->deadline != deadline) { + if (deadline < current->deadline) { + current = current->left; + } + else { + current = current->right; + } + } + + return current; +} + +void transplant(struct binary_tree *binary_tree, struct TreeNode *u, struct TreeNode *v) { + if (u->parent == NULL) + binary_tree->root = v; + else if (u == u->parent->left) + u->parent->left = v; + else + u->parent->right = v; + if (v != NULL) + v->parent = u->parent; +} + +struct TreeNode* minimum(struct TreeNode *node) { + while (node->left != NULL) { + node = node->left; + } + return node; +} + +void deleteFixup(struct binary_tree *binary_tree, struct TreeNode *x) { + while (x != binary_tree->root && (x == NULL || x->color == BLACK)) { + + if (x == NULL){ + break; + } + + if ( x == x->parent->left) { + struct TreeNode *w = x->parent->right; + if (w->color == RED) { + w->color = BLACK; + x->parent->color = RED; + leftRotate(binary_tree, x->parent); + w = x->parent->right; + } + if ((w->left == NULL || w->left->color == BLACK) && (w->right == NULL || w->right->color == BLACK)) { + w->color = RED; + x = x->parent; + } else { + if (w->right == NULL || w->right->color == BLACK) { + if (w->left != NULL) w->left->color = BLACK; + w->color = RED; + rightRotate(binary_tree, w); + w = x->parent->right; + } + w->color = x->parent->color; + x->parent->color = BLACK; + if (w->right != NULL) w->right->color = BLACK; + leftRotate(binary_tree, x->parent); + x = binary_tree->root; + } + } else { + struct TreeNode *w = x->parent->left; + if (w->color == RED) { + w->color = BLACK; + x->parent->color = RED; + rightRotate(binary_tree, x->parent); + w = x->parent->left; + } + if ((w->right == NULL || w->right->color == BLACK) && (w->left == NULL || w->left->color == BLACK)) { + w->color = RED; + x = x->parent; + } else { + if (w->left == NULL || w->left->color == BLACK) { + if (w->right != NULL) w->right->color = BLACK; + w->color = RED; + leftRotate(binary_tree, w); + w = x->parent->left; + } + w->color = x->parent->color; + x->parent->color = BLACK; + if (w->left != NULL) w->left->color = BLACK; + rightRotate(binary_tree, x->parent); + x = binary_tree->root; + } + } + } + if (x != NULL) x->color = BLACK; +} + +void removeNode(struct binary_tree *binary_tree, struct TreeNode *z) { + struct TreeNode *y = z; + struct TreeNode *x = NULL; + Color y_original_color = y->color; + + if ( z->left != NULL && z->right != NULL ) { + y = minimum(z->right); + + int diff = get_sum_exe_time_of_node(y) - get_sum_exe_time_of_node(z); + struct TreeNode* cur = z->right; + while (cur != y) { + cur->left_subtree_sum -= diff; + cur = cur->left; + } + + uint64_t remove_deadline = z->deadline; + uint64_t remove_exe_time = z->exe_time; + z->deadline = y->deadline; + z->exe_time = y->exe_time; + z->dup_next = y->dup_next; + y->deadline = remove_deadline; + y->exe_time = remove_exe_time; + y->dup_next = NULL; + + removeNode(binary_tree, y); + return; + } + + //now the node to be removed has only no children + //or only one child, update the sum_left value of + //all the node along the path from root to z. + struct TreeNode* current = z; + struct TreeNode* p = current->parent; + while (p != NULL) { + if (p->left == current) + { + p->left_subtree_sum -= z->exe_time; + } + current = p; + p = current->parent; + } + + if (z->left == NULL) { + x = z->right; + transplant(binary_tree, z, z->right); + + } else if (z->right == NULL) { + x = z->left; + transplant(binary_tree, z, z->left); + + } + + deleteNode(binary_tree, z); + if (y_original_color == BLACK) { + deleteFixup(binary_tree, x); + } +} + +// Function to delete a value from a binary search tree +void delete_i(struct binary_tree *binary_tree, uint64_t deadline, uint64_t exe_time, bool *deleted) { + + assert(binary_tree != NULL); + + struct TreeNode *z = searchByKey(binary_tree, deadline); + if (z != NULL) { + //if there are duplicated nodes in Z, + //we just need to remove duplicated one. + if (z->dup_next != NULL) { + struct TreeNode* cur = z; + struct TreeNode* prev = NULL; + while (cur && cur->exe_time != exe_time) { + prev = cur; + cur = cur->dup_next; + } + + //if the target node has been found + if (cur != NULL) { + //update the sumLeft in all of its parent node. + struct TreeNode* current = z; + struct TreeNode* p = current->parent; + while (p != NULL) { + if (p->left == current) + { + p->left_subtree_sum -= exe_time; + } + current = p; + p = current->parent; + } + } else { + *deleted = false; + printf("not found the node (%d %d)\n", deadline, exe_time); + return; + } + + //if the removed node is the head of the linkedlist; + if (cur == z) { + //copy the data from the removed node. + struct TreeNode* newroot = z->dup_next; + newroot->color = z->color; + newroot->left_subtree_sum = z->left_subtree_sum; + newroot->left = z->left; + if (newroot->left != NULL) { + newroot->left->parent = newroot; + } + newroot->right = z->right; + if (newroot->right != NULL) { + newroot->right->parent = newroot; + } + + newroot->parent = z->parent; + + if (z->parent) { + if (z->parent->left == z) { + z->parent->left = newroot; + } else { + z->parent->right = newroot; + } + } + //clean up the remove node z; + //memset( z, 0, sizeof(Node)); + binary_tree->queue_length--; + *deleted = true; + deleteNode(binary_tree, z); + } + else { //remove the node from the link list; + prev->dup_next = cur->dup_next; + } + } else{ + if (z->exe_time == exe_time) { + removeNode(binary_tree, z); + binary_tree->queue_length--; + *deleted = true; + } else { + *deleted = false; + printf("not found the node (%d %d)\n", deadline, exe_time); + } + } + } else { + *deleted = false; + printf("not found the node (%d %d)\n", deadline, exe_time); + } +} + +// Function to find a value in a binary search tree (non-recursive) +/*struct TreeNode* find(struct TreeNode* root, int val) { + while (root != NULL) { + if (val == root->val) { + return root; // Return the node if value is found + } else if (val < root->val) { + root = root->left; // Move to left subtree if value is less + } else { + root = root->right; // Move to right subtree if value is greater + } + } + return NULL; // Return NULL if value is not found or if the tree is empty +}*/ + +bool is_empty(struct binary_tree *binary_tree) { + assert(binary_tree != NULL); + + return binary_tree->root == NULL; +} + +void inorder(struct binary_tree *binary_tree, struct TreeNode* root) +{ + assert(binary_tree != NULL); + + if(root == NULL) + return; + inorder(binary_tree, root->left); + printf("%lu(%lu) ", root->deadline, root->exe_time); + inorder(binary_tree, root->right); +} +// return the sum of nodes' execution time that less than the target priority +uint64_t findMaxValueLessThan(struct binary_tree *binary_tree, struct TreeNode* root, uint64_t deadline) { + assert(binary_tree != NULL); + + if (root == NULL) { + return 0; + } + if (deadline == root->deadline) { + return root->left_subtree_sum; + } else if (deadline < root->deadline) { + return findMaxValueLessThan(binary_tree, root->left, deadline); + } else { + return get_sum_exe_time_of_node(root) + root->left_subtree_sum + findMaxValueLessThan(binary_tree, root->right, deadline); + } + +} + +struct TreeNode* makeEmpty(struct binary_tree *binary_tree, struct TreeNode* root) +{ + assert(binary_tree != NULL); + + if(root != NULL) { + makeEmpty(binary_tree, root->left); + makeEmpty(binary_tree, root->right); + deleteNode(binary_tree, root); + } + return NULL; +} + +int main() { + struct binary_tree * bst = init_binary_tree(12, MAX_NODES); + for(int i = 0; i < 64; i++) { + insert(bst, i+1, i+1); + } + print_tree_in_order(bst); + printf("\n"); + + printf("=============================================\n"); + for (int i = 0; i < 64; i++) { + printf("Sum of values less than %d: %lu\n", i+1, findMaxValueLessThan(bst, bst->root, i+1)); + } + + printf("\n============insert the duplicated value: 8===============" ); + insert(bst, 8, 8); + + for (int i = 0; i < 64; i++) { + printf("Sum of values less than %d: %lu\n", i+1, findMaxValueLessThan(bst, bst->root, i+1)); + } + + printf("\n============insert the duplicated value: 10===============" ); + insert(bst, 10, 10); + for (int i = 0; i < 64; i++) { + printf("Sum of values less than %d: %lu\n", i+1, findMaxValueLessThan(bst, bst->root, i+1)); + } + + printf("\n============remove the duplicated value: 8===============" ); + bool deleted = false; + delete_i(bst, 8, 8, &deleted); + for (int i = 0; i < 64; i++) { + printf("Sum of values less than %d: %lu\n", i+1, findMaxValueLessThan(bst, bst->root, i+1)); + } + + printf("\n============remove the duplicated value: 10===============" ); + delete_i(bst, 10, 10, &deleted); + for (int i = 0; i < 64; i++) { + printf("Sum of values less than %d: %lu\n", i+1, findMaxValueLessThan(bst, bst->root, i+1)); + } + + printf("\n============remove the single value: 20===============" ); + delete_i(bst, 20, 20, &deleted); + for (int i = 0; i < 64; i++) { + printf("Sum of values less than %d: %lu\n", i+1, findMaxValueLessThan(bst, bst->root, i+1)); + } + printf("\n============insert the duplicated value: 41===============" ); + insert(bst, 41, 35); + print_tree_in_order(bst); + printf("\n"); + + for (int i = 0; i < 64; i++) { + printf("Sum of values less than %d: %lu\n", i+1, findMaxValueLessThan(bst, bst->root, i+1)); + } + + printf("\n============remove the single value: 40===============" ); + + delete_i(bst, 40, 40, &deleted); + print_tree_in_order(bst); + printf("\n"); + for (int i = 0; i < 64; i++) { + printf("Sum of values less than %d: %lu\n", i+1, findMaxValueLessThan(bst, bst->root, i+1)); + } + + struct TreeNode *min = findMin(bst); + printf("min is (%u %u)\n", min->deadline, min->exe_time); + struct TreeNode *max = findMax(bst); + printf("max is (%u %u)\n", max->deadline, max->exe_time); + + printf("delete 45, 30\n"); + delete_i(bst, 45, 30, &deleted); + printf("delete 41, 35\n"); + delete_i(bst, 41, 35, &deleted); + print_tree_in_order(bst); + printf("\n"); +} diff --git a/runtime/tests/dummy_tpcc_DARC.json b/runtime/tests/dummy_tpcc_DARC.json index 5a7c1a1e6..41eef78fb 100644 --- a/runtime/tests/dummy_tpcc_DARC.json +++ b/runtime/tests/dummy_tpcc_DARC.json @@ -18,7 +18,7 @@ { "route": "/NewOrder", "request-type": 2, - "n-resas": 3, + "n-resas": 2, "path": "dummy_tpcc.wasm.so", "admissions-percentile": 70, "expected-execution-us": 5, @@ -28,7 +28,7 @@ { "route": "/Delivery-StockLevel", "request-type": 3, - "n-resas": 3, + "n-resas": 2, "path": "dummy_tpcc.wasm.so", "admissions-percentile": 70, "expected-execution-us": 5, diff --git a/runtime/tests/hash_high_bimodal.json b/runtime/tests/hash_high_bimodal.json new file mode 100644 index 000000000..448c14efc --- /dev/null +++ b/runtime/tests/hash_high_bimodal.json @@ -0,0 +1,33 @@ +[ + { + "name": "gwu", + "port": 31850, + "replenishment-period-us": 0, + "max-budget-us": 0, + "routes": [ + { + "route": "/hash", + "request-type": 1, + "n-resas": 1, + "path": "hash.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 5, + "relative-deadline-us": 50, + "http-resp-content-type": "text/plain" + }, + { + "route": "/hash2", + "request-type": 2, + "n-resas": 4, + "path": "hash.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 5, + "relative-deadline-us": 50, + "http-resp-content-type": "text/plain" + } + ] + + } + +] + diff --git a/runtime/tests/redblacktree.c b/runtime/tests/redblacktree.c new file mode 100644 index 000000000..5514a2435 --- /dev/null +++ b/runtime/tests/redblacktree.c @@ -0,0 +1,617 @@ +// RedblackTreeChatGPT.cpp : This file contains the 'main' function. Program execution begins and ends there. +// + +#include +#include +#include + +// Define the colors for Red-Black Tree +typedef enum { RED, BLACK } Color; + +typedef struct NodeData { + int deadline; + int exe_time; + +}NodeData; + +// Node structure +typedef struct Node { + NodeData* data; + int sum_left; + Color color; + struct Node *left, *right, *parent, *duplicated; +} Node; + +// Red-Black Tree structure +typedef struct RBTree { + Node *root; +} RBTree; + +// Function prototypes +NodeData* createNodeData(int deadline, int exe_time); +Node* createNode(NodeData* data, Color color, Node* left, Node* right, Node* parent); +RBTree* createTree(); +void leftRotate(RBTree *tree, Node *x); +void rightRotate(RBTree *tree, Node *x); +void insertFixup(RBTree *tree, Node *z); +void insert(RBTree *tree, NodeData* data); +Node* search(RBTree *tree, NodeData* data); +Node* searchByKey(RBTree* tree, NodeData* data); +void transplant(RBTree *tree, Node *u, Node *v); +Node* minimum(Node *node); +void deleteFixup(RBTree *tree, Node *x); +void removeNode(RBTree *tree, Node *z); +void deleteNode(RBTree *tree, NodeData* data); +void inorder(Node *node); +void destroyTree(Node *node); +int getTotalExeTimeOf(Node* node); + + +int getTotalExeTimeOf(Node* node) { + int total = 0; + Node* cur = node; + while (cur != NULL) { + total += cur->data->exe_time; + cur = cur->duplicated; + } + + return total; +} + +NodeData* createNodeData(int deadline, int exe_time){ + NodeData* data = (NodeData*)malloc(sizeof(NodeData)); + data->deadline = deadline; + data->exe_time = exe_time; + + return data; +} + +Node* createNode(NodeData* data, Color color, Node* left, Node* right, Node* parent) { + Node* newNode = (Node*)malloc(sizeof(Node)); + newNode->data = data; + newNode->color = color; + newNode->left = left; + newNode->right = right; + newNode->parent = parent; + newNode->sum_left = 0; + newNode->duplicated = NULL; + return newNode; +} + +RBTree* createTree() { + RBTree* tree = (RBTree*)malloc(sizeof(RBTree)); + tree->root = NULL; + return tree; +} + +int getSumSubTree(Node* root) { + if (root == NULL) { + return 0; + } + + return getTotalExeTimeOf(root) + root->sum_left + getSumSubTree(root->right); +} + +void leftRotate(RBTree *tree, Node *x) { + Node *y = x->right; + x->right = y->left; + if (y->left != NULL) y->left->parent = x; + y->parent = x->parent; + if (x->parent == NULL) tree->root = y; + else if (x == x->parent->left) x->parent->left = y; + else x->parent->right = y; + y->left = x; + x->parent = y; + y->sum_left += x->data->exe_time + x->sum_left; +} + +void rightRotate(RBTree *tree, Node *x) { + Node *y = x->left; + x->left = y->right; + + int new_sum_left = 0; + if (y->right != NULL) { + y->right->parent = x; + new_sum_left = getSumSubTree( y->right ); //y->right->data->exe_time + y->right->sum_left; + } + x->sum_left = new_sum_left; + y->parent = x->parent; + if (x->parent == NULL) tree->root = y; + else if (x == x->parent->right) x->parent->right = y; + else x->parent->left = y; + y->right = x; + x->parent = y; +} + +void insertFixup(RBTree *tree, Node *z) { + while (z->parent != NULL && z->parent->color == RED) { + if (z->parent == z->parent->parent->left) { + Node *y = z->parent->parent->right; + if (y != NULL && y->color == RED) { + z->parent->color = BLACK; + y->color = BLACK; + z->parent->parent->color = RED; + z = z->parent->parent; + } else { + if (z == z->parent->right) { + z = z->parent; + leftRotate(tree, z); + } + z->parent->color = BLACK; + z->parent->parent->color = RED; + rightRotate(tree, z->parent->parent); + } + } else { + Node *y = z->parent->parent->left; + if (y != NULL && y->color == RED) { + z->parent->color = BLACK; + y->color = BLACK; + z->parent->parent->color = RED; + z = z->parent->parent; + } else { + if (z == z->parent->left) { + z = z->parent; + rightRotate(tree, z); + } + z->parent->color = BLACK; + z->parent->parent->color = RED; + leftRotate(tree, z->parent->parent); + } + } + } + tree->root->color = BLACK; +} + +void insert(RBTree *tree, NodeData* data) { + Node *z = createNode(data, RED, NULL, NULL, NULL); + Node *y = NULL; + Node *x = tree->root; + while (x != NULL) { + y = x; + + //if found a duplicated deadline, inserted the node + //at the end of the linklist + if (z->data->deadline == x->data->deadline) { + //find the tail the link list; + Node* tail = x; + while (tail->duplicated != NULL) { + tail = tail->duplicated; + } + //append the new node at the end of the list; + tail->duplicated = z; + z->color = x->color; + z->sum_left = x->sum_left; + return; + } + else if (z->data->deadline < x->data->deadline) { + x->sum_left += z->data->exe_time; + x = x->left; + } + else { + x = x->right; + } + } + + z->parent = y; + if (y == NULL) { + tree->root = z; + } + else if (z->data->deadline < y->data->deadline) { + y->left = z; + } + else { + y->right = z; + } + + insertFixup(tree, z); +} + +int getSumLessThan(Node* root, int deadline){ + if ( root == NULL ) { + return 0; + } + if ( deadline == root->data->deadline ) { + return root->sum_left; + } + else if ( deadline < root->data->deadline ) { + return getSumLessThan(root->left, deadline); + } + else { + return getTotalExeTimeOf( root ) + root->sum_left + getSumLessThan(root->right, deadline ); + } + +} + + +Node* search(RBTree *tree, NodeData* data) { + Node *current = tree->root; + while (current != NULL && current->data->deadline != data->deadline ) { + if (data->deadline < current->data->deadline) { + current = current->left; + } + else { + current = current->right; + } + } + + while (current && current->data->exe_time != data->exe_time) { + current = current->duplicated; + } + + return current; +} + +Node* searchByKey(RBTree* tree, NodeData* data) { + Node* current = tree->root; + while (current != NULL && current->data->deadline != data->deadline) { + if (data->deadline < current->data->deadline) { + current = current->left; + } + else { + current = current->right; + } + } + + return current; +} + +void transplant(RBTree *tree, Node *u, Node *v) { + if (u->parent == NULL) tree->root = v; + else if (u == u->parent->left) u->parent->left = v; + else u->parent->right = v; + if (v != NULL) v->parent = u->parent; +} + +Node* minimum(Node *node) { + while (node->left != NULL) { + node = node->left; + } + return node; +} + +void deleteFixup(RBTree *tree, Node *x) { + while (x != tree->root && (x == NULL || x->color == BLACK)) { + + if (x == NULL){ + break; + } + + if ( x == x->parent->left) { + Node *w = x->parent->right; + if (w->color == RED) { + w->color = BLACK; + x->parent->color = RED; + leftRotate(tree, x->parent); + w = x->parent->right; + } + if ((w->left == NULL || w->left->color == BLACK) && (w->right == NULL || w->right->color == BLACK)) { + w->color = RED; + x = x->parent; + } else { + if (w->right == NULL || w->right->color == BLACK) { + if (w->left != NULL) w->left->color = BLACK; + w->color = RED; + rightRotate(tree, w); + w = x->parent->right; + } + w->color = x->parent->color; + x->parent->color = BLACK; + if (w->right != NULL) w->right->color = BLACK; + leftRotate(tree, x->parent); + x = tree->root; + } + } else { + Node *w = x->parent->left; + if (w->color == RED) { + w->color = BLACK; + x->parent->color = RED; + rightRotate(tree, x->parent); + w = x->parent->left; + } + if ((w->right == NULL || w->right->color == BLACK) && (w->left == NULL || w->left->color == BLACK)) { + w->color = RED; + x = x->parent; + } else { + if (w->left == NULL || w->left->color == BLACK) { + if (w->right != NULL) w->right->color = BLACK; + w->color = RED; + leftRotate(tree, w); + w = x->parent->left; + } + w->color = x->parent->color; + x->parent->color = BLACK; + if (w->left != NULL) w->left->color = BLACK; + rightRotate(tree, x->parent); + x = tree->root; + } + } + } + if (x != NULL) x->color = BLACK; +} + +void removeNode(RBTree *tree, Node *z) { + Node *y = z; + Node *x = NULL; + Color y_original_color = y->color; + + if ( z->left != NULL && z->right != NULL ) { + y = minimum(z->right); + + int diff = getTotalExeTimeOf(y) - getTotalExeTimeOf(z); + Node* cur = z->right; + while (cur != y) { + cur->sum_left -= diff; + cur = cur->left; + } + + NodeData* remove_data = z->data; + z->data = y->data; + z->duplicated = y->duplicated; + y->data = remove_data; + y->duplicated = NULL; + + removeNode( tree, y ); + return; + } + + //now the node to be removed has only no children + //or only one child, update the sum_left value of + //all the node along the path from root to z. + Node* current = z; + Node* p = current->parent; + while (p != NULL) { + if (p->left == current) + { + p->sum_left -= z->data->exe_time; + } + current = p; + p = current->parent; + } + + if (z->left == NULL) { + x = z->right; + transplant(tree, z, z->right); + + } else if (z->right == NULL) { + x = z->left; + transplant(tree, z, z->left); + + } + + free(z); + if (y_original_color == BLACK) { + deleteFixup(tree, x); + } +} + +void deleteNode(RBTree *tree, NodeData* data) { + Node *z = searchByKey(tree, data); + if (z != NULL) { + //if there are duplicated nodes in Z, + //we just need to remove duplicated one. + if (z->duplicated != NULL) { + Node* cur = z; + Node* prev = NULL; + while (cur && cur->data->exe_time != data->exe_time) { + prev = cur; + cur = cur->duplicated; + } + + //if the target node has been found + if (cur != NULL) { + //update the sumLeft in all of its parent node. + Node* current = z; + Node* p = current->parent; + while (p != NULL) { + if (p->left == current) + { + p->sum_left -= data->exe_time; + } + current = p; + p = current->parent; + } + } + + //if the removed node is the head of the linkedlist; + if (cur == z) { + //copy the data from the removed node. + Node* newroot = z->duplicated; + newroot->color = z->color; + newroot->sum_left = z->sum_left; + newroot->left = z->left; + if (newroot->left != NULL) { + newroot->left->parent = newroot; + } + newroot->right = z->right; + if (newroot->right != NULL) { + newroot->right->parent = newroot; + } + + newroot->parent = z->parent; + + if (z->parent) { + if (z->parent->left = z) { + z->parent->left = newroot; + } + else { + z->parent->right = newroot; + } + } + //clean up the remove node z; + memset( z, 0, sizeof(Node)); + } + else { //remove the node from the link list; + prev->duplicated = cur->duplicated; + } + } + else{ + removeNode(tree, z); + } + } +} + +void inorder(Node *node) { + if (node != NULL) { + inorder(node->left); + printf("%d(%d) ", node->data->deadline, node->data->exe_time); + inorder(node->right); + } +} + +void destroyTree(Node *node) { + if (node != NULL) { + destroyTree(node->left); + destroyTree(node->right); + free(node); + + } +} + +// Helper function to print the tree +void printTree(Node* root, int space) { + if (root != NULL) { + space += 10; + printTree(root->right, space); + printf("\n"); + for (int i = 10; i < space; i++) + printf(" "); + printf("%d\n", root->data->deadline); + printTree(root->left, space); + } +} + + +int main() { + printf("============Test the program from ChatGPT===============\n"); + + RBTree *tree = createTree(); + const int size = 64; + int keys[size]; // = { 9, 8, 7, 6, 5, 4, 3, 2, 1 }; //{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + int vals[size]; //= { 9, 8, 7, 6, 5, 4, 3, 2, 1 }; //{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + for (int i = 1; i <= size; ++i) { + keys[i - 1] = i; + vals[i - 1] = i; + } + + NodeData* arr[size]; + + for ( int i = 0; i < size; ++i ) + { + arr[i] = createNodeData(keys[i], vals[i]); + insert( tree, arr[i] ); + } + + printTree( tree->root, 0 ); + + printf("===============================================" ); + for (int i = 0; i < size; i++) { + printf("Sum of values less than %d: %d\n", arr[i]->deadline, getSumLessThan(tree->root, arr[i]->deadline) ); + } + + printf("\n============insert the duplicated value: 8===============" ); + insert(tree, arr[7]); + + for (int i = 0; i < size; i++) { + printf("Sum of values less than %d: %d\n", arr[i]->deadline, getSumLessThan(tree->root, arr[i]->deadline)); + } + + printf("\n============insert the duplicated value: 10===============" ); + insert(tree, arr[9]); + + for (int i = 0; i < size; i++) { + printf("Sum of values less than %d: %d\n", arr[i]->deadline, getSumLessThan(tree->root, arr[i]->deadline)); + } + + printf("\n============remove the duplicated value: 8===============" ); + deleteNode(tree, arr[7]); + + for (int i = 0; i < size; i++) { + printf("Sum of values less than %d: %d\n", arr[i]->deadline, getSumLessThan(tree->root, arr[i]->deadline)); + } + + printf("\n============remove the duplicated value: 10===============" ); + deleteNode(tree, arr[9]); + + for (int i = 0; i < size; i++) { + printf("Sum of values less than %d: %d\n", arr[i]->deadline, getSumLessThan(tree->root, arr[i]->deadline)); + } + + printf("\n============remove the single value: 20===============" ); + deleteNode(tree, arr[19]); + + for (int i = 0; i < size; i++) { + printf("Sum of values less than %d: %d\n", arr[i]->deadline, getSumLessThan(tree->root, arr[i]->deadline)); + } + + printf("\n============insert the duplicated value: 41===============" ); + insert(tree, arr[40]); + + for (int i = 0; i < size; i++) { + printf("Sum of values less than %d: %d\n", arr[i]->deadline, getSumLessThan(tree->root, arr[i]->deadline)); + } + + printf("\n============remove the single value: 40===============" ); + deleteNode(tree, arr[39]); + + inorder(tree->root); + for (int i = 0; i < size; i++) { + printf("Sum of values less than %d: %d\n", arr[i]->deadline, getSumLessThan(tree->root, arr[i]->deadline)); + } + + + /*printf("============delete the value 8===============" ); + deleteNode(tree, arr[7]); + printTree( tree->root, 0 ); + + for (int i = 0; i < size; i++) { + printf("Sum of values less than %d: %d\n", arr[i]->deadline, getSumLessThan(tree->root, arr[i]->deadline) ); + } + + printf("============delete the root value 6===============" ); + deleteNode(tree, arr[5]); + printTree( tree->root, 0 ); + + for (int i = 0; i < size; i++) { + printf("Sum of values less than %d: %d\n", arr[i]->deadline, getSumLessThan(tree->root, arr[i]->deadline) ); + } + + printf("============delete the root value 32===============" ); + deleteNode(tree, arr[31]); + printTree(tree->root, 0); + + for (int i = 0; i < size; i++) { + printf("Sum of values less than %d: %d\n", arr[i]->deadline, getSumLessThan(tree->root, arr[i]->deadline)); + } + + + printf("============insert the root value 6===============" ); + insert(tree, arr[5]); + printTree( tree->root, 0 ); + + + printf("============insert the root value 8===============" ); + insert(tree, arr[7]); + printTree( tree->root, 0 ); + + + for (int i = 0; i < size; i++) { + printf("Sum of values less than %d: %d\n", arr[i]->deadline, getSumLessThan(tree->root, arr[i]->deadline) ); + }*/ + + destroyTree(tree->root); + free(tree); + + return 0; +} + + +// Run program: Ctrl + F5 or Debug > Start Without Debugging menu +// Debug program: F5 or Debug > Start Debugging menu + +// Tips for Getting Started: +// 1. Use the Solution Explorer window to add/manage files +// 2. Use the Team Explorer window to connect to source control +// 3. Use the Output window to see build output and other messages +// 4. Use the Error List window to view errors +// 5. Go to Project > Add New Item to create new code files, or Project > Add Existing Item to add existing code files to the project +// 6. In the future, to open this project again, go to File > Open > Project and select the .sln file From 8c0e87b6aae25f5dc5df4a98f66399776551761a Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 5 Jun 2024 16:32:19 -0600 Subject: [PATCH 133/198] use remaining execution time instead of estimated execution time to calculate the total waiting time for a new request inserted to a local queueu, this only works for EDF_INTERRUPT scheduling algorithm --- runtime/include/sandbox_functions.h | 38 ++++++++++++++++++++++++++-- runtime/tests/hash.json | 2 +- runtime/tests/hash_darc.json | 33 ++++++++++++++++++++++++ runtime/tests/hash_high_bimodal.json | 2 +- 4 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 runtime/tests/hash_darc.json diff --git a/runtime/include/sandbox_functions.h b/runtime/include/sandbox_functions.h index 808ee38c3..f2010cbb8 100644 --- a/runtime/include/sandbox_functions.h +++ b/runtime/include/sandbox_functions.h @@ -12,6 +12,7 @@ * Public API * **************************/ +extern struct sandbox* current_sandboxes[1024]; extern bool runtime_exponential_service_time_simulation_enabled; extern struct perf_window * worker_perf_windows[1024]; struct sandbox *sandbox_alloc(struct module *module, struct http_session *session, struct route *route, @@ -63,13 +64,46 @@ sandbox_get_execution_cost(void *element, int thread_id) struct sandbox *sandbox = (struct sandbox *)element; if (runtime_exponential_service_time_simulation_enabled) { assert(sandbox->estimated_cost != 0); - return sandbox->estimated_cost; + if (sandbox == current_sandboxes[thread_id]) { + /* This sandbox is running, get the running lasting time until now and + calculate the remaining execution time + */ + uint64_t run_cycles = __getcycles() - sandbox->timestamp_of.last_state_change; + return sandbox->estimated_cost > (sandbox->duration_of_state[SANDBOX_RUNNING_SYS] + + sandbox->duration_of_state[SANDBOX_RUNNING_USER] + run_cycles) ? + sandbox->estimated_cost - + sandbox->duration_of_state[SANDBOX_RUNNING_SYS] - + sandbox->duration_of_state[SANDBOX_RUNNING_USER] - run_cycles : 0; + } else { + + return sandbox->estimated_cost > (sandbox->duration_of_state[SANDBOX_RUNNING_SYS] + + sandbox->duration_of_state[SANDBOX_RUNNING_USER]) ? + sandbox->estimated_cost - + sandbox->duration_of_state[SANDBOX_RUNNING_SYS] - + sandbox->duration_of_state[SANDBOX_RUNNING_USER] : 0; + } } else { uint32_t uid = sandbox->route->admissions_info.uid; - return perf_window_get_percentile(&worker_perf_windows[thread_id][uid], + uint64_t estimated_cost = perf_window_get_percentile(&worker_perf_windows[thread_id][uid], sandbox->route->admissions_info.percentile, sandbox->route->admissions_info.control_index); + if (sandbox == current_sandboxes[thread_id]) { + uint64_t run_cycles = __getcycles() - sandbox->timestamp_of.last_state_change; + return estimated_cost > (sandbox->duration_of_state[SANDBOX_RUNNING_SYS] + + sandbox->duration_of_state[SANDBOX_RUNNING_USER] + run_cycles) ? + estimated_cost - + sandbox->duration_of_state[SANDBOX_RUNNING_SYS] - + sandbox->duration_of_state[SANDBOX_RUNNING_USER] - run_cycles : 0; + + } else { + return estimated_cost > (sandbox->duration_of_state[SANDBOX_RUNNING_SYS] + + sandbox->duration_of_state[SANDBOX_RUNNING_USER]) ? + estimated_cost - + sandbox->duration_of_state[SANDBOX_RUNNING_SYS] - + sandbox->duration_of_state[SANDBOX_RUNNING_USER] : 0; + } + } } diff --git a/runtime/tests/hash.json b/runtime/tests/hash.json index 396b8f926..f273d745b 100644 --- a/runtime/tests/hash.json +++ b/runtime/tests/hash.json @@ -8,7 +8,7 @@ { "route": "/hash", "request-type": 1, - "n-resas": 5, + "n-resas": 6, "path": "hash.wasm.so", "admissions-percentile": 70, "expected-execution-us": 5, diff --git a/runtime/tests/hash_darc.json b/runtime/tests/hash_darc.json new file mode 100644 index 000000000..e6faad624 --- /dev/null +++ b/runtime/tests/hash_darc.json @@ -0,0 +1,33 @@ +[ + { + "name": "gwu", + "port": 31850, + "replenishment-period-us": 0, + "max-budget-us": 0, + "routes": [ + { + "route": "/hash1", + "request-type": 1, + "n-resas": 3, + "path": "hash.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 5, + "relative-deadline-us": 50, + "http-resp-content-type": "text/plain" + }, + { + "route": "/hash2", + "request-type": 2, + "n-resas": 3, + "path": "hash.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 5, + "relative-deadline-us": 50, + "http-resp-content-type": "text/plain" + } + ] + + } + +] + diff --git a/runtime/tests/hash_high_bimodal.json b/runtime/tests/hash_high_bimodal.json index 448c14efc..f7382c25a 100644 --- a/runtime/tests/hash_high_bimodal.json +++ b/runtime/tests/hash_high_bimodal.json @@ -18,7 +18,7 @@ { "route": "/hash2", "request-type": 2, - "n-resas": 4, + "n-resas": 5, "path": "hash.wasm.so", "admissions-percentile": 70, "expected-execution-us": 5, From e70adf06166b58f4f1b90e97932aafbfc488da0b Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Mon, 10 Jun 2024 00:36:33 -0600 Subject: [PATCH 134/198] update runtime/src/software_interrupt.c to wakeup_worker and sem_post only when runtime_worker_busy_loop_enabled is false --- runtime/src/software_interrupt.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index f097e94fc..58be8f9dc 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -285,9 +285,13 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void local_runqueue_count[global_worker_thread_idx], local_runqueue_get_length(), total_complete_requests); pthread_stop = true; - /* Wake up worker so it can check if pthread_stop is true, othewise, it will block at condition wait */ - wakeup_worker(global_worker_thread_idx); - sem_post(&semlock[global_worker_thread_idx]); + if (!runtime_worker_busy_loop_enabled) { + /* Wake up worker so it can check if pthread_stop is true, othewise, it will block at condition wait */ + wakeup_worker(global_worker_thread_idx); + sem_post(&semlock[global_worker_thread_idx]); + } + /* Use pthread_exit in case some function code is an infinite loop and cannot finish forever */ + //pthread_exit(NULL); break; } default: { From 21595abf1f0fe3106ac8fa41b85b9b769d4fad8c Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Mon, 17 Jun 2024 14:49:31 -0600 Subject: [PATCH 135/198] update curl.sh and measure_old_sledge_cost.sh of folder ori_sledge_tests --- runtime/tests/ori_sledge_tests/curl.sh | 1 + runtime/tests/ori_sledge_tests/measure_old_sledge_cost.sh | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/runtime/tests/ori_sledge_tests/curl.sh b/runtime/tests/ori_sledge_tests/curl.sh index 5ea14ad74..be0c86293 100755 --- a/runtime/tests/ori_sledge_tests/curl.sh +++ b/runtime/tests/ori_sledge_tests/curl.sh @@ -1,2 +1,3 @@ #curl -I -w "Total time: %{time_total}s\n" http://10.10.1.1:31850/empty curl -w "Total time: %{time_total}s\n" http://10.10.1.1:31850/empty http://10.10.1.1:31850/empty http://10.10.1.1:31850/empty http://10.10.1.1:31850/empty +#curl -w "Total time: %{time_total}s\n" http://10.10.1.1:31850/empty http://10.10.1.1:31850/empty diff --git a/runtime/tests/ori_sledge_tests/measure_old_sledge_cost.sh b/runtime/tests/ori_sledge_tests/measure_old_sledge_cost.sh index e04023869..a59c9e024 100755 --- a/runtime/tests/ori_sledge_tests/measure_old_sledge_cost.sh +++ b/runtime/tests/ori_sledge_tests/measure_old_sledge_cost.sh @@ -15,13 +15,14 @@ remote_ip="10.10.1.1" repeat_count=$1 > old_sledge.log -path="/my_mount/ori_sledge/sledge-serverless-framework/runtime/tests" +path="/my_mount/old_sledge/sledge-serverless-framework/runtime/tests" for(( i=0;i<$repeat_count;i++ )) do echo "i is $i" echo "start server..." ssh -o stricthostkeychecking=no -i ./id_rsa xiaosuGW@$remote_ip "sudo $path/start.sh > 1.txt 2>&1 &" sleep 1 echo "start client..." - ./curl.sh >> old_sledge.log + #./curl.sh >> old_sledge.log + ./curl.sh ssh -o stricthostkeychecking=no -i ./id_rsa xiaosuGW@$remote_ip "sudo $path/kill_sledge.sh" done From cd88451432e5c711aaa22cc3417e16abe3377ad0 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 28 Jun 2024 15:00:20 -0600 Subject: [PATCH 136/198] update curl.sh measure_old_sledge_cost.sh and parse_cost.py --- runtime/tests/ori_sledge_tests/curl.sh | 7 +++++-- .../ori_sledge_tests/measure_old_sledge_cost.sh | 10 +++++----- runtime/tests/ori_sledge_tests/parse_cost.py | 15 +++++++++++---- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/runtime/tests/ori_sledge_tests/curl.sh b/runtime/tests/ori_sledge_tests/curl.sh index be0c86293..3fde506f9 100755 --- a/runtime/tests/ori_sledge_tests/curl.sh +++ b/runtime/tests/ori_sledge_tests/curl.sh @@ -1,3 +1,6 @@ #curl -I -w "Total time: %{time_total}s\n" http://10.10.1.1:31850/empty -curl -w "Total time: %{time_total}s\n" http://10.10.1.1:31850/empty http://10.10.1.1:31850/empty http://10.10.1.1:31850/empty http://10.10.1.1:31850/empty -#curl -w "Total time: %{time_total}s\n" http://10.10.1.1:31850/empty http://10.10.1.1:31850/empty +#curl -w "Total time: %{time_total}s\n" http://10.10.1.1:31850/empty http://10.10.1.1:31850/empty http://10.10.1.1:31850/empty http://10.10.1.1:31850/empty +curl -w "Total time: %{time_total}s TCP Connect time: %{time_connect}s\n" -o /dev/null -s http://10.10.1.1:31850/empty http://10.10.1.1:31850/empty + + +#curl -H 'Expect:' -H "Content-Type: image/bmp" --data-binary "@frog5.bmp" "10.10.1.1:31850/classify" diff --git a/runtime/tests/ori_sledge_tests/measure_old_sledge_cost.sh b/runtime/tests/ori_sledge_tests/measure_old_sledge_cost.sh index a59c9e024..d84a3ac2a 100755 --- a/runtime/tests/ori_sledge_tests/measure_old_sledge_cost.sh +++ b/runtime/tests/ori_sledge_tests/measure_old_sledge_cost.sh @@ -15,14 +15,14 @@ remote_ip="10.10.1.1" repeat_count=$1 > old_sledge.log -path="/my_mount/old_sledge/sledge-serverless-framework/runtime/tests" +path="/my_mount/ori_sledge/sledge-serverless-framework/runtime/tests" for(( i=0;i<$repeat_count;i++ )) do - echo "i is $i" - echo "start server..." + #echo "i is $i" + #echo "start server..." ssh -o stricthostkeychecking=no -i ./id_rsa xiaosuGW@$remote_ip "sudo $path/start.sh > 1.txt 2>&1 &" sleep 1 - echo "start client..." + #echo "start client..." #./curl.sh >> old_sledge.log ./curl.sh - ssh -o stricthostkeychecking=no -i ./id_rsa xiaosuGW@$remote_ip "sudo $path/kill_sledge.sh" + ssh -o stricthostkeychecking=no -i ./id_rsa xiaosuGW@$remote_ip "sudo $path/kill_sledge.sh" > /dev/null 2>&1 done diff --git a/runtime/tests/ori_sledge_tests/parse_cost.py b/runtime/tests/ori_sledge_tests/parse_cost.py index 976e4c07f..179699ee9 100644 --- a/runtime/tests/ori_sledge_tests/parse_cost.py +++ b/runtime/tests/ori_sledge_tests/parse_cost.py @@ -14,22 +14,29 @@ sys.exit(1) total_cold_time = 0 +total_tcp_conn = 0 total_warm_time = 0 count = 0 -for i in range(0, len(lines), 4): - time_str_1 = lines[i].split(": ")[1].strip() - time_str_2 = lines[i+3].split(": ")[1].strip() +for i in range(0, len(lines), 2): + time_str_1 = lines[i].split(" ")[2].strip() + tcp_cost_str = lines[i].split(" ")[6].strip() + time_str_2 = lines[i+1].split(" ")[2].strip() time_value_1 = float(time_str_1[:-1]) time_value_2 = float(time_str_2[:-1]) + tcp_cost = float(tcp_cost_str[:-1]) + print("cold:", time_value_1, " warm:", time_value_2) total_cold_time += time_value_1 - total_warm_time += time_value_2 + total_warm_time += time_value_2 + total_tcp_conn += tcp_cost count += 1 average_cold_time = total_cold_time / count average_warm_time = total_warm_time / count +average_tcp_conn = total_tcp_conn / count print("Average cold time:", average_cold_time, "s") print("Average warm time:", average_warm_time, "s") +print("Average tcp conn:", average_tcp_conn, "s") From 6123731108cba67dd2b87b78515ef3173df00908 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 3 Jul 2024 16:47:38 -0600 Subject: [PATCH 137/198] upload high_bimodal_realapps.json --- runtime/tests/high_bimodal_realapps.json | 33 ++++++++++++++++++++++++ runtime/tests/start.sh | 4 +-- 2 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 runtime/tests/high_bimodal_realapps.json diff --git a/runtime/tests/high_bimodal_realapps.json b/runtime/tests/high_bimodal_realapps.json new file mode 100644 index 000000000..ed777438c --- /dev/null +++ b/runtime/tests/high_bimodal_realapps.json @@ -0,0 +1,33 @@ +[ + { + "name": "gwu", + "port": 31850, + "replenishment-period-us": 0, + "max-budget-us": 0, + "routes": [ + { + "route": "/resize", + "request-type": 1, + "n-resas": 1, + "path": "resize_image.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 25, + "relative-deadline-us": 250, + "http-resp-content-type": "text/plain" + }, + { + "route": "/classifier", + "request-type": 2, + "n-resas": 5, + "path": "cifar10.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 2070, + "relative-deadline-us": 20700, + "http-resp-content-type": "text/plain" + } + ] + + } + +] + diff --git a/runtime/tests/start.sh b/runtime/tests/start.sh index 968a8a442..2d4687cda 100755 --- a/runtime/tests/start.sh +++ b/runtime/tests/start.sh @@ -45,9 +45,9 @@ cd $project_path/runtime/bin #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/mulitple_linear_chain.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing3.json -LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/fib.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/fib.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/hash.json -#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/empty.json +LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/empty.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/my_fibonacci.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_sodresize.json #LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/my_sodresize.json From c7fc8b238d05f5e91e9fde7b3c657818a0e8b4f1 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 16 Jul 2024 23:36:20 -0600 Subject: [PATCH 138/198] update tests/high_bimodal_realapps.json --- runtime/tests/high_bimodal_realapps.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/tests/high_bimodal_realapps.json b/runtime/tests/high_bimodal_realapps.json index ed777438c..f55881cfc 100644 --- a/runtime/tests/high_bimodal_realapps.json +++ b/runtime/tests/high_bimodal_realapps.json @@ -11,8 +11,8 @@ "n-resas": 1, "path": "resize_image.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 25, - "relative-deadline-us": 250, + "expected-execution-us": 26, + "relative-deadline-us": 260, "http-resp-content-type": "text/plain" }, { From ea6f45135395c2c4b15427955dc159f7884e596e Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 16 Jul 2024 23:47:06 -0600 Subject: [PATCH 139/198] update scripts --- runtime/tests/ori_sledge_tests/curl.sh | 4 +- runtime/tests/ori_sledge_tests/parse_cost.py | 7 +- .../ori_sledge_tests/two_curl_requests.log | 200 ++++++++++++++++++ 3 files changed, 208 insertions(+), 3 deletions(-) create mode 100644 runtime/tests/ori_sledge_tests/two_curl_requests.log diff --git a/runtime/tests/ori_sledge_tests/curl.sh b/runtime/tests/ori_sledge_tests/curl.sh index 3fde506f9..70a2cc6d2 100755 --- a/runtime/tests/ori_sledge_tests/curl.sh +++ b/runtime/tests/ori_sledge_tests/curl.sh @@ -1,6 +1,6 @@ #curl -I -w "Total time: %{time_total}s\n" http://10.10.1.1:31850/empty #curl -w "Total time: %{time_total}s\n" http://10.10.1.1:31850/empty http://10.10.1.1:31850/empty http://10.10.1.1:31850/empty http://10.10.1.1:31850/empty -curl -w "Total time: %{time_total}s TCP Connect time: %{time_connect}s\n" -o /dev/null -s http://10.10.1.1:31850/empty http://10.10.1.1:31850/empty +#curl -I -H "Connection: keep-alive" -w "Total time: %{time_total}s TCP Connect time: %{time_connect}s\n" -o /dev/null -s http://10.10.1.1:31850/empty http://10.10.1.1:31850/empty -#curl -H 'Expect:' -H "Content-Type: image/bmp" --data-binary "@frog5.bmp" "10.10.1.1:31850/classify" +curl -H 'Expect:' -H "Content-Type: image/bmp" --data-binary "@frog5.bmp" "10.10.1.1:31850/classify" diff --git a/runtime/tests/ori_sledge_tests/parse_cost.py b/runtime/tests/ori_sledge_tests/parse_cost.py index 179699ee9..17e3b3b30 100644 --- a/runtime/tests/ori_sledge_tests/parse_cost.py +++ b/runtime/tests/ori_sledge_tests/parse_cost.py @@ -15,6 +15,7 @@ total_cold_time = 0 total_tcp_conn = 0 +total_tcp_conn2 = 0 total_warm_time = 0 count = 0 @@ -22,21 +23,25 @@ time_str_1 = lines[i].split(" ")[2].strip() tcp_cost_str = lines[i].split(" ")[6].strip() time_str_2 = lines[i+1].split(" ")[2].strip() + tcp_cost_str2 = lines[i+1].split(" ")[6].strip() time_value_1 = float(time_str_1[:-1]) time_value_2 = float(time_str_2[:-1]) tcp_cost = float(tcp_cost_str[:-1]) + tcp_cost2 = float(tcp_cost_str2[:-1]) print("cold:", time_value_1, " warm:", time_value_2) total_cold_time += time_value_1 total_warm_time += time_value_2 total_tcp_conn += tcp_cost + total_tcp_conn2 += tcp_cost2 count += 1 average_cold_time = total_cold_time / count average_warm_time = total_warm_time / count average_tcp_conn = total_tcp_conn / count +average_tcp_conn2 = total_tcp_conn2 / count print("Average cold time:", average_cold_time, "s") print("Average warm time:", average_warm_time, "s") print("Average tcp conn:", average_tcp_conn, "s") - +print("Average tcp conn2:", average_tcp_conn2, "s") diff --git a/runtime/tests/ori_sledge_tests/two_curl_requests.log b/runtime/tests/ori_sledge_tests/two_curl_requests.log new file mode 100644 index 000000000..fdcbc0fb3 --- /dev/null +++ b/runtime/tests/ori_sledge_tests/two_curl_requests.log @@ -0,0 +1,200 @@ +Total time: 0.000256s TCP Connect time: 0.000119s +Total time: 0.000155s TCP Connect time: 0.000077s +Total time: 0.000231s TCP Connect time: 0.000100s +Total time: 0.000141s TCP Connect time: 0.000078s +Total time: 0.000275s TCP Connect time: 0.000126s +Total time: 0.000158s TCP Connect time: 0.000080s +Total time: 0.000265s TCP Connect time: 0.000121s +Total time: 0.000228s TCP Connect time: 0.000126s +Total time: 0.000216s TCP Connect time: 0.000091s +Total time: 0.000170s TCP Connect time: 0.000097s +Total time: 0.000214s TCP Connect time: 0.000088s +Total time: 0.000204s TCP Connect time: 0.000112s +Total time: 0.000337s TCP Connect time: 0.000111s +Total time: 0.000174s TCP Connect time: 0.000095s +Total time: 0.000251s TCP Connect time: 0.000115s +Total time: 0.000180s TCP Connect time: 0.000096s +Total time: 0.000210s TCP Connect time: 0.000084s +Total time: 0.000159s TCP Connect time: 0.000091s +Total time: 0.000243s TCP Connect time: 0.000111s +Total time: 0.000154s TCP Connect time: 0.000083s +Total time: 0.000248s TCP Connect time: 0.000100s +Total time: 0.000149s TCP Connect time: 0.000081s +Total time: 0.000237s TCP Connect time: 0.000106s +Total time: 0.000165s TCP Connect time: 0.000084s +Total time: 0.000232s TCP Connect time: 0.000101s +Total time: 0.000167s TCP Connect time: 0.000090s +Total time: 0.000264s TCP Connect time: 0.000114s +Total time: 0.000174s TCP Connect time: 0.000090s +Total time: 0.000222s TCP Connect time: 0.000090s +Total time: 0.000153s TCP Connect time: 0.000076s +Total time: 0.000235s TCP Connect time: 0.000103s +Total time: 0.000168s TCP Connect time: 0.000098s +Total time: 0.000223s TCP Connect time: 0.000100s +Total time: 0.000136s TCP Connect time: 0.000071s +Total time: 0.000226s TCP Connect time: 0.000103s +Total time: 0.000177s TCP Connect time: 0.000095s +Total time: 0.000254s TCP Connect time: 0.000101s +Total time: 0.000167s TCP Connect time: 0.000099s +Total time: 0.000255s TCP Connect time: 0.000108s +Total time: 0.000142s TCP Connect time: 0.000074s +Total time: 0.000223s TCP Connect time: 0.000101s +Total time: 0.000154s TCP Connect time: 0.000076s +Total time: 0.000264s TCP Connect time: 0.000108s +Total time: 0.000150s TCP Connect time: 0.000085s +Total time: 0.000243s TCP Connect time: 0.000107s +Total time: 0.000135s TCP Connect time: 0.000071s +Total time: 0.000237s TCP Connect time: 0.000096s +Total time: 0.000201s TCP Connect time: 0.000093s +Total time: 0.000229s TCP Connect time: 0.000093s +Total time: 0.000167s TCP Connect time: 0.000088s +Total time: 0.000223s TCP Connect time: 0.000090s +Total time: 0.000187s TCP Connect time: 0.000098s +Total time: 0.000222s TCP Connect time: 0.000107s +Total time: 0.000148s TCP Connect time: 0.000073s +Total time: 0.000228s TCP Connect time: 0.000100s +Total time: 0.000173s TCP Connect time: 0.000075s +Total time: 0.000235s TCP Connect time: 0.000100s +Total time: 0.000147s TCP Connect time: 0.000080s +Total time: 0.000258s TCP Connect time: 0.000104s +Total time: 0.000213s TCP Connect time: 0.000121s +Total time: 0.000210s TCP Connect time: 0.000093s +Total time: 0.000174s TCP Connect time: 0.000100s +Total time: 0.000229s TCP Connect time: 0.000100s +Total time: 0.000167s TCP Connect time: 0.000074s +Total time: 0.000218s TCP Connect time: 0.000088s +Total time: 0.000155s TCP Connect time: 0.000077s +Total time: 0.000248s TCP Connect time: 0.000099s +Total time: 0.000141s TCP Connect time: 0.000075s +Total time: 0.000210s TCP Connect time: 0.000089s +Total time: 0.000150s TCP Connect time: 0.000069s +Total time: 0.000246s TCP Connect time: 0.000115s +Total time: 0.000144s TCP Connect time: 0.000079s +Total time: 0.000239s TCP Connect time: 0.000102s +Total time: 0.000174s TCP Connect time: 0.000091s +Total time: 0.000260s TCP Connect time: 0.000101s +Total time: 0.000197s TCP Connect time: 0.000118s +Total time: 0.000232s TCP Connect time: 0.000093s +Total time: 0.000143s TCP Connect time: 0.000078s +Total time: 0.000249s TCP Connect time: 0.000094s +Total time: 0.000139s TCP Connect time: 0.000072s +Total time: 0.000252s TCP Connect time: 0.000114s +Total time: 0.000164s TCP Connect time: 0.000088s +Total time: 0.000214s TCP Connect time: 0.000091s +Total time: 0.000146s TCP Connect time: 0.000079s +Total time: 0.000230s TCP Connect time: 0.000089s +Total time: 0.000147s TCP Connect time: 0.000076s +Total time: 0.000238s TCP Connect time: 0.000108s +Total time: 0.000148s TCP Connect time: 0.000080s +Total time: 0.000269s TCP Connect time: 0.000097s +Total time: 0.000167s TCP Connect time: 0.000088s +Total time: 0.000257s TCP Connect time: 0.000123s +Total time: 0.000221s TCP Connect time: 0.000070s +Total time: 0.000246s TCP Connect time: 0.000098s +Total time: 0.000150s TCP Connect time: 0.000073s +Total time: 0.000244s TCP Connect time: 0.000108s +Total time: 0.000161s TCP Connect time: 0.000082s +Total time: 0.000225s TCP Connect time: 0.000103s +Total time: 0.000158s TCP Connect time: 0.000079s +Total time: 0.000241s TCP Connect time: 0.000099s +Total time: 0.000153s TCP Connect time: 0.000081s +Total time: 0.000229s TCP Connect time: 0.000096s +Total time: 0.000184s TCP Connect time: 0.000110s +Total time: 0.000230s TCP Connect time: 0.000103s +Total time: 0.000150s TCP Connect time: 0.000075s +Total time: 0.000210s TCP Connect time: 0.000103s +Total time: 0.000152s TCP Connect time: 0.000065s +Total time: 0.000257s TCP Connect time: 0.000123s +Total time: 0.000143s TCP Connect time: 0.000075s +Total time: 0.000218s TCP Connect time: 0.000088s +Total time: 0.000155s TCP Connect time: 0.000079s +Total time: 0.000257s TCP Connect time: 0.000117s +Total time: 0.000188s TCP Connect time: 0.000111s +Total time: 0.000240s TCP Connect time: 0.000102s +Total time: 0.000150s TCP Connect time: 0.000080s +Total time: 0.000237s TCP Connect time: 0.000104s +Total time: 0.000157s TCP Connect time: 0.000075s +Total time: 0.000268s TCP Connect time: 0.000132s +Total time: 0.000135s TCP Connect time: 0.000079s +Total time: 0.000228s TCP Connect time: 0.000095s +Total time: 0.000151s TCP Connect time: 0.000081s +Total time: 0.000226s TCP Connect time: 0.000103s +Total time: 0.000139s TCP Connect time: 0.000075s +Total time: 0.000235s TCP Connect time: 0.000105s +Total time: 0.000175s TCP Connect time: 0.000104s +Total time: 0.000224s TCP Connect time: 0.000103s +Total time: 0.000160s TCP Connect time: 0.000090s +Total time: 0.000217s TCP Connect time: 0.000095s +Total time: 0.000167s TCP Connect time: 0.000094s +Total time: 0.000246s TCP Connect time: 0.000109s +Total time: 0.000159s TCP Connect time: 0.000081s +Total time: 0.000300s TCP Connect time: 0.000141s +Total time: 0.000151s TCP Connect time: 0.000073s +Total time: 0.000268s TCP Connect time: 0.000105s +Total time: 0.000146s TCP Connect time: 0.000084s +Total time: 0.000240s TCP Connect time: 0.000100s +Total time: 0.000131s TCP Connect time: 0.000067s +Total time: 0.000231s TCP Connect time: 0.000108s +Total time: 0.000159s TCP Connect time: 0.000092s +Total time: 0.000233s TCP Connect time: 0.000109s +Total time: 0.000146s TCP Connect time: 0.000078s +Total time: 0.000247s TCP Connect time: 0.000111s +Total time: 0.000144s TCP Connect time: 0.000076s +Total time: 0.000224s TCP Connect time: 0.000092s +Total time: 0.000197s TCP Connect time: 0.000105s +Total time: 0.000240s TCP Connect time: 0.000102s +Total time: 0.000161s TCP Connect time: 0.000078s +Total time: 0.000245s TCP Connect time: 0.000106s +Total time: 0.000163s TCP Connect time: 0.000093s +Total time: 0.000298s TCP Connect time: 0.000121s +Total time: 0.000170s TCP Connect time: 0.000097s +Total time: 0.000227s TCP Connect time: 0.000102s +Total time: 0.000188s TCP Connect time: 0.000080s +Total time: 0.000245s TCP Connect time: 0.000103s +Total time: 0.000164s TCP Connect time: 0.000085s +Total time: 0.000219s TCP Connect time: 0.000101s +Total time: 0.000163s TCP Connect time: 0.000090s +Total time: 0.000251s TCP Connect time: 0.000111s +Total time: 0.000204s TCP Connect time: 0.000124s +Total time: 0.000246s TCP Connect time: 0.000111s +Total time: 0.000165s TCP Connect time: 0.000084s +Total time: 0.000230s TCP Connect time: 0.000092s +Total time: 0.000167s TCP Connect time: 0.000089s +Total time: 0.000241s TCP Connect time: 0.000090s +Total time: 0.000164s TCP Connect time: 0.000096s +Total time: 0.000234s TCP Connect time: 0.000100s +Total time: 0.000150s TCP Connect time: 0.000081s +Total time: 0.000233s TCP Connect time: 0.000085s +Total time: 0.000135s TCP Connect time: 0.000069s +Total time: 0.000242s TCP Connect time: 0.000109s +Total time: 0.000222s TCP Connect time: 0.000091s +Total time: 0.000280s TCP Connect time: 0.000112s +Total time: 0.000181s TCP Connect time: 0.000099s +Total time: 0.000241s TCP Connect time: 0.000110s +Total time: 0.000133s TCP Connect time: 0.000069s +Total time: 0.000235s TCP Connect time: 0.000105s +Total time: 0.000164s TCP Connect time: 0.000092s +Total time: 0.000250s TCP Connect time: 0.000111s +Total time: 0.000159s TCP Connect time: 0.000088s +Total time: 0.000309s TCP Connect time: 0.000124s +Total time: 0.000181s TCP Connect time: 0.000100s +Total time: 0.000224s TCP Connect time: 0.000092s +Total time: 0.000144s TCP Connect time: 0.000075s +Total time: 0.000243s TCP Connect time: 0.000100s +Total time: 0.000154s TCP Connect time: 0.000076s +Total time: 0.000225s TCP Connect time: 0.000091s +Total time: 0.000171s TCP Connect time: 0.000089s +Total time: 0.000224s TCP Connect time: 0.000092s +Total time: 0.000160s TCP Connect time: 0.000080s +Total time: 0.000238s TCP Connect time: 0.000106s +Total time: 0.000153s TCP Connect time: 0.000083s +Total time: 0.000243s TCP Connect time: 0.000111s +Total time: 0.000182s TCP Connect time: 0.000109s +Total time: 0.000221s TCP Connect time: 0.000096s +Total time: 0.000186s TCP Connect time: 0.000111s +Total time: 0.000231s TCP Connect time: 0.000101s +Total time: 0.000138s TCP Connect time: 0.000074s +Total time: 0.000223s TCP Connect time: 0.000106s +Total time: 0.000162s TCP Connect time: 0.000093s +Total time: 0.000217s TCP Connect time: 0.000086s +Total time: 0.000150s TCP Connect time: 0.000080s From a82a971d4c7910fe79a318d4f7d21bdc4d4dfc24 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 4 Oct 2024 16:08:37 -0600 Subject: [PATCH 140/198] upload monitor_mem.sh kill_perf.sh run_perf.sh --- runtime/tests/kill_perf.sh | 9 +++++++ runtime/tests/monitor_mem.sh | 47 ++++++++++++++++++++++++++++++++++++ runtime/tests/run_perf.sh | 20 +++++++++++++++ 3 files changed, 76 insertions(+) create mode 100755 runtime/tests/kill_perf.sh create mode 100755 runtime/tests/monitor_mem.sh create mode 100755 runtime/tests/run_perf.sh diff --git a/runtime/tests/kill_perf.sh b/runtime/tests/kill_perf.sh new file mode 100755 index 000000000..6af2b12df --- /dev/null +++ b/runtime/tests/kill_perf.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +pid=`ps -ef | grep "perf" | grep -v grep | awk 'NR==1 {print $2}'` +sudo kill -SIGINT $pid +sleep 2 + +pid=`ps -ef|grep "perf" |grep -v grep |awk '{print $2}'` +echo $pid +sudo kill -9 $pid diff --git a/runtime/tests/monitor_mem.sh b/runtime/tests/monitor_mem.sh new file mode 100755 index 000000000..74092809c --- /dev/null +++ b/runtime/tests/monitor_mem.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +function usage { + echo "$0 [output file]" + exit 1 +} + +if [ $# != 1 ] ; then + usage + exit 1; +fi + +output=$1 + +pid=`ps -ef|grep "sledgert"|grep -v grep |awk '{print $2}'` + +if [ -z "$pid" ]; then + echo "No process found. Exiting." + exit 1 +fi + +interval=1 # 采样间隔时间,单位为秒 +samples=20 # 采样次数 + +total_rss=0 +count=0 + +while [ $count -lt $samples ]; do + # 使用ps命令获取RSS (单位为KB) + rss=$(ps -o rss= -p $pid) + + if [ -n "$rss" ]; then + total_rss=$((total_rss + rss)) + count=$((count + 1)) + else + echo "process $pid not exists or exits" + exit 1 + fi + + sleep $interval # 采样间隔 +done + +# 计算平均RSS +average_rss=$((total_rss / samples)) + +echo "avg RSS (KB): $average_rss" > $output + diff --git a/runtime/tests/run_perf.sh b/runtime/tests/run_perf.sh new file mode 100755 index 000000000..6378983cb --- /dev/null +++ b/runtime/tests/run_perf.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +function usage { + echo "$0 [output]" + exit 1 +} + +if [ $# != 1 ] ; then + usage + exit 1; +fi + +pid=`ps -ef|grep "sledgert"|grep -v grep |awk '{print $2}'` +output=$1 + +cpu=$(lscpu | awk '/^Core\(s\) per socket:/ {cores=$4} /^Socket\(s\):/ {sockets=$2} END {print cores * sockets}') +last_core=$((cpu - 1)) #get the last core + +taskset -c $last_core sudo perf stat -B -e context-switches,cache-references,cache-misses,cycles,instructions,page-faults -p $pid -o $output 2>&1 & + From 367cc15c7ce660d9b17ee466faa14405d48c073d Mon Sep 17 00:00:00 2001 From: xiaosuGW Date: Fri, 11 Oct 2024 00:40:37 -0600 Subject: [PATCH 141/198] upload parse_batch_profile.py --- runtime/tests/parse_batch_profile.py | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 runtime/tests/parse_batch_profile.py diff --git a/runtime/tests/parse_batch_profile.py b/runtime/tests/parse_batch_profile.py new file mode 100644 index 000000000..8d76e77cd --- /dev/null +++ b/runtime/tests/parse_batch_profile.py @@ -0,0 +1,128 @@ +import re +import os +import sys +from collections import defaultdict + +mem_dict = defaultdict(list) +funs_dict = defaultdict(list) + +cache_miss_dict = defaultdict(list) +pagefault_dict = defaultdict(list) + +seperate_sending_rate_dict = defaultdict(lambda: defaultdict(list)) +seperate_service_rate_dict = defaultdict(lambda: defaultdict(list)) + +def parse_file(file_path): + #key is request type, value is latency + fo = open(file_path, "r+") + deadline_miss_count = 0 + for line in fo: + line = line.strip() + #latency log line + if "avg RSS" in line: + mem = line.split(":")[1].strip() + mem = int(mem) + print("mem:", mem) + return mem + +#get all file names which contain key_str +def file_name(file_dir, key_str): + print(file_dir, key_str) + file_list = [] + funs_list = [] + + for root, dirs, files in os.walk(file_dir): + print("file:", files) + print("root:", root) + print("dirs:", dirs) + for file_i in files: + if file_i.find(key_str) >= 0: + full_path = os.path.join(os.getcwd() + "/" + root, file_i) + print(full_path) + segs = file_i.split('_') + if len(segs) < 2: + continue + funs=segs[0].strip() + print("funs---------", funs) + file_list.append(full_path) + funs_list.append(int(funs)) + + #file_list = sorted(file_list, key = lambda x: int(x.split('-')[-1].split(".")[0])) + file_list = sorted(file_list, key = lambda x: int(x.split(key_str)[0].split("/")[-1])) + funs_list = sorted(funs_list) + print(file_list) + print("--------------------------------", funs_list) + return file_list, funs_list + +def get_values(key, files_list, mem_dict): + for file_i in files_list: + mem = parse_file(file_i) + mem_dict[key].append(mem) + + +def parse_perf(file_path): + #key is request type, value is latency + with open(file_path, 'r') as file: + file_content = file.read() + + # 使用正则表达式来匹配所需的数据 + cache_miss_rate_pattern = r'([\d.]+)\s+% of all cache refs' + page_faults_pattern = r'(\d[\d,]*)\s+page-faults' + + # 查找 % of all cache refs 的值 + cache_miss_rate_match = re.search(cache_miss_rate_pattern, file_content) + cache_miss_rate = cache_miss_rate_match.group(1) if cache_miss_rate_match else None + + # 查找 page-faults 的值 + page_faults_match = re.search(page_faults_pattern, file_content) + page_faults = page_faults_match.group(1).replace(',', '') if page_faults_match else None + + return float(cache_miss_rate), int(page_faults) + +def get_perf(key, files_list, pagefault_dict, cache_miss_dict): + for file_i in files_list: + cache_miss, pagefault = parse_perf(file_i) + pagefault_dict[key].append(pagefault) + cache_miss_dict[key].append(cache_miss) + +if __name__ == "__main__": + import json + #file_folders = ['SHINJUKU', 'SHINJUKU_25', 'DARC', 'EDF_SRSF_INTERRUPT'] + #file_folders = ['SHINJUKU_7', 'SHINJUKU_25', 'DARC', 'EDF_SRSF_INTERRUPT'] + file_folders = ['Sledge_pool_per_module', 'Sledge_no_pool', 'EdgeScale'] + #file_folders = ['EdgeScale'] + + argv = sys.argv[1:] + if len(argv) < 1: + print("usage ", sys.argv[0], "[file key]") + sys.exit() + + for key in file_folders: + files_list, funs_list = file_name(key, argv[0]) + funs_dict[key] = funs_list + get_values(key, files_list, mem_dict) + + files_list, funs_list = file_name(key, "_perf") + get_perf(key, files_list, pagefault_dict, cache_miss_dict) + + js1 = json.dumps(mem_dict) + f1 = open("mem.txt", 'w') + f1.write(js1) + f1.close() + + js2 = json.dumps(funs_dict) + f2 = open("funs.txt", 'w') + f2.write(js2) + f2.close() + + js3 = json.dumps(cache_miss_dict) + f3 = open("cache_miss.txt", 'w') + f3.write(js3) + f3.close() + + js4 = json.dumps(pagefault_dict) + f4 = open("pagefault.txt", 'w') + f4.write(js4) + f4.close() + + From b4a22edc7c63c2c8d38499f58f0f0827c056a236 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Sun, 10 Nov 2024 00:10:04 -0700 Subject: [PATCH 142/198] upload vision_apps.json --- runtime/tests/vision_apps.json | 74 ++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 runtime/tests/vision_apps.json diff --git a/runtime/tests/vision_apps.json b/runtime/tests/vision_apps.json new file mode 100644 index 000000000..ae75e5556 --- /dev/null +++ b/runtime/tests/vision_apps.json @@ -0,0 +1,74 @@ +[ + { + "name": "gwu", + "port": 31850, + "replenishment-period-us": 0, + "max-budget-us": 0, + "routes": [ + { + "route": "/sift", + "request-type": 1, + "n-resas": 1, + "path": "sift.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 26, + "relative-deadline-us": 260, + "http-resp-content-type": "text/plain" + }, + { + "route": "/mser", + "request-type": 2, + "n-resas": 5, + "path": "mser.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 2070, + "relative-deadline-us": 20700, + "http-resp-content-type": "text/plain" + }, + { + "route": "/multi_ncut", + "request-type": 3, + "n-resas": 5, + "path": "multi_ncut.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 2070, + "relative-deadline-us": 20700, + "http-resp-content-type": "text/plain" + }, + { + "route": "/tracking", + "request-type": 4, + "n-resas": 5, + "path": "tracking.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 2070, + "relative-deadline-us": 20700, + "http-resp-content-type": "text/plain" + }, + { + "route": "/disparity", + "request-type": 5, + "n-resas": 5, + "path": "disparity.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 2070, + "relative-deadline-us": 20700, + "http-resp-content-type": "text/plain" + }, + { + "route": "/classification", + "request-type": 6, + "n-resas": 5, + "path": "cifar10.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 2070, + "relative-deadline-us": 20700, + "http-resp-content-type": "text/plain" + } + + ] + + } + +] + From 19a372e01a4ce7ebd543e47898614d85e875bc82 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 13 Nov 2024 12:08:53 -0700 Subject: [PATCH 143/198] change DARC core reservation way by group id not request id --- runtime/include/http_router.h | 15 ++++--- runtime/include/request_typed_queue.h | 5 +-- runtime/include/route.h | 1 + runtime/include/route_config.h | 25 ++++++++++- runtime/include/route_config_parse.h | 10 +++++ runtime/include/tenant_functions.h | 10 +++-- runtime/src/listener_thread.c | 4 +- runtime/src/request_typed_queue.c | 10 ++--- runtime/src/route_config.c | 3 ++ ...tpcc_EDF_SHINJUKU.json => dummy_tpcc.json} | 39 +++++++++-------- runtime/tests/dummy_tpcc_DARC.json | 43 ------------------- 11 files changed, 80 insertions(+), 85 deletions(-) create mode 100644 runtime/src/route_config.c rename runtime/tests/{dummy_tpcc_EDF_SHINJUKU.json => dummy_tpcc.json} (70%) delete mode 100644 runtime/tests/dummy_tpcc_DARC.json diff --git a/runtime/include/http_router.h b/runtime/include/http_router.h index 39e1bb753..5140f0f2a 100644 --- a/runtime/include/http_router.h +++ b/runtime/include/http_router.h @@ -38,14 +38,15 @@ http_router_add_route(http_router_t *router, struct route_config *config, struct assert(config->route != NULL); assert(config->http_resp_content_type != NULL); - struct route route = { .route = config->route, - .request_type = config->request_type, - .module = module, - .relative_deadline_us = config->relative_deadline_us, - .relative_deadline = (uint64_t)config->relative_deadline_us - * runtime_processor_speed_MHz, + struct route route = { .route = config->route, + .request_type = config->request_type, + .module = module, + .relative_deadline_us = config->relative_deadline_us, + .relative_deadline = (uint64_t)config->relative_deadline_us + * runtime_processor_speed_MHz, .expected_execution_cycle = config->expected_execution_cycle, - .response_content_type = config->http_resp_content_type }; + .response_content_type = config->http_resp_content_type, + .group_id = config->group_id}; route_latency_init(&route.latency); http_route_total_init(&route.metrics); diff --git a/runtime/include/request_typed_queue.h b/runtime/include/request_typed_queue.h index b9b6f76c3..e00e905a1 100644 --- a/runtime/include/request_typed_queue.h +++ b/runtime/include/request_typed_queue.h @@ -13,9 +13,6 @@ struct request_msg { }; struct request_typed_queue { - uint8_t type; - uint64_t mean_ns; - uint64_t deadline; double ratio; struct sandbox *rqueue[RQUEUE_LEN]; unsigned int rqueue_tail; @@ -34,7 +31,7 @@ struct request_typed_queue { uint64_t last_resa; uint32_t stealable_workers[MAX_WORKERS]; uint32_t n_stealable; - int type_group; + uint32_t type_group; uint64_t max_delay; double prev_demand; diff --git a/runtime/include/route.h b/runtime/include/route.h index 3fffc087f..b239d753b 100644 --- a/runtime/include/route.h +++ b/runtime/include/route.h @@ -21,4 +21,5 @@ struct route { char *response_content_type; struct admissions_info admissions_info; struct perf_window latency; + uint32_t group_id; }; diff --git a/runtime/include/route_config.h b/runtime/include/route_config.h index 337389f63..273432b11 100644 --- a/runtime/include/route_config.h +++ b/runtime/include/route_config.h @@ -4,6 +4,7 @@ #include #include +#include "dispatcher_options.h" #include "admissions_control.h" #include "runtime.h" #include "scheduler_options.h" @@ -13,6 +14,7 @@ enum route_config_member route_config_member_route, route_config_member_request_type, route_config_member_n_resas, + route_config_member_group_id, route_config_member_path, route_config_member_admissions_percentile, route_config_member_expected_execution_us, @@ -21,10 +23,13 @@ enum route_config_member route_config_member_len }; +extern int groups[route_config_member_len]; + struct route_config { char *route; uint8_t request_type; uint32_t n_resas; + uint32_t group_id; char *path; uint8_t admissions_percentile; uint32_t expected_execution_us; @@ -82,7 +87,7 @@ route_config_validate(struct route_config *config, bool *did_set) } if (did_set[route_config_member_http_resp_content_type] == false) { - debuglog("http_resp_content_type not set, defaulting to text/plain\n"); + fprintf(stderr, "http_resp_content_type not set, defaulting to text/plain\n"); config->http_resp_content_type = "text/plain"; } @@ -127,6 +132,22 @@ route_config_validate(struct route_config *config, bool *did_set) } #endif } - + + if (dispatcher == DISPATCHER_DARC) { + if (did_set[route_config_member_group_id] == false) { + fprintf(stderr, "group id is required for DARC\n"); + return -1; + } + + if (groups[config->group_id] == 0) { + groups[config->group_id] = config->n_resas; + } else { + if (groups[config->group_id] != config->n_resas) { + fprintf(stderr, "same group id %d has different n-resas config, must be same\n", config->group_id); + return -1; + } + } + } + return 0; } diff --git a/runtime/include/route_config_parse.h b/runtime/include/route_config_parse.h index 522f3dbc3..e22dd52d4 100644 --- a/runtime/include/route_config_parse.h +++ b/runtime/include/route_config_parse.h @@ -9,6 +9,7 @@ static const char *route_config_json_keys[route_config_member_len] = { "route", "request-type", "n-resas", + "group-id", "path", "admissions-percentile", "expected-execution-us", @@ -76,6 +77,15 @@ route_config_parse(struct route_config *config, const char *json_buf, jsmntok_t route_config_json_keys[route_config_member_n_resas], &config->n_resas); if (rc < 0) return -1; + } else if (strcmp(key, route_config_json_keys[route_config_member_group_id]) == 0) { + if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1; + if (route_config_set_key_once(did_set, route_config_member_group_id) == -1) + return -1; + + int rc = parse_uint32_t(tokens[i], json_buf, + route_config_json_keys[route_config_member_group_id], + &config->group_id); + if (rc < 0) return -1; } else if (strcmp(key, route_config_json_keys[route_config_member_path]) == 0) { if (!is_nonempty_string(tokens[i], key)) return -1; if (route_config_set_key_once(did_set, route_config_member_path) == -1) return -1; diff --git a/runtime/include/tenant_functions.h b/runtime/include/tenant_functions.h index 396dddc83..cfcae1d73 100644 --- a/runtime/include/tenant_functions.h +++ b/runtime/include/tenant_functions.h @@ -197,15 +197,17 @@ tenant_request_typed_queue_init(struct tenant *tenant, void *arg1, void *arg2) { for(int i = 0; i < tenant->routes_len; i++) { request_type_deque[tenant->routes_config[i].request_type - 1] = request_typed_deque_init(tenant->routes_config[i].request_type, 4096); + n_rtypes++; } - } else if (dispatcher == DISPATCHER_DARC) { for(int i = 0; i < tenant->routes_len; i++) { - request_type_queue[tenant->routes_config[i].request_type - 1] = - request_typed_queue_init(tenant->routes_config[i].request_type, tenant->routes_config[i].n_resas); + if (request_type_queue[tenant->routes_config[i].group_id - 1] == NULL) { + request_type_queue[tenant->routes_config[i].group_id - 1] = + request_typed_queue_init(tenant->routes_config[i].group_id, tenant->routes_config[i].n_resas); + n_rtypes++; + } } } - n_rtypes = tenant->routes_len; } static inline void diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 70293b595..df5a42068 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -67,7 +67,7 @@ _Atomic uint32_t free_workers[MAX_DISPATCHER] = {0}; // the index is the dispate // will be 111, then the free_workers[dispatcher_id] is 7 -thread_local struct request_typed_queue *request_type_queue[MAX_REQUEST_TYPE]; +thread_local struct request_typed_queue *request_type_queue[MAX_REQUEST_TYPE]; // key is group ID thread_local struct request_typed_deque *request_type_deque[MAX_REQUEST_TYPE]; thread_local uint32_t n_rtypes = 0; @@ -672,7 +672,7 @@ void darc_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t s memcpy(sandbox->rpc_request_body, msg, size); sandbox->rpc_request_body_size = size; - push_to_rqueue(sandbox, request_type_queue[req_type - 1], __getcycles()); + push_to_rqueue(sandbox, request_type_queue[route->group_id - 1], __getcycles()); global_queue_length++; if (global_queue_length > max_queue_length) { max_queue_length = global_queue_length; diff --git a/runtime/src/request_typed_queue.c b/runtime/src/request_typed_queue.c index e4e4c4c5f..52801e7a2 100644 --- a/runtime/src/request_typed_queue.c +++ b/runtime/src/request_typed_queue.c @@ -12,9 +12,7 @@ extern thread_local uint8_t dispatcher_thread_idx; struct request_typed_queue * request_typed_queue_init(uint8_t type, uint32_t n_resas) { struct request_typed_queue *queue = malloc(sizeof(struct request_typed_queue)); - queue->type = type; - queue->mean_ns = 0; - queue->deadline = 0; + queue->type_group = type; queue->rqueue_tail = 0; queue->rqueue_head = 0; queue->n_resas = n_resas; @@ -27,10 +25,10 @@ request_typed_queue_init(uint8_t type, uint32_t n_resas) { } if (queue->n_stealable == 0) { - printf("Listener %u reserve %u cores (from %u to %u) to request type %u, can steal 0 core\n", + printf("Listener %u reserve %u cores (from %u to %u) to group id %u, can steal 0 core\n", dispatcher_thread_idx, n_resas, queue->res_workers[0], queue->res_workers[n_resas-1], type); } else { - printf("Listener %u reserve %u cores (from %u to %u) to request type %u, can steal cores %u(from %u to %u)\n", + printf("Listener %u reserve %u cores (from %u to %u) to group id %u, can steal cores %u(from %u to %u)\n", dispatcher_thread_idx, n_resas, queue->res_workers[0], queue->res_workers[n_resas-1], type, queue->n_stealable, queue->stealable_workers[0], queue->stealable_workers[queue->n_stealable-1]); } @@ -44,7 +42,7 @@ int push_to_rqueue(struct sandbox *sandbox, struct request_typed_queue *rtype, u assert(sandbox != NULL); if (unlikely(rtype->rqueue_head - rtype->rqueue_tail == RQUEUE_LEN)) { - panic("Dispatcher dropped request as type %hhu because queue is full\n", rtype->type); + panic("Dispatcher dropped request as group type %d because queue is full\n", rtype->type_group); return -1; } else { rtype->tsqueue[rtype->rqueue_head & (RQUEUE_LEN - 1)] = tsc; diff --git a/runtime/src/route_config.c b/runtime/src/route_config.c new file mode 100644 index 000000000..b09b23b5c --- /dev/null +++ b/runtime/src/route_config.c @@ -0,0 +1,3 @@ +#include "route_config.h" + +int groups[route_config_member_len] = { 0 }; // record reserved cpu cores per group, key is group id diff --git a/runtime/tests/dummy_tpcc_EDF_SHINJUKU.json b/runtime/tests/dummy_tpcc.json similarity index 70% rename from runtime/tests/dummy_tpcc_EDF_SHINJUKU.json rename to runtime/tests/dummy_tpcc.json index 206651aee..7bb073931 100644 --- a/runtime/tests/dummy_tpcc_EDF_SHINJUKU.json +++ b/runtime/tests/dummy_tpcc.json @@ -9,53 +9,58 @@ "route": "/Payment", "request-type": 1, "n-resas": 1, + "group-id": 1, "path": "dummy_tpcc.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 6, - "relative-deadline-us": 60, + "expected-execution-us": 5, + "relative-deadline-us": 50, "http-resp-content-type": "text/plain" }, - { + { "route": "/OrderStatus", "request-type": 2, - "n-resas": 1, + "n-resas": 1, + "group-id": 1, "path": "dummy_tpcc.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 6, - "relative-deadline-us": 60, + "expected-execution-us": 5, + "relative-deadline-us": 50, "http-resp-content-type": "text/plain" }, { "route": "/NewOrder", "request-type": 3, - "n-resas": 1, + "n-resas": 2, + "group-id": 2, "path": "dummy_tpcc.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 20, - "relative-deadline-us": 200, + "expected-execution-us": 5, + "relative-deadline-us": 50, "http-resp-content-type": "text/plain" }, - { + + { "route": "/Delivery", "request-type": 4, - "n-resas": 1, + "n-resas": 2, + "group-id": 3, "path": "dummy_tpcc.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 88, - "relative-deadline-us": 880, + "expected-execution-us": 5, + "relative-deadline-us": 50, "http-resp-content-type": "text/plain" }, { "route": "/StockLevel", "request-type": 5, - "n-resas": 1, + "n-resas": 2, + "group-id": 3, "path": "dummy_tpcc.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 100, - "relative-deadline-us": 1000, + "expected-execution-us": 5, + "relative-deadline-us": 50, "http-resp-content-type": "text/plain" } - ] } diff --git a/runtime/tests/dummy_tpcc_DARC.json b/runtime/tests/dummy_tpcc_DARC.json deleted file mode 100644 index 41eef78fb..000000000 --- a/runtime/tests/dummy_tpcc_DARC.json +++ /dev/null @@ -1,43 +0,0 @@ -[ - { - "name": "gwu", - "port": 31850, - "replenishment-period-us": 0, - "max-budget-us": 0, - "routes": [ - { - "route": "/Payment-OrderStatus", - "request-type": 1, - "n-resas": 1, - "path": "dummy_tpcc.wasm.so", - "admissions-percentile": 70, - "expected-execution-us": 5, - "relative-deadline-us": 50, - "http-resp-content-type": "text/plain" - }, - { - "route": "/NewOrder", - "request-type": 2, - "n-resas": 2, - "path": "dummy_tpcc.wasm.so", - "admissions-percentile": 70, - "expected-execution-us": 5, - "relative-deadline-us": 50, - "http-resp-content-type": "text/plain" - }, - { - "route": "/Delivery-StockLevel", - "request-type": 3, - "n-resas": 2, - "path": "dummy_tpcc.wasm.so", - "admissions-percentile": 70, - "expected-execution-us": 5, - "relative-deadline-us": 50, - "http-resp-content-type": "text/plain" - } - ] - - } - -] - From f1983f1e235377a4b0c8e8e876c927ffa2729b3f Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 13 Nov 2024 14:30:42 -0700 Subject: [PATCH 144/198] 1. check valiadation of group-id and n-resas if using DARC. 2. add group-id to all .json files --- runtime/include/route_config.h | 10 +++ runtime/tests/empty.json | 1 + runtime/tests/fib.json | 2 + runtime/tests/hash.json | 3 +- runtime/tests/hash_darc.json | 2 + runtime/tests/hash_high_bimodal.json | 2 + runtime/tests/high_bimodal_realapps.json | 2 + runtime/tests/sed_json.sh | 2 +- runtime/tests/vision_apps.json | 78 +++++++++++++----------- 9 files changed, 64 insertions(+), 38 deletions(-) diff --git a/runtime/include/route_config.h b/runtime/include/route_config.h index 273432b11..66e3c29c7 100644 --- a/runtime/include/route_config.h +++ b/runtime/include/route_config.h @@ -134,11 +134,21 @@ route_config_validate(struct route_config *config, bool *did_set) } if (dispatcher == DISPATCHER_DARC) { + if (did_set[route_config_member_n_resas] == false) { + fprintf(stderr, "n-resas is required for DARC\n"); + return -1; + } + if (did_set[route_config_member_group_id] == false) { fprintf(stderr, "group id is required for DARC\n"); return -1; } + if (config->group_id <= 0) { + fprintf(stderr, "group id must be larger than 0\n"); + return -1; + } + if (groups[config->group_id] == 0) { groups[config->group_id] = config->n_resas; } else { diff --git a/runtime/tests/empty.json b/runtime/tests/empty.json index acfa2f6bb..dfa91cef5 100644 --- a/runtime/tests/empty.json +++ b/runtime/tests/empty.json @@ -9,6 +9,7 @@ "route": "/empty", "request-type": 1, "n-resas": 2, + "group-id": 1, "path": "empty.wasm.so", "admissions-percentile": 70, "expected-execution-us": 1, diff --git a/runtime/tests/fib.json b/runtime/tests/fib.json index e8bf8fb67..3666ec8bc 100644 --- a/runtime/tests/fib.json +++ b/runtime/tests/fib.json @@ -9,6 +9,7 @@ "route": "/fib", "request-type": 1, "n-resas": 1, + "group-id": 1, "path": "fibonacci.wasm.so", "admissions-percentile": 70, "expected-execution-us": 5, @@ -19,6 +20,7 @@ "route": "/fib2", "request-type": 2, "n-resas": 2, + "group-id": 2, "path": "fibonacci.wasm.so", "admissions-percentile": 70, "expected-execution-us": 6480, diff --git a/runtime/tests/hash.json b/runtime/tests/hash.json index f273d745b..2c3f1e84c 100644 --- a/runtime/tests/hash.json +++ b/runtime/tests/hash.json @@ -8,7 +8,8 @@ { "route": "/hash", "request-type": 1, - "n-resas": 6, + "n-resas": 3, + "group-id": 1, "path": "hash.wasm.so", "admissions-percentile": 70, "expected-execution-us": 5, diff --git a/runtime/tests/hash_darc.json b/runtime/tests/hash_darc.json index e6faad624..9bfb2b6d4 100644 --- a/runtime/tests/hash_darc.json +++ b/runtime/tests/hash_darc.json @@ -9,6 +9,7 @@ "route": "/hash1", "request-type": 1, "n-resas": 3, + "group-id": 1, "path": "hash.wasm.so", "admissions-percentile": 70, "expected-execution-us": 5, @@ -19,6 +20,7 @@ "route": "/hash2", "request-type": 2, "n-resas": 3, + "group-id": 2, "path": "hash.wasm.so", "admissions-percentile": 70, "expected-execution-us": 5, diff --git a/runtime/tests/hash_high_bimodal.json b/runtime/tests/hash_high_bimodal.json index f7382c25a..ecdcb18f2 100644 --- a/runtime/tests/hash_high_bimodal.json +++ b/runtime/tests/hash_high_bimodal.json @@ -9,6 +9,7 @@ "route": "/hash", "request-type": 1, "n-resas": 1, + "group-id": 1, "path": "hash.wasm.so", "admissions-percentile": 70, "expected-execution-us": 5, @@ -19,6 +20,7 @@ "route": "/hash2", "request-type": 2, "n-resas": 5, + "group-id": 2, "path": "hash.wasm.so", "admissions-percentile": 70, "expected-execution-us": 5, diff --git a/runtime/tests/high_bimodal_realapps.json b/runtime/tests/high_bimodal_realapps.json index f55881cfc..68cd18c5d 100644 --- a/runtime/tests/high_bimodal_realapps.json +++ b/runtime/tests/high_bimodal_realapps.json @@ -9,6 +9,7 @@ "route": "/resize", "request-type": 1, "n-resas": 1, + "group-id": 1, "path": "resize_image.wasm.so", "admissions-percentile": 70, "expected-execution-us": 26, @@ -19,6 +20,7 @@ "route": "/classifier", "request-type": 2, "n-resas": 5, + "group-id": 2, "path": "cifar10.wasm.so", "admissions-percentile": 70, "expected-execution-us": 2070, diff --git a/runtime/tests/sed_json.sh b/runtime/tests/sed_json.sh index ad2eadc3b..4c2c671fd 100755 --- a/runtime/tests/sed_json.sh +++ b/runtime/tests/sed_json.sh @@ -19,7 +19,7 @@ fi sed -i "11s/\(\"n-resas\": \)[0-9]\+/\1$NUMBER1/" "$FILENAME" # Replace the "n-resas" value in the 21st line with NUMBER2 -sed -i "21s/\(\"n-resas\": \)[0-9]\+/\1$NUMBER2/" "$FILENAME" +sed -i "22s/\(\"n-resas\": \)[0-9]\+/\1$NUMBER2/" "$FILENAME" echo "The file $FILENAME has been updated." diff --git a/runtime/tests/vision_apps.json b/runtime/tests/vision_apps.json index ae75e5556..200defde9 100644 --- a/runtime/tests/vision_apps.json +++ b/runtime/tests/vision_apps.json @@ -5,67 +5,73 @@ "replenishment-period-us": 0, "max-budget-us": 0, "routes": [ - { - "route": "/sift", + { + "route": "/tracking", "request-type": 1, "n-resas": 1, - "path": "sift.wasm.so", + "group-id": 1, + "path": "tracking.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 26, - "relative-deadline-us": 260, + "expected-execution-us": 5, + "relative-deadline-us": 50, "http-resp-content-type": "text/plain" - }, - { - "route": "/mser", + }, + { + "route": "/disparity", "request-type": 2, - "n-resas": 5, - "path": "mser.wasm.so", + "n-resas": 1, + "group-id": 1, + "path": "disparity.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 2070, - "relative-deadline-us": 20700, + "expected-execution-us": 5, + "relative-deadline-us": 50, "http-resp-content-type": "text/plain" }, - { - "route": "/multi_ncut", + { + "route": "/mser", "request-type": 3, - "n-resas": 5, - "path": "multi_ncut.wasm.so", + "n-resas": 1, + "group-id": 1, + "path": "mser.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 2070, - "relative-deadline-us": 20700, + "expected-execution-us": 5, + "relative-deadline-us": 50, "http-resp-content-type": "text/plain" }, - { - "route": "/tracking", + { + "route": "/sift", "request-type": 4, - "n-resas": 5, - "path": "tracking.wasm.so", + "n-resas": 1, + "group-id": 1, + "path": "sift.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 2070, - "relative-deadline-us": 20700, + "expected-execution-us": 5, + "relative-deadline-us": 50, "http-resp-content-type": "text/plain" }, - { - "route": "/disparity", + { + "route": "/multi_ncut", "request-type": 5, - "n-resas": 5, - "path": "disparity.wasm.so", + "n-resas": 1, + "group-id": 2, + "path": "multi_ncut.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 2070, - "relative-deadline-us": 20700, + "expected-execution-us": 5, + "relative-deadline-us": 50, "http-resp-content-type": "text/plain" }, - { - "route": "/classification", + { + "route": "/cifar10", "request-type": 6, - "n-resas": 5, + "n-resas": 8, + "group-id": 3, "path": "cifar10.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 2070, - "relative-deadline-us": 20700, + "expected-execution-us": 5, + "relative-deadline-us": 50, "http-resp-content-type": "text/plain" } - + ] } From 5e81cbc26c2f133bb33310a15e61467b03a53257 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 13 Nov 2024 15:11:02 -0700 Subject: [PATCH 145/198] update increase_req_type.patch --- runtime/increase_req_type.patch | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/runtime/increase_req_type.patch b/runtime/increase_req_type.patch index 0f2db52ea..cb328d347 100644 --- a/runtime/increase_req_type.patch +++ b/runtime/increase_req_type.patch @@ -11,10 +11,10 @@ index 7442ea1..04de7fa 100644 void darc_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); void shinjuku_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); diff --git a/runtime/include/http_router.h b/runtime/include/http_router.h -index 39e1bb7..e6c877c 100644 +index 5140f0f..8aa30dd 100644 --- a/runtime/include/http_router.h +++ b/runtime/include/http_router.h -@@ -91,7 +91,7 @@ http_router_match_route(http_router_t *router, char *route) +@@ -92,7 +92,7 @@ http_router_match_route(http_router_t *router, char *route) } static inline struct route * @@ -50,7 +50,7 @@ index 24d1b46..32902dc 100644 struct module_database { struct module *modules[MODULE_DATABASE_CAPACITY]; diff --git a/runtime/include/route.h b/runtime/include/route.h -index 3fffc08..3127055 100644 +index b239d75..9afaafa 100644 --- a/runtime/include/route.h +++ b/runtime/include/route.h @@ -11,7 +11,7 @@ @@ -63,19 +63,19 @@ index 3fffc08..3127055 100644 struct module *module; /* HTTP State */ diff --git a/runtime/include/route_config.h b/runtime/include/route_config.h -index 337389f..fcc4c3a 100644 +index 66e3c29..d25f5e9 100644 --- a/runtime/include/route_config.h +++ b/runtime/include/route_config.h -@@ -23,7 +23,7 @@ enum route_config_member +@@ -27,7 +27,7 @@ extern int groups[route_config_member_len]; struct route_config { char *route; - uint8_t request_type; + uint16_t request_type; uint32_t n_resas; + uint32_t group_id; char *path; - uint8_t admissions_percentile; -@@ -48,8 +48,7 @@ static inline void +@@ -53,8 +53,7 @@ static inline void route_config_print(struct route_config *config) { printf("[Route] Route: %s\n", config->route); @@ -86,10 +86,10 @@ index 337389f..fcc4c3a 100644 printf("[Route] Admissions Percentile: %hhu\n", config->admissions_percentile); printf("[Route] Expected Execution (us): %u\n", config->expected_execution_us); diff --git a/runtime/include/route_config_parse.h b/runtime/include/route_config_parse.h -index 522f3db..4b68008 100644 +index e22dd52..662a13a 100644 --- a/runtime/include/route_config_parse.h +++ b/runtime/include/route_config_parse.h -@@ -63,7 +63,7 @@ route_config_parse(struct route_config *config, const char *json_buf, jsmntok_t +@@ -64,7 +64,7 @@ route_config_parse(struct route_config *config, const char *json_buf, jsmntok_t if (route_config_set_key_once(did_set, route_config_member_request_type) == -1) return -1; @@ -177,7 +177,7 @@ index 14b7aef..6515015 100644 if (tenant_config_set_key_once(did_set, tenant_config_member_routes) == -1) return -1; diff --git a/runtime/include/tenant_functions.h b/runtime/include/tenant_functions.h -index 396dddc..919fd8c 100644 +index cfcae1d..0e781ed 100644 --- a/runtime/include/tenant_functions.h +++ b/runtime/include/tenant_functions.h @@ -21,7 +21,7 @@ extern thread_local uint32_t n_rtypes; @@ -365,7 +365,7 @@ index 77c3417..f9837df 100644 * Initializes perf window * @param admissions_info diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c -index 70293b5..987473a 100644 +index df5a420..7a4ad87 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -472,7 +472,7 @@ on_client_socket_epoll_event(struct epoll_event *evt) From c2d13ae2db69f931d117d174431d6dd5911db8b7 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 13 Nov 2024 15:41:30 -0700 Subject: [PATCH 146/198] update vision_apps.json --- runtime/tests/vision_apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/tests/vision_apps.json b/runtime/tests/vision_apps.json index 200defde9..0ce7b6e74 100644 --- a/runtime/tests/vision_apps.json +++ b/runtime/tests/vision_apps.json @@ -63,7 +63,7 @@ { "route": "/cifar10", "request-type": 6, - "n-resas": 8, + "n-resas": 6, "group-id": 3, "path": "cifar10.wasm.so", "admissions-percentile": 70, From fd55a29192d4edeb4e247e06e2c7fc6ad566e4b6 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 13 Nov 2024 15:53:14 -0700 Subject: [PATCH 147/198] update vision_apps.json --- runtime/tests/vision_apps.json | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/runtime/tests/vision_apps.json b/runtime/tests/vision_apps.json index 0ce7b6e74..9a379b12b 100644 --- a/runtime/tests/vision_apps.json +++ b/runtime/tests/vision_apps.json @@ -12,8 +12,8 @@ "group-id": 1, "path": "tracking.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 5, - "relative-deadline-us": 50, + "expected-execution-us": 6, + "relative-deadline-us": 60, "http-resp-content-type": "text/plain" }, { @@ -23,8 +23,8 @@ "group-id": 1, "path": "disparity.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 5, - "relative-deadline-us": 50, + "expected-execution-us": 11, + "relative-deadline-us": 110, "http-resp-content-type": "text/plain" }, { @@ -34,8 +34,8 @@ "group-id": 1, "path": "mser.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 5, - "relative-deadline-us": 50, + "expected-execution-us": 16, + "relative-deadline-us": 160, "http-resp-content-type": "text/plain" }, { @@ -45,8 +45,8 @@ "group-id": 1, "path": "sift.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 5, - "relative-deadline-us": 50, + "expected-execution-us": 113, + "relative-deadline-us": 1130, "http-resp-content-type": "text/plain" }, { @@ -56,8 +56,8 @@ "group-id": 2, "path": "multi_ncut.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 5, - "relative-deadline-us": 50, + "expected-execution-us": 326, + "relative-deadline-us": 3260, "http-resp-content-type": "text/plain" }, { @@ -67,8 +67,8 @@ "group-id": 3, "path": "cifar10.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 5, - "relative-deadline-us": 50, + "expected-execution-us": 2060, + "relative-deadline-us": 20600, "http-resp-content-type": "text/plain" } From cd2c95be5465db794698d90420c1501731451357 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 14 Nov 2024 14:24:20 -0700 Subject: [PATCH 148/198] update dummy_tpcc.json --- runtime/tests/dummy_tpcc.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/runtime/tests/dummy_tpcc.json b/runtime/tests/dummy_tpcc.json index 7bb073931..de44828e4 100644 --- a/runtime/tests/dummy_tpcc.json +++ b/runtime/tests/dummy_tpcc.json @@ -12,8 +12,8 @@ "group-id": 1, "path": "dummy_tpcc.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 5, - "relative-deadline-us": 50, + "expected-execution-us": 6, + "relative-deadline-us": 60, "http-resp-content-type": "text/plain" }, { @@ -23,8 +23,8 @@ "group-id": 1, "path": "dummy_tpcc.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 5, - "relative-deadline-us": 50, + "expected-execution-us": 6, + "relative-deadline-us": 60, "http-resp-content-type": "text/plain" }, { @@ -34,8 +34,8 @@ "group-id": 2, "path": "dummy_tpcc.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 5, - "relative-deadline-us": 50, + "expected-execution-us": 20, + "relative-deadline-us": 200, "http-resp-content-type": "text/plain" }, @@ -46,8 +46,8 @@ "group-id": 3, "path": "dummy_tpcc.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 5, - "relative-deadline-us": 50, + "expected-execution-us": 88, + "relative-deadline-us": 880, "http-resp-content-type": "text/plain" }, { @@ -57,8 +57,8 @@ "group-id": 3, "path": "dummy_tpcc.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 5, - "relative-deadline-us": 50, + "expected-execution-us": 100, + "relative-deadline-us": 1000, "http-resp-content-type": "text/plain" } ] From a07829605db181e20c4eed9bb971df428e4e4470 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 15 Nov 2024 15:18:40 -0700 Subject: [PATCH 149/198] update log info for each sandbox --- runtime/include/sandbox_perf_log.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/runtime/include/sandbox_perf_log.h b/runtime/include/sandbox_perf_log.h index 042da55f8..f2d07052a 100644 --- a/runtime/include/sandbox_perf_log.h +++ b/runtime/include/sandbox_perf_log.h @@ -16,7 +16,7 @@ static inline void sandbox_perf_log_print_header() { if (sandbox_perf_log == NULL) { perror("sandbox perf log"); } - fprintf(sandbox_perf_log, "tid,rid,total,execution,queued,route,init,cleanup,deadline,queuelen\n"); + fprintf(sandbox_perf_log, "tid,rid,SLO,total,execution,queued,rtype,init,cleanup,deadline,queuelen\n"); } /** @@ -58,18 +58,18 @@ sandbox_perf_log_print_entry(struct sandbox *sandbox) global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route,init_time, cleanup, deadline, sandbox->context_switch_to, other, t1,t2,t3,t4,t5); */ - mem_log("%d %u miss %lu %lu %lu %s %lu %lu %lu %u\n", + mem_log("%d %u miss %lu %lu %lu %u %lu %lu %lu %u\n", global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, - sandbox->route->route,init_time, cleanup, deadline,local_queue_length[global_worker_thread_idx]); + sandbox->route->request_type, init_time, cleanup, deadline,local_queue_length[global_worker_thread_idx]); } else { /*mem_log("tid %d %u meet %lu %lu %lu %s %lu %lu %lu f%d %lu %lu %lu %lu %lu %lu\n", global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route,init_time, cleanup, deadline, sandbox->context_switch_to, other, t1,t2,t3,t4,t5); */ - mem_log("%d %u meet %lu %lu %lu %s %lu %lu %lu %lu\n", + mem_log("%d %u meet %lu %lu %lu %u %lu %lu %lu %lu\n", global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, - sandbox->route->route,init_time, cleanup, deadline,local_queue_length[global_worker_thread_idx]); + sandbox->route->request_type, init_time, cleanup, deadline,local_queue_length[global_worker_thread_idx]); } /* From 4353632b68b26adb07d44ecfdc2f59ff78da93ed Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 15 Nov 2024 17:09:48 -0700 Subject: [PATCH 150/198] update meet_deadline_percentage.py and parse_batch.py --- runtime/tests/meet_deadline_percentage.py | 33 ++++++------ runtime/tests/parse_batch.py | 61 +++++++++++++++++++---- 2 files changed, 66 insertions(+), 28 deletions(-) diff --git a/runtime/tests/meet_deadline_percentage.py b/runtime/tests/meet_deadline_percentage.py index d685673da..2c3eb1570 100644 --- a/runtime/tests/meet_deadline_percentage.py +++ b/runtime/tests/meet_deadline_percentage.py @@ -63,13 +63,12 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): line = line.strip() if "meet" in line: meet_deadline += 1 - name = line.split(" ")[7] - cleanup = line.split(" ")[9] - deadline = int(line.split(" ")[10]) - name = name[1:] - tid = line.split(" ")[1] + name = line.split(" ")[6] + cleanup = line.split(" ")[8] + deadline = int(line.split(" ")[9]) + tid = line.split(" ")[0] request_counter[name] += 1 - total_time = int(line.split(" ")[4]) + total_time = int(line.split(" ")[3]) total_time_dist[name].append(total_time) if name == "fib": total_slow_down.append(round((float(total_time) / deadline), 2)) @@ -80,22 +79,21 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): if total_time > max_latency_dist[name]: max_latency_dist[name] = total_time meet_deadline_dist[name] += 1 - exe_time = int(line.split(" ")[5]) + exe_time = int(line.split(" ")[4]) if exe_time > max_exe_time: max_exe_time = exe_time running_times[name].append(exe_time); - queue_time = int(line.split(" ")[6]) + queue_time = int(line.split(" ")[5]) queuing_times[name].append(queue_time); thread_running_times[tid].append(exe_time); t2_cleanup[tid].append(cleanup) if "miss" in line: miss_deadline += 1 - name = line.split(" ")[7] - cleanup = line.split(" ")[9] - deadline = int(line.split(" ")[10]) - name = name[1:] - tid = line.split(" ")[1] - total_time = int(line.split(" ")[4]) + name = line.split(" ")[6] + cleanup = line.split(" ")[8] + deadline = int(line.split(" ")[9]) + tid = line.split(" ")[0] + total_time = int(line.split(" ")[3]) if total_time > max_latency_dist[name]: max_latency_dist[name] = total_time request_counter[name] += 1 @@ -107,12 +105,11 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): total_slow_down.append(round((float(total_time) / deadline), 2)) thread_times[tid].append(total_time) miss_deadline_dist[name] += 1 - exe_time = line.split(" ")[5] - exe_time = int(line.split(" ")[5]) + exe_time = int(line.split(" ")[4]) if exe_time > max_exe_time: max_exe_time = exe_time running_times[name].append(exe_time); - queue_time = int(line.split(" ")[6]) + queue_time = int(line.split(" ")[5]) queuing_times[name].append(queue_time); thread_running_times[tid].append(exe_time); t2_cleanup[tid].append(cleanup) @@ -150,7 +147,7 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): total_request = miss_value + value miss_rate = (miss_value * 100) / total_request - print(key + " miss deadline rate:" + str(miss_rate)); + print("type ", key, " miss deadline rate:", str(miss_rate)); # print(func_name_dict[key] + " miss deadline rate:" + str(miss_rate) + " miss count is:" + str(miss_value) + " total request:" + str(total_request)) #print("effective total cpu times:", total_cpu_times) #for key,value in real_time_workload_times_dist.items(): diff --git a/runtime/tests/parse_batch.py b/runtime/tests/parse_batch.py index 8fbca84db..cf65ce7a7 100644 --- a/runtime/tests/parse_batch.py +++ b/runtime/tests/parse_batch.py @@ -3,6 +3,10 @@ import sys from collections import defaultdict +miss_rate_dict = defaultdict(lambda: defaultdict(list)) +total_miss_rate_dict = defaultdict(list) +load_dict = defaultdict(int) + #get all file names which contain key_str def file_name(file_dir, key_str): print(file_dir, key_str) @@ -10,23 +14,28 @@ def file_name(file_dir, key_str): rps_list = [] for root, dirs, files in os.walk(file_dir): - print(files, root, dirs) + print("file:", files) + print("root:", root) + print("dirs:", dirs) for file_i in files: if file_i.find(key_str) >= 0: full_path = os.path.join(os.getcwd() + "/" + root, file_i) - #print(full_path) + print(full_path) segs = file_i.split('-') if len(segs) < 2: continue rps=segs[1] + print("rps---------", rps) rps=rps.split(".")[0] file_list.append(full_path) - rps_list.append(rps) - - file_list = sorted(file_list, key = lambda x: int(x.split('-')[-1].split(".")[0])) + rps_list.append(int(rps)) + + pattern = r"server-(\d+)-\d+\.log" + + file_list = sorted(file_list, key=lambda x: int(re.search(pattern, x).group(1))) rps_list = sorted(rps_list) - print(file_list) - print(rps_list) + #print(file_list) + print("--------------------------------", rps_list) return file_list, rps_list def get_values(key, files_list, latency_dict, slow_down_dict, slow_down_99_9_dict, latency_99_9_dict, slow_down_99_99_dict, latency_99_99_dict): @@ -42,6 +51,9 @@ def get_values(key, files_list, latency_dict, slow_down_dict, slow_down_99_9_dic latency_99_99_rule = r'99.99 percentile latency is\s*([\d.]+)' slow_down_99_99_rule = r'99.99 percentile slow down is\s*([\d.]+)' + miss_rate_rule = r"type\s+(\d+)\s+miss\s+deadline\s+rate:\s+([\d.]+)" + total_miss_rate_rule = r"miss\s+deadline\s+percentage:\s+([\d.]+)" + # Use the regular expressions to find the values latency_match = re.search(latency_rule, rt) slow_down_match = re.search(slow_down_rule, rt) @@ -49,7 +61,8 @@ def get_values(key, files_list, latency_dict, slow_down_dict, slow_down_99_9_dic slow_down_99_9_match = re.search(slow_down_99_9_rule, rt) latency_99_99_match = re.search(latency_99_99_rule, rt) slow_down_99_99_match = re.search(slow_down_99_99_rule, rt) - + total_miss_rate_match = re.search(total_miss_rate_rule, rt) + # Check if matches were found and extract the values if latency_match: latency_value = 0 @@ -87,11 +100,22 @@ def get_values(key, files_list, latency_dict, slow_down_dict, slow_down_99_9_dic print("99.99th slow down is:", slow_down_value) slow_down_99_99_dict[key].append(slow_down_value) + if total_miss_rate_match: + total_miss_rate = 0 + total_miss_rate = total_miss_rate_match.group(1) + print("total miss rate for ", key, " is:", total_miss_rate) + total_miss_rate_dict[key].append(total_miss_rate) + + for match in re.finditer(miss_rate_rule, rt): + r_type, miss_rate = match.groups() + print("type:", r_type, "miss rate:", miss_rate) + miss_rate_dict[key][int(r_type)].append(float(miss_rate)) + + if __name__ == "__main__": import json #file_folders = ['SHINJUKU', 'SHINJUKU_25', 'DARC', 'EDF_SRSF_INTERRUPT'] - file_folders = ['SHINJUKU_5', 'SHINJUKU_100', 'SHINJUKU_200', 'SHINJUKU_25', 'DARC', 'EDF_SRSF_INTERRUPT'] - #file_folders = ['SHINJUKU'] + file_folders = ['SHINJUKU', 'DARC', 'EDF_INTERRUPT'] latency = defaultdict(list) slow_down = defaultdict(list) slow_down_99_9 = defaultdict(list) @@ -108,6 +132,7 @@ def get_values(key, files_list, latency_dict, slow_down_dict, slow_down_99_9_dic for key in file_folders: files_list, rps_list = file_name(key, argv[0]) + load_dict[key] = rps_list get_values(key, files_list, latency, slow_down, slow_down_99_9, latency_99_9, slow_down_99_99, latency_99_99) print("99 latency:") @@ -151,3 +176,19 @@ def get_values(key, files_list, latency_dict, slow_down_dict, slow_down_99_9_dic f3 = open("rps.txt", 'w') f3.write(js3) f3.close() + + js8 = json.dumps(miss_rate_dict) + f8 = open("seperate_miss_rate.txt", 'w') + f8.write(js8) + f8.close() + + js9 = json.dumps(total_miss_rate_dict) + f9 = open("total_miss_rate.txt", 'w') + f9.write(js9) + f9.close() + + js10 = json.dumps(load_dict) + f10 = open("sload.txt", 'w') + f10.write(js10) + f10.close() + From 3f5a2b251bc0794d40afde8b1d1f358b1052a9c9 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 20 Nov 2024 23:31:15 -0700 Subject: [PATCH 151/198] fix bug: forget to assign admission_info.uid, assign it with request type id --- runtime/include/admissions_info.h | 2 +- runtime/include/http_router.h | 2 +- runtime/include/sandbox_perf_log.h | 16 +++++++++------- runtime/include/tenant_functions.h | 1 - runtime/src/admissions_info.c | 3 ++- runtime/src/worker_thread.c | 4 ++-- 6 files changed, 15 insertions(+), 13 deletions(-) diff --git a/runtime/include/admissions_info.h b/runtime/include/admissions_info.h index 57a152fb3..13f31395f 100644 --- a/runtime/include/admissions_info.h +++ b/runtime/include/admissions_info.h @@ -12,7 +12,7 @@ struct admissions_info { uint32_t uid; /* unique id to identify an admissions_info at each thread */ }; -void admissions_info_initialize(struct admissions_info *admissions_info, uint8_t percentile, +void admissions_info_initialize(struct admissions_info *admissions_info, uint8_t uid, uint8_t percentile, uint64_t expected_execution, uint64_t relative_deadline); void admissions_info_update(struct admissions_info *admissions_info, uint64_t execution_duration); void perf_window_per_thread_update(struct admissions_info *admissions_info, uint64_t execution_duration); diff --git a/runtime/include/http_router.h b/runtime/include/http_router.h index 5140f0f2a..b851f45d9 100644 --- a/runtime/include/http_router.h +++ b/runtime/include/http_router.h @@ -69,7 +69,7 @@ http_router_add_route(http_router_t *router, struct route_config *config, struct /* Admissions Control */ uint64_t expected_execution = (uint64_t)config->expected_execution_us * runtime_processor_speed_MHz; - admissions_info_initialize(&route.admissions_info, config->admissions_percentile, expected_execution, + admissions_info_initialize(&route.admissions_info, route.request_type, config->admissions_percentile, expected_execution, route.relative_deadline); int rc = vec_route_t_push(router, route); diff --git a/runtime/include/sandbox_perf_log.h b/runtime/include/sandbox_perf_log.h index f2d07052a..ab588dcf0 100644 --- a/runtime/include/sandbox_perf_log.h +++ b/runtime/include/sandbox_perf_log.h @@ -16,7 +16,7 @@ static inline void sandbox_perf_log_print_header() { if (sandbox_perf_log == NULL) { perror("sandbox perf log"); } - fprintf(sandbox_perf_log, "tid,rid,SLO,total,execution,queued,rtype,init,cleanup,deadline,queuelen\n"); + fprintf(sandbox_perf_log, "tid,rid,SLO,total,execution,queued,rtype,init,cleanup,deadline,queuelen,estimated\n"); } /** @@ -45,12 +45,14 @@ sandbox_perf_log_print_entry(struct sandbox *sandbox) uint64_t cleanup = sandbox->timestamp_of.cleanup / runtime_processor_speed_MHz; uint64_t deadline = sandbox->relative_deadline / runtime_processor_speed_MHz; uint64_t other = sandbox->timestamp_of.other / runtime_processor_speed_MHz; - uint64_t t1 = sandbox->ret[0] / runtime_processor_speed_MHz; + /* + uint64_t t1 = sandbox->ret[0] / runtime_processor_speed_MHz; uint64_t t2 = sandbox->ret[1] / runtime_processor_speed_MHz; uint64_t t3 = sandbox->ret[2] / runtime_processor_speed_MHz; uint64_t t4 = sandbox->ret[3] / runtime_processor_speed_MHz; uint64_t t5 = sandbox->ret[4] / runtime_processor_speed_MHz; - + */ + uint64_t estimated_time = sandbox->estimated_cost / runtime_processor_speed_MHz; uint64_t init_time = sandbox->duration_of_state[SANDBOX_INITIALIZED] / runtime_processor_speed_MHz; if (miss_deadline) { @@ -58,18 +60,18 @@ sandbox_perf_log_print_entry(struct sandbox *sandbox) global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route,init_time, cleanup, deadline, sandbox->context_switch_to, other, t1,t2,t3,t4,t5); */ - mem_log("%d %u miss %lu %lu %lu %u %lu %lu %lu %u\n", + mem_log("%d %u miss %lu %lu %lu %u %lu %lu %lu %u %lu\n", global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, - sandbox->route->request_type, init_time, cleanup, deadline,local_queue_length[global_worker_thread_idx]); + sandbox->route->request_type, init_time, cleanup, deadline,local_queue_length[global_worker_thread_idx], estimated_time); } else { /*mem_log("tid %d %u meet %lu %lu %lu %s %lu %lu %lu f%d %lu %lu %lu %lu %lu %lu\n", global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, sandbox->route->route,init_time, cleanup, deadline, sandbox->context_switch_to, other, t1,t2,t3,t4,t5); */ - mem_log("%d %u meet %lu %lu %lu %u %lu %lu %lu %lu\n", + mem_log("%d %u meet %lu %lu %lu %u %lu %lu %lu %lu %lu\n", global_worker_thread_idx, sandbox->id, total_time, execution_time, queued_duration, - sandbox->route->request_type, init_time, cleanup, deadline,local_queue_length[global_worker_thread_idx]); + sandbox->route->request_type, init_time, cleanup, deadline,local_queue_length[global_worker_thread_idx], estimated_time); } /* diff --git a/runtime/include/tenant_functions.h b/runtime/include/tenant_functions.h index cfcae1d73..65cb23e6a 100644 --- a/runtime/include/tenant_functions.h +++ b/runtime/include/tenant_functions.h @@ -185,7 +185,6 @@ tenant_preallocate_memory(struct tenant *tenant, void *arg1, void *arg2) { static inline void tenant_perf_window_init(struct tenant *tenant, void *arg1, void *arg2) { for(int i = 0; i < tenant->router.length; i++) { - tenant->router.buffer[i].admissions_info.uid = i; perf_window_initialize(&perf_window_per_thread[i]); } } diff --git a/runtime/src/admissions_info.c b/runtime/src/admissions_info.c index 77c3417aa..711db9614 100644 --- a/runtime/src/admissions_info.c +++ b/runtime/src/admissions_info.c @@ -9,12 +9,13 @@ extern thread_local struct perf_window perf_window_per_thread[1024]; * @param admissions_info */ void -admissions_info_initialize(struct admissions_info *admissions_info, uint8_t percentile, uint64_t expected_execution, +admissions_info_initialize(struct admissions_info *admissions_info, uint8_t uid, uint8_t percentile, uint64_t expected_execution, uint64_t relative_deadline) { //#ifdef ADMISSIONS_CONTROL assert(relative_deadline > 0); assert(expected_execution > 0); + admissions_info->uid = uid; admissions_info->relative_deadline = relative_deadline; admissions_info->estimate = admissions_control_calculate_estimate(expected_execution, relative_deadline); debuglog("Initial Estimate: %lu\n", admissions_info->estimate); diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c index dd356a48b..67a8d9f37 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c @@ -31,8 +31,8 @@ extern sem_t semlock[1024]; _Atomic uint32_t local_queue_length[1024] = {0}; uint32_t max_local_queue_length[1024] = {0}; uint32_t max_local_queue_height[1024] = {0}; -extern struct perf_window * worker_perf_windows[1024]; -thread_local struct perf_window perf_window_per_thread[1024]; +extern struct perf_window * worker_perf_windows[1024]; // index is worker id +thread_local struct perf_window perf_window_per_thread[1024]; // index is route unique id struct sandbox* current_sandboxes[1024] = { NULL }; extern uint32_t runtime_worker_group_size; From cfad89bcd5243c05a27a64b7295828e935061b44 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Wed, 20 Nov 2024 23:47:46 -0700 Subject: [PATCH 152/198] update increase_req_type.patch --- runtime/increase_req_type.patch | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/runtime/increase_req_type.patch b/runtime/increase_req_type.patch index cb328d347..92424299d 100644 --- a/runtime/increase_req_type.patch +++ b/runtime/increase_req_type.patch @@ -11,7 +11,7 @@ index 7442ea1..04de7fa 100644 void darc_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); void shinjuku_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); diff --git a/runtime/include/http_router.h b/runtime/include/http_router.h -index 5140f0f..8aa30dd 100644 +index b851f45..2925b0d 100644 --- a/runtime/include/http_router.h +++ b/runtime/include/http_router.h @@ -92,7 +92,7 @@ http_router_match_route(http_router_t *router, char *route) @@ -177,7 +177,7 @@ index 14b7aef..6515015 100644 if (tenant_config_set_key_once(did_set, tenant_config_member_routes) == -1) return -1; diff --git a/runtime/include/tenant_functions.h b/runtime/include/tenant_functions.h -index cfcae1d..0e781ed 100644 +index 65cb23e..f1c4c66 100644 --- a/runtime/include/tenant_functions.h +++ b/runtime/include/tenant_functions.h @@ -21,7 +21,7 @@ extern thread_local uint32_t n_rtypes; @@ -352,7 +352,7 @@ index cfcae1d..0e781ed 100644 } diff --git a/runtime/src/admissions_info.c b/runtime/src/admissions_info.c -index 77c3417..f9837df 100644 +index 711db96..443b227 100644 --- a/runtime/src/admissions_info.c +++ b/runtime/src/admissions_info.c @@ -3,7 +3,7 @@ @@ -378,10 +378,10 @@ index df5a420..7a4ad87 100644 if (first_request_comming == false){ t_start = time(NULL); diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c -index dd356a4..26ce73b 100644 +index 67a8d9f..fab3f6b 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c -@@ -24,16 +24,16 @@ +@@ -24,16 +24,17 @@ * Worker Thread State * **************************/ @@ -392,8 +392,8 @@ index dd356a4..26ce73b 100644 -_Atomic uint32_t local_queue_length[1024] = {0}; -uint32_t max_local_queue_length[1024] = {0}; -uint32_t max_local_queue_height[1024] = {0}; --extern struct perf_window * worker_perf_windows[1024]; --thread_local struct perf_window perf_window_per_thread[1024]; +-extern struct perf_window * worker_perf_windows[1024]; // index is worker id +-thread_local struct perf_window perf_window_per_thread[1024]; // index is route unique id -struct sandbox* current_sandboxes[1024] = { NULL }; +extern pthread_mutex_t mutexs[1024]; //maximum index is number of threads +extern pthread_cond_t conds[1024]; //maximum index is number of threads @@ -402,13 +402,14 @@ index dd356a4..26ce73b 100644 +_Atomic uint32_t local_queue_length[1024] = {0}; //maximum index is number of threads +uint32_t max_local_queue_length[1024] = {0}; //maximum index is number of threads +uint32_t max_local_queue_height[1024] = {0}; //maximum index is number of threads -+extern struct perf_window * worker_perf_windows[1024]; //maximum index is the number of modules -+thread_local struct perf_window *perf_window_per_thread = NULL; // maximum index is the number of modules ++extern struct perf_window * worker_perf_windows[1024]; //index is worker id. maximum index is the number of threads ++//thread_local struct perf_window perf_window_per_thread[1024]; // index is route unique id ++thread_local struct perf_window *perf_window_per_thread = NULL; //index is route unique id, maximum index is the number of modules +struct sandbox* current_sandboxes[1024] = { NULL }; //maximum index is number of threads extern uint32_t runtime_worker_group_size; extern FILE *sandbox_perf_log; -@@ -101,7 +101,8 @@ worker_thread_main(void *argument) +@@ -101,7 +102,8 @@ worker_thread_main(void *argument) // runtime_set_pthread_prio(pthread_self(), 2); pthread_setschedprio(pthread_self(), -20); From c67ab8a27780dfa68ef0584fe7eaa3c0a97c4f37 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Sat, 23 Nov 2024 23:38:07 -0700 Subject: [PATCH 153/198] add comment code for shinjuku, won't changge performance --- runtime/src/listener_thread.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index df5a42068..0aa16d66c 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -882,7 +882,8 @@ void shinjuku_dispatch_different_core() { } /* core is idle */ - if ((1 << i) & free_workers[dispatcher_thread_idx]) { + //if ((1 << i) & free_workers[dispatcher_thread_idx]) { + if (local_runqueue_get_length_index(worker_list[i]) == 0) { struct sandbox *sandbox = shinjuku_select_sandbox(); if (!sandbox) return; // queue is empty @@ -936,6 +937,7 @@ void shinjuku_dispatch() { if (local_runqueue_get_length_index(worker_list[true_idx]) == 0) { struct sandbox *sandbox = shinjuku_select_sandbox(); if (!sandbox) return; // queue is empty + //while (sandbox->global_worker_thread_idx != -1 && sandbox->global_worker_thread_idx != worker_list[true_idx]) { while (sandbox->global_worker_thread_idx != -1) { sandbox->start_ts = __getcycles(); local_runqueue_add_index(sandbox->global_worker_thread_idx, sandbox); @@ -959,6 +961,7 @@ void shinjuku_dispatch() { struct sandbox *sandbox = shinjuku_select_sandbox(); if (!sandbox) return; // queue is empty + //while (sandbox->global_worker_thread_idx != -1 && sandbox->global_worker_thread_idx != worker_list[true_idx]) { while (sandbox->global_worker_thread_idx != -1) { sandbox->start_ts = __getcycles(); local_runqueue_add_index(sandbox->global_worker_thread_idx, sandbox); From f16ce515113e66dc4d41f3a6e94bb5a9ee5bd6f0 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 26 Nov 2024 16:44:06 -0700 Subject: [PATCH 154/198] add total received requests count log --- runtime/src/listener_thread.c | 5 ++++- runtime/src/software_interrupt.c | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 0aa16d66c..474631aa7 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -60,13 +60,13 @@ thread_local uint32_t current_reserved = 0; thread_local uint32_t dispatcher_try_interrupts = 0; thread_local uint32_t worker_start_id; thread_local uint32_t worker_end_id; +uint64_t requests_counter[MAX_DISPATCHER][MAX_REQUEST_TYPE] = {0}; thread_local uint32_t worker_list[MAX_WORKERS]; // record the worker's true id(0 - N workers - 1). worker_list[0] - worker_list[2] _Atomic uint32_t free_workers[MAX_DISPATCHER] = {0}; // the index is the dispatercher id, free_workers[dispatcher_id] // is decimal value of the bitmap of avaliable workers. // For example, if there are 3 workers available, the bitmap // will be 111, then the free_workers[dispatcher_id] is 7 - thread_local struct request_typed_queue *request_type_queue[MAX_REQUEST_TYPE]; // key is group ID thread_local struct request_typed_deque *request_type_deque[MAX_REQUEST_TYPE]; @@ -502,6 +502,7 @@ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, } total_requests++; + requests_counter[dispatcher_thread_idx][req_type]++; /* Allocate a Sandbox */ //session->state = HTTP_SESSION_EXECUTING; struct sandbox *sandbox = sandbox_alloc(route->module, NULL, route, tenant, work_admitted, req_handle, dispatcher_thread_idx); @@ -655,6 +656,7 @@ void darc_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t s } total_requests++; + requests_counter[dispatcher_thread_idx][req_type]++; /* Allocate a Sandbox */ //session->state = HTTP_SESSION_EXECUTING; struct sandbox *sandbox = sandbox_alloc(route->module, NULL, route, tenant, work_admitted, req_handle, dispatcher_thread_idx); @@ -718,6 +720,7 @@ void shinjuku_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size } total_requests++; + requests_counter[dispatcher_thread_idx][req_type]++; /* Allocate a Sandbox */ //session->state = HTTP_SESSION_EXECUTING; struct sandbox *sandbox = sandbox_alloc(route->module, NULL, route, tenant, work_admitted, req_handle, dispatcher_thread_idx); diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index 58be8f9dc..209e80032 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -46,6 +46,7 @@ extern thread_local int global_worker_thread_idx; extern thread_local bool pthread_stop; extern thread_local bool is_listener; extern thread_local uint32_t total_complete_requests; +extern uint64_t requests_counter[MAX_DISPATCHER][MAX_REQUEST_TYPE]; thread_local _Atomic volatile sig_atomic_t handler_depth = 0; thread_local _Atomic volatile sig_atomic_t deferred_sigalrm = 0; @@ -260,6 +261,11 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void double arriving_rate = total_requests / seconds; printf("%d try preempts:%u max global queue %u arriving rate %f total requests %lu\n", dispatcher_thread_idx, dispatcher_try_interrupts, max_queue_length, arriving_rate, total_requests); + for (int i = 0; i < MAX_REQUEST_TYPE; i++) { + if (requests_counter[dispatcher_thread_idx][i] != 0) { + mem_log("type %d total requests %lu\n", i, requests_counter[dispatcher_thread_idx][i]); + } + } //mem_log("%d try preempts:%u max global queue %u arriving rate %f total requests %lu\n", dispatcher_thread_idx, // dispatcher_try_interrupts, max_queue_length, arriving_rate, total_requests); dump_log_to_file(); From 5379e5cfa0d44989795c074e5cf74a2c0d35e6fc Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 26 Nov 2024 16:47:19 -0700 Subject: [PATCH 155/198] update parse script, upload scp.sh --- runtime/tests/meet_deadline_percentage.py | 13 ++++- runtime/tests/parse_batch.py | 62 ++++++++++++++++++++++- runtime/tests/scp.sh | 29 +++++++++++ runtime/tests/vision_apps.json | 53 ++++--------------- 4 files changed, 110 insertions(+), 47 deletions(-) create mode 100755 runtime/tests/scp.sh diff --git a/runtime/tests/meet_deadline_percentage.py b/runtime/tests/meet_deadline_percentage.py index 2c3eb1570..ea2b175fb 100644 --- a/runtime/tests/meet_deadline_percentage.py +++ b/runtime/tests/meet_deadline_percentage.py @@ -3,6 +3,12 @@ from collections import defaultdict import numpy as np +weights_dict = { + '1': 0.99, + '2': 0.09, + '3': 0.01 +} + def def_list_value(): return [0, 0, 0, 0, 0] def def_value(): @@ -141,18 +147,21 @@ def count_miss_or_meet_deadline_requests(file_dir, percentage): p = np.percentile(a, int(percentage)) print(key + " " + percentage + " percentile is:" + str(p) + " mean is:" + str(np.mean(value)) + " max latency is:" + str(max_latency_dist[key])) #total_cpu_times = 0 + weighted_miss_rate = 0 for key,value in meet_deadline_dist.items(): # total_cpu_times += value * fun_execution_time[key] miss_value = miss_deadline_dist[key] total_request = miss_value + value miss_rate = (miss_value * 100) / total_request + weighted_miss_rate = weighted_miss_rate + miss_rate * weights_dict[key] - print("type ", key, " miss deadline rate:", str(miss_rate)); + print("type ", key, " miss deadline rate:", str(miss_rate)); + print("type ", key, " total meet requests:", str(value), " total miss requests:", str(miss_value)) # print(func_name_dict[key] + " miss deadline rate:" + str(miss_rate) + " miss count is:" + str(miss_value) + " total request:" + str(total_request)) #print("effective total cpu times:", total_cpu_times) #for key,value in real_time_workload_times_dist.items(): # real_time_workload_times_dist[key] = [x - min_time for x in value] - + print("weighted miss rate:", weighted_miss_rate) for key,value in running_times.items(): #print("function times:", func_name_with_id[key], np.median(total_times[key]), np.median(running_times[key]), np.median(queuing_times[key]), np.median(runnable_times[key]), np.median(blocked_times[key]), np.median(initializing_times[key])) print("function :", key, "median total:", np.median(total_time_dist[key]), "exec:", np.median(running_times[key]), "queue:", np.median(queuing_times[key])) diff --git a/runtime/tests/parse_batch.py b/runtime/tests/parse_batch.py index cf65ce7a7..a6fb22190 100644 --- a/runtime/tests/parse_batch.py +++ b/runtime/tests/parse_batch.py @@ -4,8 +4,12 @@ from collections import defaultdict miss_rate_dict = defaultdict(lambda: defaultdict(list)) +seperate_meet_dict = defaultdict(lambda: defaultdict(list)) +total_meet_dict = defaultdict(list) total_miss_rate_dict = defaultdict(list) +weighted_miss_rate_dict = defaultdict(list) load_dict = defaultdict(int) +total_requests_dict = defaultdict(list) #get all file names which contain key_str def file_name(file_dir, key_str): @@ -30,9 +34,18 @@ def file_name(file_dir, key_str): file_list.append(full_path) rps_list.append(int(rps)) - pattern = r"server-(\d+)-\d+\.log" - file_list = sorted(file_list, key=lambda x: int(re.search(pattern, x).group(1))) + #pattern = r"server-(\d+\.?\d*)-\d+\.log" + pattern = r"server-(\d+)-\d+(\.\d+)?\.log" + + for file in file_list: + match = re.search(pattern, file) + if match: + print(f"Matched: {file}, RPS: {match.group(1)}") + else: + print(f"Not Matched: {file}", file) + + file_list = sorted(file_list, key=lambda x: float(re.search(pattern, x).group(1))) rps_list = sorted(rps_list) #print(file_list) print("--------------------------------", rps_list) @@ -52,7 +65,11 @@ def get_values(key, files_list, latency_dict, slow_down_dict, slow_down_99_9_dic slow_down_99_99_rule = r'99.99 percentile slow down is\s*([\d.]+)' miss_rate_rule = r"type\s+(\d+)\s+miss\s+deadline\s+rate:\s+([\d.]+)" + total_meet_requests_rule = r"type\s+(\d+)\s+total\s+meet\s+requests:\s+([\d.]+)" + total_requests_rule = r"type\s+(\d+)\s+meet\s+requests:\s+([\d.]+)" total_miss_rate_rule = r"miss\s+deadline\s+percentage:\s+([\d.]+)" + weighted_miss_rate_rule = r"weighted\s+miss\s+rate:\s+([\d.]+)" + #total_requests_rule = r"total\s+requests:\s+([\d.]+)" # Use the regular expressions to find the values latency_match = re.search(latency_rule, rt) @@ -62,6 +79,8 @@ def get_values(key, files_list, latency_dict, slow_down_dict, slow_down_99_9_dic latency_99_99_match = re.search(latency_99_99_rule, rt) slow_down_99_99_match = re.search(slow_down_99_99_rule, rt) total_miss_rate_match = re.search(total_miss_rate_rule, rt) + weighted_miss_rate_match = re.search(weighted_miss_rate_rule, rt) + total_requests_match = re.search(total_requests_rule, rt) # Check if matches were found and extract the values if latency_match: @@ -106,6 +125,25 @@ def get_values(key, files_list, latency_dict, slow_down_dict, slow_down_99_9_dic print("total miss rate for ", key, " is:", total_miss_rate) total_miss_rate_dict[key].append(total_miss_rate) + if weighted_miss_rate_match: + weighted_miss_rate = 0 + weighted_miss_rate = weighted_miss_rate_match.group(1) + print("weighted miss rate for ", key, " is:", weighted_miss_rate) + weighted_miss_rate_dict[key].append(weighted_miss_rate) + + total_meet = 0 + for match in re.finditer(total_meet_requests_rule, rt): + r_type, meet_requests = match.groups() + print("type:", r_type, "meet requests:", meet_requests) + total_meet = total_meet + int(meet_requests) + seperate_meet_dict[key][int(r_type)].append(meet_requests) + total_meet_dict[key].append(total_meet) + if total_requests_match: + total_requests = 0 + total_requests = total_requests_match.group(1) + print("total request for ", key, " is:", total_requests) + total_requests_dict[key].append(total_requests) + for match in re.finditer(miss_rate_rule, rt): r_type, miss_rate = match.groups() print("type:", r_type, "miss rate:", miss_rate) @@ -116,6 +154,7 @@ def get_values(key, files_list, latency_dict, slow_down_dict, slow_down_99_9_dic import json #file_folders = ['SHINJUKU', 'SHINJUKU_25', 'DARC', 'EDF_SRSF_INTERRUPT'] file_folders = ['SHINJUKU', 'DARC', 'EDF_INTERRUPT'] + #file_folders = ['SHINJUKU'] latency = defaultdict(list) slow_down = defaultdict(list) slow_down_99_9 = defaultdict(list) @@ -192,3 +231,22 @@ def get_values(key, files_list, latency_dict, slow_down_dict, slow_down_99_9_dic f10.write(js10) f10.close() + js11 = json.dumps(weighted_miss_rate_dict) + f11 = open("weighted_miss_rate.txt", 'w') + f11.write(js11) + f11.close() + + js12 = json.dumps(total_requests_dict) + f12 = open("total_requests.txt", 'w') + f12.write(js12) + f12.close() + + js13 = json.dumps(total_meet_dict) + f13 = open("total_meet.txt", 'w') + f13.write(js13) + f13.close() + + js14 = json.dumps(seperate_meet_dict) + f14 = open("seperate_meet.txt", 'w') + f14.write(js14) + f14.close() diff --git a/runtime/tests/scp.sh b/runtime/tests/scp.sh new file mode 100755 index 000000000..60e8dfbc6 --- /dev/null +++ b/runtime/tests/scp.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +if [ "$#" -lt 2 ]; then + echo "Usage: $0 target_path file1 [file2 ... fileN]" + exit 1 +fi + +TARGET_DIR="$1" +shift # remove first parameter, so $@ is the file list + +PRIVATE_KEY="/my_mount/sledge-serverless-framework/runtime/tests/id_rsa" +TARGET_USER="xiaosuGW" +TARGET_HOST="10.10.1.2" + +chmod 400 "$PRIVATE_KEY" + +#loop copy +for file in "$@"; do + if [ -f "$file" ]; then + scp -i "$PRIVATE_KEY" "$file" "$TARGET_USER@$TARGET_HOST:$TARGET_DIR" + if [ $? -eq 0 ]; then + echo "Successfully copied $file to $TARGET_DIR" + else + echo "Failed to copy $file to $TARGET_DIR" + fi + else + echo "File $file does not exist, skipping." + fi +done diff --git a/runtime/tests/vision_apps.json b/runtime/tests/vision_apps.json index 9a379b12b..1b6ba42c9 100644 --- a/runtime/tests/vision_apps.json +++ b/runtime/tests/vision_apps.json @@ -5,70 +5,37 @@ "replenishment-period-us": 0, "max-budget-us": 0, "routes": [ - { - "route": "/tracking", - "request-type": 1, - "n-resas": 1, - "group-id": 1, - "path": "tracking.wasm.so", - "admissions-percentile": 70, - "expected-execution-us": 6, - "relative-deadline-us": 60, - "http-resp-content-type": "text/plain" - }, - { - "route": "/disparity", - "request-type": 2, - "n-resas": 1, - "group-id": 1, - "path": "disparity.wasm.so", - "admissions-percentile": 70, - "expected-execution-us": 11, - "relative-deadline-us": 110, - "http-resp-content-type": "text/plain" - }, - { - "route": "/mser", - "request-type": 3, - "n-resas": 1, - "group-id": 1, - "path": "mser.wasm.so", - "admissions-percentile": 70, - "expected-execution-us": 16, - "relative-deadline-us": 160, - "http-resp-content-type": "text/plain" - }, { "route": "/sift", - "request-type": 4, - "n-resas": 1, + "request-type": 1, + "n-resas": 3, "group-id": 1, "path": "sift.wasm.so", "admissions-percentile": 70, "expected-execution-us": 113, - "relative-deadline-us": 1130, + "relative-deadline-us": 11300, "http-resp-content-type": "text/plain" }, { "route": "/multi_ncut", - "request-type": 5, - "n-resas": 1, + "request-type": 2, + "n-resas": 2, "group-id": 2, "path": "multi_ncut.wasm.so", "admissions-percentile": 70, - "expected-execution-us": 326, - "relative-deadline-us": 3260, + "expected-execution-us": 1100, + "relative-deadline-us": 2200, "http-resp-content-type": "text/plain" }, { "route": "/cifar10", - "request-type": 6, - "n-resas": 6, + "request-type": 3, + "n-resas": 1, "group-id": 3, "path": "cifar10.wasm.so", "admissions-percentile": 70, "expected-execution-us": 2060, - "relative-deadline-us": 20600, + "relative-deadline-us": 4120, "http-resp-content-type": "text/plain" } From 98315a984be079ff009029f81203ea7312306032 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Mon, 2 Dec 2024 10:44:44 -0700 Subject: [PATCH 156/198] upload vision_apps_same_6apps.json and apps_Makefile --- runtime/tests/apps_Makefile | 159 ++++++++++++++++++++++ runtime/tests/vision_apps_same_6apps.json | 80 +++++++++++ 2 files changed, 239 insertions(+) create mode 100644 runtime/tests/apps_Makefile create mode 100644 runtime/tests/vision_apps_same_6apps.json diff --git a/runtime/tests/apps_Makefile b/runtime/tests/apps_Makefile new file mode 100644 index 000000000..4bf96144c --- /dev/null +++ b/runtime/tests/apps_Makefile @@ -0,0 +1,159 @@ +AWSMCC=../awsm/target/release/awsm +CC=clang + +# Used by aWsm when compiling the *.wasm to *.bc +AWSMFLAGS= --inline-constant-globals --runtime-globals + +# Used by clang when compiling the *.so module +# --whole-archive causes the symbols in the listed static archive to be exported from the resulting *.so +# https://stackoverflow.com/questions/805555/ld-linker-question-the-whole-archive-option +CFLAGS=-O3 -flto +LDFLAGS=-shared -fPIC -Wl,--export-dynamic,--whole-archive -L../libsledge/dist/ -lsledge -Wl,--no-whole-archive +# LDFLAGS=-flto -fvisibility=hidden + +# Strips out calls to assert() and disables debuglog +CFLAGS+=-DNDEBUG + +dist: + mkdir -p dist + +.PHONY: all +all: \ + cifar10.install \ + resize_image.install \ + dummy_tpcc.install \ + hash.install \ + sift.install \ + mser.install \ + multi_ncut.install \ + disparity.install \ + tracking.install \ + empty.install \ + fibonacci.install \ + #gocr.install \ + #gps_ekf.install \ + #license_plate_detection.install \ + #resize_image.install \ + #scratch_storage_get.install \ + #scratch_storage_set.install \ + #scratch_storage_delete.install \ + #scratch_storage_upsert.install \ + +.PHONY: clean +clean: + @make -C wasm_apps clean + @make -C scratch_storage clean + @rm -rf dist + @rm -rf ../runtime/bin/*.so + +wasm_apps/dist/%.wasm: + make -C wasm_apps $(addprefix dist/,$(notdir $@)) + +../libsledge/dist/: + mkdir ../libsledge/dist + +../libsledge/dist/libsledge.a: ../libsledge/dist/ + make -C .. libsledge + +PHONY: scratch_storage +scratch_storage: + make -C scratch_storage all + +PHONY: scratch_storage.install +scratch_storage.install: \ + scratch_storage_get.install \ + scratch_storage_set.install \ + scratch_storage_delete.install \ + scratch_storage_upsert.install + +scratch_storage/scratch_storage_%.wasm: + make -C scratch_storage all + +dist/scratch_storage_%.bc: scratch_storage/scratch_storage_%.wasm dist + ${AWSMCC} ${AWSMFLAGS} $< -o $@ + +dist/%.bc: ./wasm_apps/dist/%.wasm dist + ${AWSMCC} ${AWSMFLAGS} $< -o $@ + +dist/%.ll: dist/%.bc + llvm-dis-12 $< -o $@ + +dist/%.wasm.so: dist/%.bc + ${CC} ${CFLAGS} ${LDFLAGS} $^ -o $@ + +../runtime/bin/%.wasm.so: dist/%.wasm.so + cp $^ $@ + +.PHONY: cifar10.install +cifar10.install: ../runtime/bin/cifar10.wasm.so + +# Echo? + +.PHONY: empty.install +empty.install: ../runtime/bin/empty.wasm.so + +.PHONY: exit.install +exit.install: ../runtime/bin/exit.wasm.so + +.PHONY: fibonacci.install +fibonacci.install: ../runtime/bin/fibonacci.wasm.so + +.PHONY: sift.install +sift.install: ../runtime/bin/sift.wasm.so + +.PHONY: mser.install +mser.install: ../runtime/bin/mser.wasm.so + +.PHONY: multi_ncut.install +multi_ncut.install: ../runtime/bin/multi_ncut.wasm.so + +.PHONY: hash.install +hash.install: ../runtime/bin/hash.wasm.so + +.PHONY: dummy_tpcc.install +dummy_tpcc.install: ../runtime/bin/dummy_tpcc.wasm.so + +.PHONY: disparity.install +disparity.install: ../runtime/bin/disparity.wasm.so + +.PHONY: tracking.install +tracking.install: ../runtime/bin/tracking.wasm.so + +.PHONY: asc-fib.install +asc-fib.install: ../runtime/bin/asc-fib.wasm.so + +.PHONY: gocr.install +gocr.install: ../runtime/bin/gocr.wasm.so + +.PHONY: resize_image.install +resize_image.install: ../runtime/bin/resize_image.wasm.so + +.PHONY: gps_ekf.install +gps_ekf.install: ../runtime/bin/gps_ekf.wasm.so + +.PHONY: license_plate_detection.install +license_plate_detection.install: ../runtime/bin/license_plate_detection.wasm.so + +.PHONY: trap_divzero.install +trap_divzero.install: ../runtime/bin/trap_divzero.wasm.so + +.PHONY: stack_overflow.install +stack_overflow.install: ../runtime/bin/stack_overflow.wasm.so + +.PHONY: html.install +html.install: ../runtime/bin/html.wasm.so + +.PHONY: scratch_storage_get.install +scratch_storage_get.install: ../runtime/bin/scratch_storage_get.wasm.so + +.PHONY: scratch_storage_set.install +scratch_storage_set.install: ../runtime/bin/scratch_storage_set.wasm.so + +.PHONY: scratch_storage_delete.install +scratch_storage_delete.install: ../runtime/bin/scratch_storage_delete.wasm.so + +.PHONY: scratch_storage_upsert.install +scratch_storage_upsert.install: ../runtime/bin/scratch_storage_upsert.wasm.so + +.PHONY: depth_to_xyz.install +depth_to_xyz.install: ../runtime/bin/depth_to_xyz.wasm.so diff --git a/runtime/tests/vision_apps_same_6apps.json b/runtime/tests/vision_apps_same_6apps.json new file mode 100644 index 000000000..851666ff6 --- /dev/null +++ b/runtime/tests/vision_apps_same_6apps.json @@ -0,0 +1,80 @@ +[ + { + "name": "gwu", + "port": 31850, + "replenishment-period-us": 0, + "max-budget-us": 0, + "routes": [ + { + "route": "/tracking", + "request-type": 1, + "n-resas": 1, + "group-id": 1, + "path": "tracking.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 6, + "relative-deadline-us": 10000, + "http-resp-content-type": "text/plain" + }, + { + "route": "/disparity", + "request-type": 2, + "n-resas": 1, + "group-id": 1, + "path": "disparity.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 11, + "relative-deadline-us": 10000, + "http-resp-content-type": "text/plain" + }, + { + "route": "/mser", + "request-type": 3, + "n-resas": 1, + "group-id": 1, + "path": "mser.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 16, + "relative-deadline-us": 10000, + "http-resp-content-type": "text/plain" + }, + { + "route": "/sift", + "request-type": 4, + "n-resas": 1, + "group-id": 2, + "path": "sift.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 113, + "relative-deadline-us": 1000, + "http-resp-content-type": "text/plain" + }, + { + "route": "/multi_ncut", + "request-type": 5, + "n-resas": 1, + "group-id": 2, + "path": "multi_ncut.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 326, + "relative-deadline-us": 600, + "http-resp-content-type": "text/plain" + }, + { + "route": "/cifar10", + "request-type": 6, + "n-resas": 6, + "group-id": 3, + "path": "cifar10.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 2060, + "relative-deadline-us": 3000, + "http-resp-content-type": "text/plain" + } + + ] + + } + +] + From c5a3a4f210cdff7912b27b51ef3ac679d87fed86 Mon Sep 17 00:00:00 2001 From: xiaosuGW Date: Sat, 14 Dec 2024 00:06:57 -0700 Subject: [PATCH 157/198] upload change_vision_apps_json.sh, update parse_batch.py --- runtime/tests/change_vision_apps_json.sh | 40 ++++++++++++++++++++++++ runtime/tests/parse_batch.py | 36 +++++++++++++++------ 2 files changed, 66 insertions(+), 10 deletions(-) create mode 100755 runtime/tests/change_vision_apps_json.sh diff --git a/runtime/tests/change_vision_apps_json.sh b/runtime/tests/change_vision_apps_json.sh new file mode 100755 index 000000000..f526bc761 --- /dev/null +++ b/runtime/tests/change_vision_apps_json.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +# 检查参数数量 +if [ $# -ne 3 ]; then + echo "Usage: $0 " + exit 1 +fi + +# 参数赋值 +multiplier=$1 +file_path=$2 +request_type=$3 + +# 创建临时文件 +temp_file=$(mktemp) + +# 读取文件并修改内容 +while IFS= read -r line; do + if echo "$line" | grep -q "\"request-type\": $request_type,"; then + found_request_type=1 + fi + + if [ "$found_request_type" == "1" ] && echo "$line" | grep -q "\"expected-execution-us\": "; then + expected_exec_us=$(echo "$line" | grep -o "[0-9]\+") + fi + + if [ "$found_request_type" == "1" ] && echo "$line" | grep -q "\"relative-deadline-us\": "; then + new_deadline=$((expected_exec_us * multiplier)) + line=$(echo "$line" | sed -E "s/[0-9]+/$new_deadline/") + found_request_type=0 + fi + + echo "$line" >> "$temp_file" +done < "$file_path" + +# 替换原文件 +mv "$temp_file" "$file_path" + +echo "Updated 'relative-deadline-us' for request_type $request_type in $file_path." + diff --git a/runtime/tests/parse_batch.py b/runtime/tests/parse_batch.py index a6fb22190..264c3297e 100644 --- a/runtime/tests/parse_batch.py +++ b/runtime/tests/parse_batch.py @@ -11,11 +11,13 @@ load_dict = defaultdict(int) total_requests_dict = defaultdict(list) + #get all file names which contain key_str def file_name(file_dir, key_str): print(file_dir, key_str) file_list = [] rps_list = [] + last_num_list = [] for root, dirs, files in os.walk(file_dir): print("file:", files) @@ -33,9 +35,10 @@ def file_name(file_dir, key_str): rps=rps.split(".")[0] file_list.append(full_path) rps_list.append(int(rps)) + last_num=segs[2] + last_num=last_num.split(".")[0] + last_num_list.append(int(last_num)) - - #pattern = r"server-(\d+\.?\d*)-\d+\.log" pattern = r"server-(\d+)-\d+(\.\d+)?\.log" for file in file_list: @@ -45,11 +48,15 @@ def file_name(file_dir, key_str): else: print(f"Not Matched: {file}", file) - file_list = sorted(file_list, key=lambda x: float(re.search(pattern, x).group(1))) + file_list_based_throughput = sorted(file_list, key=lambda x: float(re.search(pattern, x).group(1))) rps_list = sorted(rps_list) - #print(file_list) + last_num_list = sorted(last_num_list) + # Sort the list based on the last number in the filename + file_list_based_last_num = sorted(file_list, key=lambda x: int(x.split('-')[-1].split('.')[0])) + + #print(file_list_based_last_num) print("--------------------------------", rps_list) - return file_list, rps_list + return file_list_based_throughput, file_list_based_last_num, rps_list, last_num_list def get_values(key, files_list, latency_dict, slow_down_dict, slow_down_99_9_dict, latency_99_9_dict, slow_down_99_99_dict, latency_99_99_dict): for file_i in files_list: @@ -165,14 +172,18 @@ def get_values(key, files_list, latency_dict, slow_down_dict, slow_down_99_9_dic rps_list = [] argv = sys.argv[1:] - if len(argv) < 1: - print("usage ", sys.argv[0], "[file key]") + if len(argv) < 2: + print("usage ", sys.argv[0], "[file key] [file order, 1 is throughput, 2 is last number]") sys.exit() - + + file_order = argv[1] for key in file_folders: - files_list, rps_list = file_name(key, argv[0]) + files_list, file_list_based_last_num, rps_list, last_num_list = file_name(key, argv[0]) load_dict[key] = rps_list - get_values(key, files_list, latency, slow_down, slow_down_99_9, latency_99_9, slow_down_99_99, latency_99_99) + if file_order == "1": + get_values(key, files_list, latency, slow_down, slow_down_99_9, latency_99_9, slow_down_99_99, latency_99_99) + else: + get_values(key, file_list_based_last_num, latency, slow_down, slow_down_99_9, latency_99_9, slow_down_99_99, latency_99_99) print("99 latency:") for key, value in latency.items(): @@ -250,3 +261,8 @@ def get_values(key, files_list, latency_dict, slow_down_dict, slow_down_99_9_dic f14 = open("seperate_meet.txt", 'w') f14.write(js14) f14.close() + + js15 = json.dumps(last_num_list) + f15 = open("last_num.txt", 'w') + f15.write(js15) + f15.close() From 516bc6fe021473a5eaaacc7fef16d0acb5bb95f5 Mon Sep 17 00:00:00 2001 From: xiaosuGW Date: Thu, 8 May 2025 17:09:59 -0600 Subject: [PATCH 158/198] 1. fix bug: replace calloc with aligned_alloc to allocate struct memory_pool to avoid crash. 2. fix bug: deque access will exceed its bounds, fixed it. 3. add feature: support multiple dispatchers with one global queue(FIFO). All dispatchers put requests to the global queue and each worker get requests from it --- runtime/include/deque.h | 8 +- runtime/include/dispatcher.h | 8 ++ runtime/include/dispatcher_options.h | 10 ++- runtime/include/erpc_handler.h | 1 + runtime/include/http_router.h | 6 +- runtime/include/scheduler.h | 13 +++- runtime/src/global_request_scheduler_deque.c | 9 ++- runtime/src/listener_thread.c | 80 ++++++++++++++++++++ runtime/src/main.c | 18 ++++- runtime/src/runtime.c | 8 +- 10 files changed, 147 insertions(+), 14 deletions(-) diff --git a/runtime/include/deque.h b/runtime/include/deque.h index ee5d62ada..9a6467858 100644 --- a/runtime/include/deque.h +++ b/runtime/include/deque.h @@ -7,6 +7,7 @@ #ifndef DEQUE_H #define DEQUE_H +#include "lock.h" /* * This was implemented by referring to: * https://github.com/cpp-taskflow/cpp-taskflow/blob/9c28ccec910346a9937c40db7bdb542262053f9c/taskflow/executor/workstealing.hpp @@ -30,6 +31,7 @@ \ volatile long top; \ volatile long bottom; \ + lock_t lock; \ }; \ \ static inline void deque_init_##name(struct deque_##name *q, size_t sz) \ @@ -39,7 +41,7 @@ if (sz) { \ /* only for size with pow of 2 */ \ /* assert((sz & (sz - 1)) == 0); */ \ - assert(sz <= DEQUE_MAX_SZ); \ + assert(sz && (sz & (sz - 1)) == 0 && sz <= DEQUE_MAX_SZ); \ } else { \ sz = DEQUE_MAX_SZ; \ } \ @@ -58,7 +60,7 @@ /* nope, fixed size only */ \ if (q->size - 1 < (cb - ct)) return -ENOSPC; \ \ - q->wrk[cb] = *w; \ + q->wrk[cb & (q->size - 1)] = *w; \ __sync_synchronize(); \ if (__sync_bool_compare_and_swap(&q->bottom, cb, cb + 1) == false) assert(0); \ \ @@ -110,7 +112,7 @@ /* Empty */ \ if (ct >= cb) return -ENOENT; \ \ - *w = deque->wrk[ct]; \ + *w = deque->wrk[ct & (deque->size - 1)]; \ if (__sync_bool_compare_and_swap(&deque->top, ct, ct + 1) == false) return -EAGAIN; \ \ return 0; \ diff --git a/runtime/include/dispatcher.h b/runtime/include/dispatcher.h index 522f109de..2c288ec1a 100644 --- a/runtime/include/dispatcher.h +++ b/runtime/include/dispatcher.h @@ -12,6 +12,14 @@ dispatcher_print(enum DISPATCHER variant) return "DARC"; case DISPATCHER_SHINJUKU: return "SHINJUKU"; + case DISPATCHER_TO_GLOBAL_QUEUE: + return "DISPATCHER_TO_GLOBAL_QUEUE"; + case DISPATCHER_RR: + return "DISPATCHER_RR"; + case DISPATCHER_JSQ: + return "DISPATCHER_JSQ"; + case DISPATCHER_LLD: + return "DISPATCHER_LLD"; } } diff --git a/runtime/include/dispatcher_options.h b/runtime/include/dispatcher_options.h index 4b82903e2..167e17924 100644 --- a/runtime/include/dispatcher_options.h +++ b/runtime/include/dispatcher_options.h @@ -2,9 +2,13 @@ enum DISPATCHER { - DISPATCHER_EDF_INTERRUPT = 0, - DISPATCHER_DARC = 1, - DISPATCHER_SHINJUKU = 2, + DISPATCHER_EDF_INTERRUPT = 0, + DISPATCHER_DARC = 1, + DISPATCHER_SHINJUKU = 2, + DISPATCHER_TO_GLOBAL_QUEUE = 3, + DISPATCHER_RR = 4, + DISPATCHER_JSQ = 5, + DISPATCHER_LLD = 6 }; extern enum DISPATCHER dispatcher; diff --git a/runtime/include/erpc_handler.h b/runtime/include/erpc_handler.h index 7442ea10c..b506eb88d 100644 --- a/runtime/include/erpc_handler.h +++ b/runtime/include/erpc_handler.h @@ -4,3 +4,4 @@ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); void darc_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); void shinjuku_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); +void enqueue_to_global_queue_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); diff --git a/runtime/include/http_router.h b/runtime/include/http_router.h index b851f45d9..c8e5a7ebc 100644 --- a/runtime/include/http_router.h +++ b/runtime/include/http_router.h @@ -65,7 +65,11 @@ http_router_add_route(http_router_t *router, struct route_config *config, struct if (erpc_register_req_func(config->request_type, shinjuku_req_handler, 0) != 0) { panic("register erpc function for Shinjuku dispatcher failed\n"); } - } + } else if (dispatcher == DISPATCHER_TO_GLOBAL_QUEUE) { + if (erpc_register_req_func(config->request_type, enqueue_to_global_queue_req_handler, 0) != 0) { + panic("register erpc function for enqueuing to global queue failed\n"); + } + } /* Admissions Control */ uint64_t expected_execution = (uint64_t)config->expected_execution_us * runtime_processor_speed_MHz; diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index fb7f8a271..3beaa7ac4 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -158,8 +158,17 @@ scheduler_fifo_get_next() /* If the local runqueue is empty, pull from global request scheduler */ if (global_request_scheduler_remove(&global) < 0) goto done; - sandbox_prepare_execution_environment(global); - sandbox_set_as_runnable(global, SANDBOX_INITIALIZED); + if (global->state == SANDBOX_INITIALIZED) { + /* add by xiaosu */ + uint64_t now = __getcycles(); + global->timestamp_of.dispatched = now; + global->duration_of_state[SANDBOX_INITIALIZED] = 0; + global->timestamp_of.last_state_change = now; + /* end by xiaosu */ + sandbox_prepare_execution_environment(global); + local_runqueue_add(global); + sandbox_set_as_runnable(global, SANDBOX_INITIALIZED); + } } else if (local == current_sandbox_get()) { /* Execute Round Robin Scheduling Logic if the head is the current sandbox */ local_runqueue_list_rotate(); diff --git a/runtime/src/global_request_scheduler_deque.c b/runtime/src/global_request_scheduler_deque.c index af151b47f..f40280e86 100644 --- a/runtime/src/global_request_scheduler_deque.c +++ b/runtime/src/global_request_scheduler_deque.c @@ -3,7 +3,6 @@ #include "runtime.h" #define GLOBAL_REQUEST_SCHEDULER_DEQUE_CAPACITY (1 << 19) - static struct deque_sandbox *global_request_scheduler_deque; /* TODO: Should this be used??? */ @@ -19,7 +18,14 @@ global_request_scheduler_deque_add(struct sandbox *sandbox) { int return_code = 1; + /* For mulitiple threads calling deque_push_sandbox(), use spin-lock instead of mutex-lock + * to reduce context-switch overhead. + * For single thread calling deque_push_sandbox(), avoid any lock since no race condition + */ + lock_node_t node = {}; + lock_lock(&global_request_scheduler_deque->lock, &node); return_code = deque_push_sandbox(global_request_scheduler_deque, &sandbox); + lock_unlock(&global_request_scheduler_deque->lock, &node); if (return_code != 0) return NULL; return sandbox; @@ -56,6 +62,7 @@ global_request_scheduler_deque_initialize() /* Note: Below is a Macro */ deque_init_sandbox(global_request_scheduler_deque, GLOBAL_REQUEST_SCHEDULER_DEQUE_CAPACITY); + lock_init(&global_request_scheduler_deque->lock); /* Register Function Pointers for Abstract Scheduling API */ struct global_request_scheduler_config config = { .add_fn = global_request_scheduler_deque_add, diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 474631aa7..a8d2fc4b3 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -988,6 +988,75 @@ void shinjuku_dispatch() { } } +void enqueue_to_global_queue_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { + + if (first_request_comming == false){ + t_start = time(NULL); + first_request_comming = true; + } + + uint8_t kMsgSize = 16; + //TODO: rpc_id is hardcode now + + struct tenant *tenant = tenant_database_find_by_port(port); + assert(tenant != NULL); + struct route *route = http_router_match_request_type(&tenant->router, req_type); + if (route == NULL) { + debuglog("Did not match any routes\n"); + dispatcher_send_response(req_handle, DIPATCH_ROUNTE_ERROR, strlen(DIPATCH_ROUNTE_ERROR)); + return; + } + + /* + * Perform admissions control. + * If 0, workload was rejected, so close with 429 "Too Many Requests" and continue + * TODO: Consider providing a Retry-After header + */ + uint64_t work_admitted = admissions_control_decide(route->admissions_info.estimate); + if (work_admitted == 0) { + dispatcher_send_response(req_handle, WORK_ADMITTED_ERROR, strlen(WORK_ADMITTED_ERROR)); + return; + } + + total_requests++; + requests_counter[dispatcher_thread_idx][req_type]++; + /* Allocate a Sandbox */ + //session->state = HTTP_SESSION_EXECUTING; + struct sandbox *sandbox = sandbox_alloc(route->module, NULL, route, tenant, work_admitted, req_handle, dispatcher_thread_idx); + if (unlikely(sandbox == NULL)) { + debuglog("Failed to allocate sandbox\n"); + dispatcher_send_response(req_handle, SANDBOX_ALLOCATION_ERROR, strlen(SANDBOX_ALLOCATION_ERROR)); + return; + } + + /* Reset estimated execution time and relative deadline for exponential service time simulation */ + if (runtime_exponential_service_time_simulation_enabled) { + int exp_num = atoi((const char *)msg); + if (exp_num == 1) { + sandbox->estimated_cost = base_simulated_service_time; + } else { + sandbox->estimated_cost = base_simulated_service_time * exp_num * (1 - LOSS_PERCENTAGE); + } + sandbox->relative_deadline = 10 * sandbox->estimated_cost; + sandbox->absolute_deadline = sandbox->timestamp_of.allocation + sandbox->relative_deadline; + } + + /* copy the received data since it will be released by erpc */ + sandbox->rpc_request_body = malloc(size); + if (!sandbox->rpc_request_body) { + panic("malloc request body failed\n"); + } + + memcpy(sandbox->rpc_request_body, msg, size); + sandbox->rpc_request_body_size = size; + //printf("add request to GQ\n"); + global_request_scheduler_add(sandbox); + global_queue_length++; + if (global_queue_length > max_queue_length) { + max_queue_length = global_queue_length; + } +} + void dispatcher_send_response(void *req_handle, char* msg, size_t msg_len) { erpc_req_response_enqueue(dispatcher_thread_idx, req_handle, msg, msg_len, 1); } @@ -1070,6 +1139,17 @@ listener_thread_main(void *dummy) erpc_run_event_loop_once(dispatcher_thread_idx); // get a group of packets from the NIC and enqueue them to the typed queue shinjuku_dispatch(); //dispatch packets } + } else if (dispatcher == DISPATCHER_TO_GLOBAL_QUEUE) { + printf("to global queeu....\n"); + while (!pthread_stop) { + erpc_run_event_loop_once(dispatcher_thread_idx); + } + } else if (dispatcher == DISPATCHER_RR) { + + } else if (dispatcher == DISPATCHER_JSQ) { + + } else if (dispatcher == DISPATCHER_LLD) { + } /* code will end here with eRPC and won't go to the following implementaion */ diff --git a/runtime/src/main.c b/runtime/src/main.c index cac70074d..714d6e205 100644 --- a/runtime/src/main.c +++ b/runtime/src/main.c @@ -188,7 +188,11 @@ runtime_get_worker_group_size() { char *worker_group_size_raw = getenv("SLEDGE_WORKER_GROUP_SIZE"); if (worker_group_size_raw != NULL) { runtime_worker_group_size = atoi(worker_group_size_raw); - assert(runtime_listener_threads_count * runtime_worker_group_size == runtime_worker_threads_count); + //If scheduler is SCHEDULER_FIFO, there will be one global queue, but might multiple listeners and + //multiple workers, so the listener threads count * worker group size != worker threads count + if (scheduler != SCHEDULER_FIFO) { + assert(runtime_listener_threads_count * runtime_worker_group_size == runtime_worker_threads_count); + } } else { printf("Not specify worker group size, default group size is 1\n"); } @@ -271,8 +275,16 @@ runtime_configure() dispatcher = DISPATCHER_EDF_INTERRUPT; } else if (strcmp(dispatcher_policy, "SHINJUKU") == 0) { dispatcher = DISPATCHER_SHINJUKU; - } else { - panic("Invalid dispatcher policy: %s. Must be {EDF_INTERRUPT|DARC|SHINJUKU\n", dispatcher_policy); + } else if (strcmp(dispatcher_policy, "TO_GLOBAL_QUEUE") == 0) { + dispatcher = DISPATCHER_TO_GLOBAL_QUEUE; + } else if (strcmp(dispatcher_policy, "RR") == 0) { + dispatcher = DISPATCHER_RR; + } else if (strcmp(dispatcher_policy, "JSQ") == 0) { + dispatcher = DISPATCHER_JSQ; + } else if (strcmp(dispatcher_policy, "LLD") == 0) { + dispatcher = DISPATCHER_LLD; + } else { + panic("Invalid dispatcher policy: %s. Must be {EDF_INTERRUPT|DARC|SHINJUKU|TO_GLOBAL_QUEUE|RR|JSQ|LLD\n", dispatcher_policy); } pretty_print_key_value("Dispatcher Policy", "%s\n", dispatcher_print(dispatcher)); diff --git a/runtime/src/runtime.c b/runtime/src/runtime.c index 27ee25ab2..05941ead6 100644 --- a/runtime/src/runtime.c +++ b/runtime/src/runtime.c @@ -133,7 +133,13 @@ runtime_initialize(void) sandbox_state_totals_initialize(); worker_queuing_cost_initialize(); - memory_pools = calloc(runtime_worker_threads_count, sizeof(struct memory_pool)); + memory_pools = aligned_alloc(128, runtime_worker_threads_count * sizeof(struct memory_pool)); + if (!memory_pools) { + perror("aligned_alloc failed"); + exit(1); + } + memset(memory_pools, 0, runtime_worker_threads_count * sizeof(struct memory_pool)); + //memory_pools = calloc(runtime_worker_threads_count, sizeof(struct memory_pool)); runtime_initialize_pools(); /* Setup Scheduler */ From 7ec4f5287be5bb28d3738b03cba26712303b8ed6 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 8 May 2025 18:24:03 -0600 Subject: [PATCH 159/198] update start_test.sh and debug.sh --- runtime/tests/debug.sh | 1 + runtime/tests/start_test.sh | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/runtime/tests/debug.sh b/runtime/tests/debug.sh index f073be052..dc6e20599 100755 --- a/runtime/tests/debug.sh +++ b/runtime/tests/debug.sh @@ -17,6 +17,7 @@ export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=true export SLEDGE_DISABLE_PREEMPTION=true export SLEDGE_SANDBOX_PERF_LOG=$path/server.log export SLEDGE_NWORKERS=1 +#export SLEDGE_SCHEDULER=FIFO export SLEDGE_FIRST_WORKER_COREID=4 export SLEDGE_NLISTENERS=1 export SLEDGE_WORKER_GROUP_SIZE=1 diff --git a/runtime/tests/start_test.sh b/runtime/tests/start_test.sh index d11cf4a19..bd39a6848 100755 --- a/runtime/tests/start_test.sh +++ b/runtime/tests/start_test.sh @@ -2,11 +2,11 @@ ulimit -n 655350 function usage { - echo "$0 [worker num] [listener num] [first worker core id] [dispatcher policy, SHINJUKU or EDF_INTERRUPT or DARC] [server log file] [disable busy loop] [disable autoscaling] [disable service time simulation] [json config]" + echo "$0 [worker num] [listener num] [first worker core id] [dispatcher policy, SHINJUKU, EDF_INTERRUPT, DARC or TO_GLOBAL_QUEUE] [scheduler policy, EDF or FIFO] [server log file] [disable busy loop] [disable autoscaling] [disable service time simulation] [json config]" exit 1 } -if [ $# != 9 ] ; then +if [ $# != 10 ] ; then usage exit 1; fi @@ -15,13 +15,18 @@ worker_num=$1 listener_num=$2 first_worker_core_id=$3 dispatcher_policy=$4 -server_log=$5 -disable_busy_loop=$6 -disable_autoscaling=$7 -disable_service_ts_simulation=$8 -json_config=$9 +scheduler_policy=$5 +server_log=$6 +disable_busy_loop=$7 +disable_autoscaling=$8 +disable_service_ts_simulation=$9 +json_config=${10} -worker_group_size=$((worker_num / listener_num)) +if [ "$scheduler_policy" = "FIFO" ]; then + worker_group_size=1 +else + worker_group_size=$((worker_num / listener_num)) +fi declare project_path="$( cd "$(dirname "$0")/../.." @@ -38,9 +43,10 @@ export SLEDGE_FIRST_WORKER_COREID=$first_worker_core_id export SLEDGE_NWORKERS=$worker_num export SLEDGE_NLISTENERS=$listener_num export SLEDGE_WORKER_GROUP_SIZE=$worker_group_size -export SLEDGE_SCHEDULER=EDF +export SLEDGE_SCHEDULER=$scheduler_policy #export SLEDGE_DISPATCHER=DARC export SLEDGE_DISPATCHER=$dispatcher_policy +export SLEDGE_SCHEDULER=$scheduler_policy #export SLEDGE_DISPATCHER=EDF_INTERRUPT export SLEDGE_SANDBOX_PERF_LOG=$path/$server_log #echo $SLEDGE_SANDBOX_PERF_LOG From 63acc72dbbc69470a77ea255eaf314ff5232759f Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Mon, 12 May 2025 17:04:27 -0600 Subject: [PATCH 160/198] update debug.sh, run_perf.sh, start_func_density_test.sh and Makefile --- runtime/Makefile | 1 + runtime/tests/debug.sh | 7 ++++--- runtime/tests/run_perf.sh | 3 ++- runtime/tests/start_func_density_test.sh | 23 +++++++++++++---------- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/runtime/Makefile b/runtime/Makefile index 607870e7f..8f4fc7648 100644 --- a/runtime/Makefile +++ b/runtime/Makefile @@ -17,6 +17,7 @@ CFLAGS+=-D_GNU_SOURCE CFLAGS+=-DSLEDGE # Release Flags CFLAGS+=-O3 -flto +#CFLAGS+=-O3 -flto -fsanitize=undefined -fno-sanitize-recover=undefined # Debugging Flags # CFLAGS+=-O0 -g3 diff --git a/runtime/tests/debug.sh b/runtime/tests/debug.sh index dc6e20599..4b5becd1e 100755 --- a/runtime/tests/debug.sh +++ b/runtime/tests/debug.sh @@ -11,19 +11,20 @@ declare project_path="$( path=`pwd` echo $project_path cd $project_path/runtime/bin -export SLEDGE_DISABLE_BUSY_LOOP=true +export SLEDGE_DISABLE_BUSY_LOOP=false export SLEDGE_DISABLE_AUTOSCALING=true export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=true export SLEDGE_DISABLE_PREEMPTION=true export SLEDGE_SANDBOX_PERF_LOG=$path/server.log export SLEDGE_NWORKERS=1 -#export SLEDGE_SCHEDULER=FIFO export SLEDGE_FIRST_WORKER_COREID=4 export SLEDGE_NLISTENERS=1 export SLEDGE_WORKER_GROUP_SIZE=1 +export SLEDGE_SCHEDULER=FIFO #export SLEDGE_DISPATCHER=DARC -export SLEDGE_DISPATCHER=EDF_INTERRUPT +#export SLEDGE_DISPATCHER=EDF_INTERRUPT #export SLEDGE_DISPATCHER=SHINJUKU +export SLEDGE_DISPATCHER=TO_GLOBAL_QUEUE export LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" #gdb --eval-command="handle SIGUSR1 nostop" \ # --eval-command="set pagination off" \ diff --git a/runtime/tests/run_perf.sh b/runtime/tests/run_perf.sh index 6378983cb..630360fbc 100755 --- a/runtime/tests/run_perf.sh +++ b/runtime/tests/run_perf.sh @@ -16,5 +16,6 @@ output=$1 cpu=$(lscpu | awk '/^Core\(s\) per socket:/ {cores=$4} /^Socket\(s\):/ {sockets=$2} END {print cores * sockets}') last_core=$((cpu - 1)) #get the last core -taskset -c $last_core sudo perf stat -B -e context-switches,cache-references,cache-misses,cycles,instructions,page-faults -p $pid -o $output 2>&1 & +#taskset -c $last_core sudo perf stat -B -e context-switches,cache-references,cache-misses,cycles,instructions,page-faults -p $pid -o $output 2>&1 & +taskset -c $last_core sudo perf stat -e syscalls:sys_enter_mmap,syscalls:sys_enter_mprotect,syscalls:sys_enter_munmap,context-switches -p $pid -o $output 2>&1 & diff --git a/runtime/tests/start_func_density_test.sh b/runtime/tests/start_func_density_test.sh index dab7ea141..edf627a10 100755 --- a/runtime/tests/start_func_density_test.sh +++ b/runtime/tests/start_func_density_test.sh @@ -6,20 +6,23 @@ ulimit -m unlimited sudo sysctl -w vm.max_map_count=262144 function usage { - echo "$0 [worker num] [listener num] [first worker core id] [json file] [server log]" + echo "$0 [dispatcher policy:SHINJUKU, EDF_INTERRUPT, DARC or TO_GLOBAL_QUEUE] [scheduler policy: EDF or FIFO] [disable busy loop] [worker num] [listener num] [first worker core id] [json file] [server log]" exit 1 } -if [ $# != 5 ] ; then +if [ $# != 8 ] ; then usage exit 1; fi -worker_num=$1 -listener_num=$2 -first_worker_core_id=$3 -json_file=$4 -server_log=$5 +dispatcher_policy=$1 +scheduler_policy=$2 +disable_busy_loop=$3 +worker_num=$4 +listener_num=$5 +first_worker_core_id=$6 +json_file=$7 +server_log=$8 worker_group_size=$((worker_num / listener_num)) declare project_path="$( @@ -29,7 +32,7 @@ declare project_path="$( echo $project_path path=`pwd` export SLEDGE_DISABLE_PREEMPTION=true -export SLEDGE_DISABLE_BUSY_LOOP=true +export SLEDGE_DISABLE_BUSY_LOOP=$disable_busy_loop export SLEDGE_DISABLE_AUTOSCALING=true export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=true #export SLEDGE_SIGALRM_HANDLER=TRIAGED @@ -37,10 +40,10 @@ export SLEDGE_FIRST_WORKER_COREID=$first_worker_core_id export SLEDGE_NWORKERS=$worker_num export SLEDGE_NLISTENERS=$listener_num export SLEDGE_WORKER_GROUP_SIZE=$worker_group_size -export SLEDGE_SCHEDULER=EDF +export SLEDGE_SCHEDULER=$scheduler_policy #export SLEDGE_DISPATCHER=DARC #export SLEDGE_DISPATCHER=SHINJUKU -export SLEDGE_DISPATCHER=EDF_INTERRUPT +export SLEDGE_DISPATCHER=$dispatcher_policy export SLEDGE_SANDBOX_PERF_LOG=$path/$server_log #echo $SLEDGE_SANDBOX_PERF_LOG cd $project_path/runtime/bin From 9e4e2ba54b91668f718dd9db3ef8494a2578116c Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Mon, 12 May 2025 17:12:21 -0600 Subject: [PATCH 161/198] update increase_req_type.patch --- runtime/increase_req_type.patch | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/runtime/increase_req_type.patch b/runtime/increase_req_type.patch index 92424299d..08460689d 100644 --- a/runtime/increase_req_type.patch +++ b/runtime/increase_req_type.patch @@ -1,8 +1,8 @@ diff --git a/runtime/include/erpc_handler.h b/runtime/include/erpc_handler.h -index 7442ea1..04de7fa 100644 +index b506eb8..4424a97 100644 --- a/runtime/include/erpc_handler.h +++ b/runtime/include/erpc_handler.h -@@ -1,6 +1,6 @@ +@@ -1,7 +1,7 @@ #pragma once #include @@ -10,11 +10,13 @@ index 7442ea1..04de7fa 100644 +void edf_interrupt_req_handler(void *req_handle, uint16_t req_type, uint8_t *msg, size_t size, uint16_t port); void darc_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); void shinjuku_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); +-void enqueue_to_global_queue_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); ++void enqueue_to_global_queue_req_handler(void *req_handle, uint16_t req_type, uint8_t *msg, size_t size, uint16_t port); diff --git a/runtime/include/http_router.h b/runtime/include/http_router.h -index b851f45..2925b0d 100644 +index c8e5a7e..1ca37b1 100644 --- a/runtime/include/http_router.h +++ b/runtime/include/http_router.h -@@ -92,7 +92,7 @@ http_router_match_route(http_router_t *router, char *route) +@@ -96,7 +96,7 @@ http_router_match_route(http_router_t *router, char *route) } static inline struct route * @@ -365,7 +367,7 @@ index 711db96..443b227 100644 * Initializes perf window * @param admissions_info diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c -index df5a420..7a4ad87 100644 +index a8d2fc4..f4244b7 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -472,7 +472,7 @@ on_client_socket_epoll_event(struct epoll_event *evt) @@ -377,8 +379,17 @@ index df5a420..7a4ad87 100644 if (first_request_comming == false){ t_start = time(NULL); +@@ -988,7 +988,7 @@ void shinjuku_dispatch() { + } + } + +-void enqueue_to_global_queue_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { ++void enqueue_to_global_queue_req_handler(void *req_handle, uint16_t req_type, uint8_t *msg, size_t size, uint16_t port) { + + if (first_request_comming == false){ + t_start = time(NULL); diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c -index 67a8d9f..fab3f6b 100644 +index 67a8d9f..24440e5 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c @@ -24,16 +24,17 @@ @@ -409,13 +420,11 @@ index 67a8d9f..fab3f6b 100644 extern uint32_t runtime_worker_group_size; extern FILE *sandbox_perf_log; -@@ -101,7 +102,8 @@ worker_thread_main(void *argument) +@@ -101,6 +102,7 @@ worker_thread_main(void *argument) // runtime_set_pthread_prio(pthread_self(), 2); pthread_setschedprio(pthread_self(), -20); -- preallocate_memory(); + perf_window_per_thread = (struct perf_window*) malloc(sizeof(struct perf_window) * MODULE_DATABASE_CAPACITY); -+ //preallocate_memory(); + preallocate_memory(); perf_window_init(); condition_variable_init(); - semaphore_init(); From 7036b135ca2bfb7ca0075c006d622037a1f33e1d Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 13 May 2025 13:36:02 -0600 Subject: [PATCH 162/198] update run_perf.sh --- runtime/tests/run_perf.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runtime/tests/run_perf.sh b/runtime/tests/run_perf.sh index 630360fbc..ec238f9e9 100755 --- a/runtime/tests/run_perf.sh +++ b/runtime/tests/run_perf.sh @@ -17,5 +17,6 @@ cpu=$(lscpu | awk '/^Core\(s\) per socket:/ {cores=$4} /^Socket\(s\):/ {sockets= last_core=$((cpu - 1)) #get the last core #taskset -c $last_core sudo perf stat -B -e context-switches,cache-references,cache-misses,cycles,instructions,page-faults -p $pid -o $output 2>&1 & -taskset -c $last_core sudo perf stat -e syscalls:sys_enter_mmap,syscalls:sys_enter_mprotect,syscalls:sys_enter_munmap,context-switches -p $pid -o $output 2>&1 & +#taskset -c $last_core sudo perf stat -e syscalls:sys_enter_mmap,syscalls:sys_enter_mprotect,syscalls:sys_enter_munmap,context-switches -p $pid -o $output 2>&1 & +taskset -c $last_core sudo perf stat -C 4 -e syscalls:sys_enter_mmap,syscalls:sys_enter_mprotect,syscalls:sys_enter_munmap,context-switches -o $output 2>&1 & From 6e8fccfd892b291cece789b2ac09d69baa7ce925 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 15 May 2025 11:26:37 -0600 Subject: [PATCH 163/198] add thread name for dispatcher and worker --- runtime/src/listener_thread.c | 1 + runtime/src/worker_thread.c | 1 + 2 files changed, 2 insertions(+) diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index a8d2fc4b3..1d079be9e 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -1073,6 +1073,7 @@ void dispatcher_send_response(void *req_handle, char* msg, size_t msg_len) { void * listener_thread_main(void *dummy) { + pthread_setname_np(pthread_self(), "dispatcher"); is_listener = true; shinjuku_interrupt_interval = INTERRUPT_INTERVAL * runtime_processor_speed_MHz; base_simulated_service_time = BASE_SERVICE_TIME * runtime_processor_speed_MHz; diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c index 67a8d9f37..70a919ee5 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c @@ -83,6 +83,7 @@ void semaphore_init(){ void * worker_thread_main(void *argument) { + pthread_setname_np(pthread_self(), "worker"); /* Set base context as running */ worker_thread_base_context.variant = ARCH_CONTEXT_VARIANT_RUNNING; From b35cb3ac45f1cd0e410c6f46e9223a268bc3285c Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 16 May 2025 13:14:02 -0600 Subject: [PATCH 164/198] support round robin distributing and EDF scheduling --- runtime/include/erpc_handler.h | 1 + runtime/include/http_router.h | 4 ++ runtime/include/scheduler.h | 9 ++-- runtime/src/listener_thread.c | 80 ++++++++++++++++++++++++++-- runtime/src/local_runqueue.c | 3 ++ runtime/src/local_runqueue_minheap.c | 65 ++++++++++++++++++---- runtime/src/main.c | 2 +- runtime/src/software_interrupt.c | 11 ++++ 8 files changed, 156 insertions(+), 19 deletions(-) diff --git a/runtime/include/erpc_handler.h b/runtime/include/erpc_handler.h index b506eb88d..08e97979b 100644 --- a/runtime/include/erpc_handler.h +++ b/runtime/include/erpc_handler.h @@ -5,3 +5,4 @@ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, void darc_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); void shinjuku_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); void enqueue_to_global_queue_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); +void rr_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); diff --git a/runtime/include/http_router.h b/runtime/include/http_router.h index c8e5a7ebc..b3ac71d65 100644 --- a/runtime/include/http_router.h +++ b/runtime/include/http_router.h @@ -69,6 +69,10 @@ http_router_add_route(http_router_t *router, struct route_config *config, struct if (erpc_register_req_func(config->request_type, enqueue_to_global_queue_req_handler, 0) != 0) { panic("register erpc function for enqueuing to global queue failed\n"); } + } else if (dispatcher == DISPATCHER_RR) { + if (erpc_register_req_func(config->request_type, rr_req_handler, 0) != 0) { + panic("register erpc function for round robain distribution failed\n"); + } } /* Admissions Control */ diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index 3beaa7ac4..2b8545615 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -230,9 +230,10 @@ scheduler_runqueue_initialize() case SCHEDULER_EDF: if (dispatcher == DISPATCHER_SHINJUKU || dispatcher == DISPATCHER_DARC) { local_runqueue_circular_queue_initialize(); - } else { - //local_runqueue_minheap_initialize(); + } else if (dispatcher == DISPATCHER_EDF_INTERRUPT) { local_runqueue_binary_tree_initialize(); + } else { + local_runqueue_minheap_initialize(); } break; case SCHEDULER_FIFO: @@ -385,8 +386,8 @@ scheduler_preemptive_sched(ucontext_t *interrupted_context) /* Assumption: the current sandbox is on the runqueue, so the scheduler should always return something */ assert(next != NULL); - /* If current equals next, no switch is necessary, or its RS <= 0, just resume execution */ - if (interrupted_sandbox == next || interrupted_sandbox->srsf_remaining_slack <= 0) { + /* If current equals next, no switch is necessary, or currend deadline is ealier than the next deadline or its RS <= 0, just resume execution */ + if (interrupted_sandbox == next || interrupted_sandbox->absolute_deadline <= next->absolute_deadline || interrupted_sandbox->srsf_remaining_slack <= 0) { sandbox_interrupt_return(interrupted_sandbox, SANDBOX_RUNNING_USER); return; } diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 1d079be9e..2246a810f 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -56,6 +56,7 @@ extern _Atomic uint64_t request_index; extern uint32_t runtime_worker_group_size; extern struct sandbox* current_sandboxes[1024]; +thread_local uint32_t rr_index = 0; thread_local uint32_t current_reserved = 0; thread_local uint32_t dispatcher_try_interrupts = 0; thread_local uint32_t worker_start_id; @@ -619,6 +620,73 @@ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, } } +void rr_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { + + if (first_request_comming == false){ + t_start = time(NULL); + first_request_comming = true; + } + + uint8_t kMsgSize = 16; + + struct tenant *tenant = tenant_database_find_by_port(port); + assert(tenant != NULL); + struct route *route = http_router_match_request_type(&tenant->router, req_type); + if (route == NULL) { + debuglog("Did not match any routes\n"); + dispatcher_send_response(req_handle, DIPATCH_ROUNTE_ERROR, strlen(DIPATCH_ROUNTE_ERROR)); + return; + } + + /* + * Perform admissions control. + * If 0, workload was rejected, so close with 429 "Too Many Requests" and continue + * TODO: Consider providing a Retry-After header + */ + uint64_t work_admitted = admissions_control_decide(route->admissions_info.estimate); + if (work_admitted == 0) { + dispatcher_send_response(req_handle, WORK_ADMITTED_ERROR, strlen(WORK_ADMITTED_ERROR)); + return; + } + + total_requests++; + requests_counter[dispatcher_thread_idx][req_type]++; + /* Allocate a Sandbox */ + //session->state = HTTP_SESSION_EXECUTING; + struct sandbox *sandbox = sandbox_alloc(route->module, NULL, route, tenant, work_admitted, req_handle, dispatcher_thread_idx); + if (unlikely(sandbox == NULL)) { + debuglog("Failed to allocate sandbox\n"); + dispatcher_send_response(req_handle, SANDBOX_ALLOCATION_ERROR, strlen(SANDBOX_ALLOCATION_ERROR)); + return; + } + + /* Reset estimated execution time and relative deadline for exponential service time simulation */ + if (runtime_exponential_service_time_simulation_enabled) { + int exp_num = atoi((const char *)msg); + if (exp_num == 1) { + sandbox->estimated_cost = base_simulated_service_time; + } else { + sandbox->estimated_cost = base_simulated_service_time * exp_num * (1 - LOSS_PERCENTAGE); + } + sandbox->relative_deadline = 10 * sandbox->estimated_cost; + sandbox->absolute_deadline = sandbox->timestamp_of.allocation + sandbox->relative_deadline; + } + + /* copy the received data since it will be released by erpc */ + sandbox->rpc_request_body = malloc(size); + if (!sandbox->rpc_request_body) { + panic("malloc request body failed\n"); + } + + memcpy(sandbox->rpc_request_body, msg, size); + sandbox->rpc_request_body_size = size; + + if (rr_index == worker_end_id + 1) { + rr_index = worker_start_id; + } + local_runqueue_add_index(rr_index, sandbox); + rr_index++; +} /** * @brief Request routing function * @param req_handle used by eRPC internal, it is used to send out the response packet @@ -1092,21 +1160,22 @@ listener_thread_main(void *dummy) /* calucate the worker start and end id for this listener */ worker_start_id = dispatcher_thread_idx * runtime_worker_group_size; - worker_end_id = worker_start_id + runtime_worker_group_size; + worker_end_id = worker_start_id + runtime_worker_group_size - 1; int index = 0; - for (uint32_t i = worker_start_id; i < worker_end_id; i++) { + for (uint32_t i = worker_start_id; i <= worker_end_id; i++) { worker_list[index] = i; index++; } + rr_index = worker_start_id; if (runtime_autoscaling_enabled) { current_active_workers = 1; } else { current_active_workers = runtime_worker_group_size; } printf("listener %d worker_start_id %d worker_end_id %d active worker %d\n", - dispatcher_thread_idx, worker_start_id, worker_end_id - 1, current_active_workers); + dispatcher_thread_idx, worker_start_id, worker_end_id, current_active_workers); free_workers[dispatcher_thread_idx] = __builtin_powi(2, current_active_workers) - 1; @@ -1146,7 +1215,10 @@ listener_thread_main(void *dummy) erpc_run_event_loop_once(dispatcher_thread_idx); } } else if (dispatcher == DISPATCHER_RR) { - + printf("RR....\n"); + while (!pthread_stop) { + erpc_run_event_loop_once(dispatcher_thread_idx); + } } else if (dispatcher == DISPATCHER_JSQ) { } else if (dispatcher == DISPATCHER_LLD) { diff --git a/runtime/src/local_runqueue.c b/runtime/src/local_runqueue.c index 5dc576c14..6a7e3d6f5 100644 --- a/runtime/src/local_runqueue.c +++ b/runtime/src/local_runqueue.c @@ -115,6 +115,7 @@ local_runqueue_is_empty_index(int index) */ int local_runqueue_get_height() { + assert(local_runqueue.get_height_fn != NULL); return local_runqueue.get_height_fn(); } @@ -122,9 +123,11 @@ int local_runqueue_get_height() { * Get total count of items in the queue */ int local_runqueue_get_length() { + assert(local_runqueue.get_length_fn != NULL); return local_runqueue.get_length_fn(); } int local_runqueue_get_length_index(int index) { + assert(local_runqueue.get_length_fn_idx != NULL); return local_runqueue.get_length_fn_idx(index); } /** diff --git a/runtime/src/local_runqueue_minheap.c b/runtime/src/local_runqueue_minheap.c index 8398ff220..8caab41f9 100644 --- a/runtime/src/local_runqueue_minheap.c +++ b/runtime/src/local_runqueue_minheap.c @@ -13,6 +13,7 @@ #include "runtime.h" extern struct priority_queue* worker_queues[1024]; +extern _Atomic uint32_t local_queue_length[1024]; extern thread_local int global_worker_thread_idx; _Atomic uint64_t worker_queuing_cost[1024]; /* index is thread id, each queue's total execution cost of queuing requests */ extern struct perf_window * worker_perf_windows[1024]; /* index is thread id, each queue's perf windows, each queue can @@ -31,6 +32,19 @@ local_runqueue_minheap_is_empty() return priority_queue_length(local_runqueue_minheap) == 0; } +/** + * Checks if the run queue is empty + * @returns true if empty. false otherwise + */ +bool +local_runqueue_minheap_is_empty_index(int index) +{ + struct priority_queue *local_queue = worker_queues[index]; + assert(local_queue != NULL); + + return priority_queue_length(local_queue) == 0;; +} + /** * Adds a sandbox to the run queue * @param sandbox @@ -53,13 +67,35 @@ local_runqueue_minheap_add_index(int index, struct sandbox *sandbox) panic("add request to local queue failed, exit\n"); } + atomic_fetch_add(&local_queue_length[index], 1); uint32_t uid = sandbox->route->admissions_info.uid; - uint64_t estimated_execute_cost = perf_window_get_percentile(&worker_perf_windows[index][uid], - sandbox->route->admissions_info.percentile, + + /* Set estimated exeuction time for the sandbox */ + if (runtime_exponential_service_time_simulation_enabled == false) { + uint32_t uid = sandbox->route->admissions_info.uid; + uint64_t estimated_execute_cost = perf_window_get_percentile(&worker_perf_windows[index][uid], + sandbox->route->admissions_info.percentile, sandbox->route->admissions_info.control_index); + /* Use expected execution time in the configuration file as the esitmated execution time + if estimated_execute_cost is 0 + */ + if (estimated_execute_cost == 0) { + estimated_execute_cost = sandbox->route->expected_execution_cycle; + } + sandbox->estimated_cost = estimated_execute_cost; + sandbox->relative_deadline = sandbox->route->relative_deadline; + } + + /* Record TS and calcuate RS. SRSF algo: + 1. When reqeust arrives to the queue, record TS and calcuate RS. RS = deadline - execution time + 2. When request starts running, update RS + 3. When request stops, update TS + 4. When request resumes, update RS + */ + sandbox->srsf_stop_running_ts = __getcycles(); + sandbox->srsf_remaining_slack = sandbox->relative_deadline - sandbox->estimated_cost; + worker_queuing_cost_increment(index, sandbox->estimated_cost); - worker_queuing_cost_increment(index, estimated_execute_cost); - sandbox->estimated_cost = estimated_execute_cost; } /** @@ -74,6 +110,7 @@ local_runqueue_minheap_delete(struct sandbox *sandbox) int rc = priority_queue_delete(local_runqueue_minheap, sandbox); if (rc == -1) panic("Tried to delete sandbox %lu from runqueue, but was not present\n", sandbox->id); + atomic_fetch_sub(&local_queue_length[global_worker_thread_idx], 1); worker_queuing_cost_decrement(global_worker_thread_idx, sandbox->estimated_cost); } @@ -89,13 +126,19 @@ local_runqueue_minheap_get_next() { /* Get the deadline of the sandbox at the head of the local request queue */ struct sandbox *next = NULL; - int rc = priority_queue_top(local_runqueue_minheap, (void **)&next); + int rc = priority_queue_top(local_runqueue_minheap, (void **)&next); if (rc == -ENOENT) return NULL; return next; } +int +local_runqueue_minheap_get_len() +{ + return priority_queue_length(local_runqueue_minheap); +} + /** * Registers the PS variant with the polymorphic interface */ @@ -107,11 +150,13 @@ local_runqueue_minheap_initialize() worker_queues[global_worker_thread_idx] = local_runqueue_minheap; /* Register Function Pointers for Abstract Scheduling API */ - struct local_runqueue_config config = { .add_fn = local_runqueue_minheap_add, - .add_fn_idx = local_runqueue_minheap_add_index, - .is_empty_fn = local_runqueue_minheap_is_empty, - .delete_fn = local_runqueue_minheap_delete, - .get_next_fn = local_runqueue_minheap_get_next }; + struct local_runqueue_config config = { .add_fn = local_runqueue_minheap_add, + .add_fn_idx = local_runqueue_minheap_add_index, + .is_empty_fn = local_runqueue_minheap_is_empty, + .is_empty_fn_idx = local_runqueue_minheap_is_empty_index, + .delete_fn = local_runqueue_minheap_delete, + .get_length_fn = local_runqueue_minheap_get_len, + .get_next_fn = local_runqueue_minheap_get_next }; local_runqueue_initialize(&config); } diff --git a/runtime/src/main.c b/runtime/src/main.c index 714d6e205..2273efa95 100644 --- a/runtime/src/main.c +++ b/runtime/src/main.c @@ -55,7 +55,7 @@ bool runtime_autoscaling_enabled = false; bool runtime_worker_busy_loop_enabled = false; bool runtime_preemption_enabled = true; bool runtime_worker_spinloop_pause_enabled = false; -uint32_t runtime_quantum_us = 5000; /* 5ms */ +uint32_t runtime_quantum_us = 1000; /* 1ms */ uint64_t runtime_boot_timestamp; pid_t runtime_pid = 0; diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index 209e80032..00ef2a6c6 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -188,6 +188,9 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void /* Global tenant promotions */ global_timeout_queue_process_promotions(); } + if (runtime_preemption_enabled) { + propagate_sigalrm(signal_info); + } } else if (current_sandbox_is_preemptable()) { preemptable_interrupts++; /* Preemptable, so run scheduler. The scheduler handles outgoing state changes */ @@ -198,6 +201,10 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void /* Global tenant promotions */ global_timeout_queue_process_promotions(); } + + if (runtime_preemption_enabled) { + propagate_sigalrm(signal_info); + } scheduler_preemptive_sched(interrupted_context); } else { /* We transition the sandbox to an interrupted state to exclude time propagating signals and @@ -206,6 +213,10 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void /* Global tenant promotions */ global_timeout_queue_process_promotions(); } + + if (runtime_preemption_enabled) { + propagate_sigalrm(signal_info); + } atomic_fetch_add(&deferred_sigalrm, 1); } From 90314e170e63bbb0d01641db6a946f834dd2cef8 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 16 May 2025 16:58:43 -0600 Subject: [PATCH 165/198] add JSQ and LLD distribution with EDF scheduling --- runtime/include/erpc_handler.h | 2 + runtime/include/http_router.h | 8 ++ runtime/include/local_runqueue.h | 11 +- runtime/src/listener_thread.c | 170 ++++++++++++++++++++++++++- runtime/src/local_runqueue.c | 5 + runtime/src/local_runqueue_minheap.c | 23 ++-- 6 files changed, 204 insertions(+), 15 deletions(-) diff --git a/runtime/include/erpc_handler.h b/runtime/include/erpc_handler.h index 08e97979b..c67ada041 100644 --- a/runtime/include/erpc_handler.h +++ b/runtime/include/erpc_handler.h @@ -6,3 +6,5 @@ void darc_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t s void shinjuku_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); void enqueue_to_global_queue_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); void rr_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); +void jsq_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); +void lld_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); diff --git a/runtime/include/http_router.h b/runtime/include/http_router.h index b3ac71d65..28fa7c2b6 100644 --- a/runtime/include/http_router.h +++ b/runtime/include/http_router.h @@ -73,6 +73,14 @@ http_router_add_route(http_router_t *router, struct route_config *config, struct if (erpc_register_req_func(config->request_type, rr_req_handler, 0) != 0) { panic("register erpc function for round robain distribution failed\n"); } + } else if (dispatcher == DISPATCHER_JSQ) { + if (erpc_register_req_func(config->request_type, jsq_req_handler, 0) != 0) { + panic("register erpc function for join shortest queue distribution failed\n"); + } + } else if (dispatcher == DISPATCHER_LLD) { + if (erpc_register_req_func(config->request_type, lld_req_handler, 0) != 0) { + panic("register erpc function for leatest load distribution failed\n"); + } } /* Admissions Control */ diff --git a/runtime/include/local_runqueue.h b/runtime/include/local_runqueue.h index 5992b8a42..0a75f6511 100644 --- a/runtime/include/local_runqueue.h +++ b/runtime/include/local_runqueue.h @@ -44,13 +44,12 @@ int local_runqueue_get_length(); int local_runqueue_get_length_index(int index); void local_runqueue_print_in_order(int index); -void -worker_queuing_cost_initialize(); +void worker_queuing_cost_initialize(); -void -worker_queuing_cost_increment(int index, uint64_t cost); +void worker_queuing_cost_increment(int index, uint64_t cost); -void -worker_queuing_cost_decrement(int index, uint64_t cost); +void worker_queuing_cost_decrement(int index, uint64_t cost); + +uint64_t get_local_queue_load(int index); void wakeup_worker(int index); diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 2246a810f..7469676df 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -687,6 +687,166 @@ void rr_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t siz local_runqueue_add_index(rr_index, sandbox); rr_index++; } + +void jsq_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { + + if (first_request_comming == false){ + t_start = time(NULL); + first_request_comming = true; + } + + uint8_t kMsgSize = 16; + + struct tenant *tenant = tenant_database_find_by_port(port); + assert(tenant != NULL); + struct route *route = http_router_match_request_type(&tenant->router, req_type); + if (route == NULL) { + debuglog("Did not match any routes\n"); + dispatcher_send_response(req_handle, DIPATCH_ROUNTE_ERROR, strlen(DIPATCH_ROUNTE_ERROR)); + return; + } + + /* + * Perform admissions control. + * If 0, workload was rejected, so close with 429 "Too Many Requests" and continue + * TODO: Consider providing a Retry-After header + */ + uint64_t work_admitted = admissions_control_decide(route->admissions_info.estimate); + if (work_admitted == 0) { + dispatcher_send_response(req_handle, WORK_ADMITTED_ERROR, strlen(WORK_ADMITTED_ERROR)); + return; + } + + total_requests++; + requests_counter[dispatcher_thread_idx][req_type]++; + /* Allocate a Sandbox */ + //session->state = HTTP_SESSION_EXECUTING; + struct sandbox *sandbox = sandbox_alloc(route->module, NULL, route, tenant, work_admitted, req_handle, dispatcher_thread_idx); + if (unlikely(sandbox == NULL)) { + debuglog("Failed to allocate sandbox\n"); + dispatcher_send_response(req_handle, SANDBOX_ALLOCATION_ERROR, strlen(SANDBOX_ALLOCATION_ERROR)); + return; + } + + /* Reset estimated execution time and relative deadline for exponential service time simulation */ + if (runtime_exponential_service_time_simulation_enabled) { + int exp_num = atoi((const char *)msg); + if (exp_num == 1) { + sandbox->estimated_cost = base_simulated_service_time; + } else { + sandbox->estimated_cost = base_simulated_service_time * exp_num * (1 - LOSS_PERCENTAGE); + } + sandbox->relative_deadline = 10 * sandbox->estimated_cost; + sandbox->absolute_deadline = sandbox->timestamp_of.allocation + sandbox->relative_deadline; + } + + /* copy the received data since it will be released by erpc */ + sandbox->rpc_request_body = malloc(size); + if (!sandbox->rpc_request_body) { + panic("malloc request body failed\n"); + } + + memcpy(sandbox->rpc_request_body, msg, size); + sandbox->rpc_request_body_size = size; + + int min_queue_len = INT_MAX; + int min_index = 0; + + next_loop_start_index++; + if (next_loop_start_index == current_active_workers) { + next_loop_start_index = 0; + } + + for(uint32_t i = next_loop_start_index; i < next_loop_start_index + current_active_workers; ++i) { + int true_idx = i % current_active_workers; + int len = local_runqueue_get_length_index(worker_list[true_idx]); + if (len < min_queue_len) { + min_queue_len = len; + min_index = worker_list[true_idx]; + } + } + local_runqueue_add_index(min_index, sandbox); +} + +void lld_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { + + if (first_request_comming == false){ + t_start = time(NULL); + first_request_comming = true; + } + + uint8_t kMsgSize = 16; + + struct tenant *tenant = tenant_database_find_by_port(port); + assert(tenant != NULL); + struct route *route = http_router_match_request_type(&tenant->router, req_type); + if (route == NULL) { + debuglog("Did not match any routes\n"); + dispatcher_send_response(req_handle, DIPATCH_ROUNTE_ERROR, strlen(DIPATCH_ROUNTE_ERROR)); + return; + } + + /* + * Perform admissions control. + * If 0, workload was rejected, so close with 429 "Too Many Requests" and continue + * TODO: Consider providing a Retry-After header + */ + uint64_t work_admitted = admissions_control_decide(route->admissions_info.estimate); + if (work_admitted == 0) { + dispatcher_send_response(req_handle, WORK_ADMITTED_ERROR, strlen(WORK_ADMITTED_ERROR)); + return; + } + + total_requests++; + requests_counter[dispatcher_thread_idx][req_type]++; + /* Allocate a Sandbox */ + //session->state = HTTP_SESSION_EXECUTING; + struct sandbox *sandbox = sandbox_alloc(route->module, NULL, route, tenant, work_admitted, req_handle, dispatcher_thread_idx); + if (unlikely(sandbox == NULL)) { + debuglog("Failed to allocate sandbox\n"); + dispatcher_send_response(req_handle, SANDBOX_ALLOCATION_ERROR, strlen(SANDBOX_ALLOCATION_ERROR)); + return; + } + + /* Reset estimated execution time and relative deadline for exponential service time simulation */ + if (runtime_exponential_service_time_simulation_enabled) { + int exp_num = atoi((const char *)msg); + if (exp_num == 1) { + sandbox->estimated_cost = base_simulated_service_time; + } else { + sandbox->estimated_cost = base_simulated_service_time * exp_num * (1 - LOSS_PERCENTAGE); + } + sandbox->relative_deadline = 10 * sandbox->estimated_cost; + sandbox->absolute_deadline = sandbox->timestamp_of.allocation + sandbox->relative_deadline; + } + + /* copy the received data since it will be released by erpc */ + sandbox->rpc_request_body = malloc(size); + if (!sandbox->rpc_request_body) { + panic("malloc request body failed\n"); + } + + memcpy(sandbox->rpc_request_body, msg, size); + sandbox->rpc_request_body_size = size; + + next_loop_start_index++; + if (next_loop_start_index == current_active_workers) { + next_loop_start_index = 0; + } + + uint64_t min_load = INT_MAX; + int min_index = 0; + + for(uint32_t i = next_loop_start_index; i < next_loop_start_index + current_active_workers; ++i) { + int true_idx = i % current_active_workers; + uint64_t load = get_local_queue_load(worker_list[true_idx]); + if (load < min_load) { + min_load = load; + min_index = worker_list[true_idx]; + } + } + local_runqueue_add_index(min_index, sandbox); +} /** * @brief Request routing function * @param req_handle used by eRPC internal, it is used to send out the response packet @@ -1220,9 +1380,15 @@ listener_thread_main(void *dummy) erpc_run_event_loop_once(dispatcher_thread_idx); } } else if (dispatcher == DISPATCHER_JSQ) { - + printf("JSQ....\n"); + while (!pthread_stop) { + erpc_run_event_loop_once(dispatcher_thread_idx); + } } else if (dispatcher == DISPATCHER_LLD) { - + printf("LLD....\n"); + while (!pthread_stop) { + erpc_run_event_loop_once(dispatcher_thread_idx); + } } /* code will end here with eRPC and won't go to the following implementaion */ diff --git a/runtime/src/local_runqueue.c b/runtime/src/local_runqueue.c index 6a7e3d6f5..21680dae1 100644 --- a/runtime/src/local_runqueue.c +++ b/runtime/src/local_runqueue.c @@ -164,6 +164,11 @@ worker_queuing_cost_decrement(int index, uint64_t cost) assert(worker_queuing_cost[index] >= 0); } +uint64_t +get_local_queue_load(int index) { + return worker_queuing_cost[index]; +} + void wakeup_worker(int index) { pthread_mutex_lock(&mutexs[index]); diff --git a/runtime/src/local_runqueue_minheap.c b/runtime/src/local_runqueue_minheap.c index 8caab41f9..7f2c4c1d1 100644 --- a/runtime/src/local_runqueue_minheap.c +++ b/runtime/src/local_runqueue_minheap.c @@ -139,6 +139,14 @@ local_runqueue_minheap_get_len() return priority_queue_length(local_runqueue_minheap); } +int +local_runqueue_minheap_get_len_index(int index) +{ + struct priority_queue *local_queue = worker_queues[index]; + assert(local_queue != NULL); + return priority_queue_length(local_queue); +} + /** * Registers the PS variant with the polymorphic interface */ @@ -150,13 +158,14 @@ local_runqueue_minheap_initialize() worker_queues[global_worker_thread_idx] = local_runqueue_minheap; /* Register Function Pointers for Abstract Scheduling API */ - struct local_runqueue_config config = { .add_fn = local_runqueue_minheap_add, - .add_fn_idx = local_runqueue_minheap_add_index, - .is_empty_fn = local_runqueue_minheap_is_empty, - .is_empty_fn_idx = local_runqueue_minheap_is_empty_index, - .delete_fn = local_runqueue_minheap_delete, - .get_length_fn = local_runqueue_minheap_get_len, - .get_next_fn = local_runqueue_minheap_get_next }; + struct local_runqueue_config config = { .add_fn = local_runqueue_minheap_add, + .add_fn_idx = local_runqueue_minheap_add_index, + .is_empty_fn = local_runqueue_minheap_is_empty, + .is_empty_fn_idx = local_runqueue_minheap_is_empty_index, + .delete_fn = local_runqueue_minheap_delete, + .get_length_fn = local_runqueue_minheap_get_len, + .get_length_fn_idx = local_runqueue_minheap_get_len_index, + .get_next_fn = local_runqueue_minheap_get_next }; local_runqueue_initialize(&config); } From ea421fa62e20f6e9c4d0231eeec726d72cca8283 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 20 May 2025 16:10:47 -0600 Subject: [PATCH 166/198] implement the second version of JSQ, RR, LLD: Dispatcher assigns requests to workers with JSQ, LLD, or RR + interruption and each worker schedule its local queue with EDF, no self interruption --- runtime/include/local_runqueue.h | 28 ++- runtime/src/listener_thread.c | 334 ++++++++++++++++++++++++++- runtime/src/local_runqueue.c | 14 ++ runtime/src/local_runqueue_minheap.c | 67 +++++- 4 files changed, 422 insertions(+), 21 deletions(-) diff --git a/runtime/include/local_runqueue.h b/runtime/include/local_runqueue.h index 0a75f6511..56879a943 100644 --- a/runtime/include/local_runqueue.h +++ b/runtime/include/local_runqueue.h @@ -8,6 +8,8 @@ typedef void (*local_runqueue_add_fn_t)(struct sandbox *); typedef void (*local_runqueue_add_fn_t_idx)(int index, struct sandbox *); typedef uint64_t (*local_runqueue_try_add_fn_t_idx)(int index, struct sandbox *, bool *need_interrupt); +typedef uint32_t (*local_runqueue_try_add_and_get_len_fn_t_idx)(int index, struct sandbox *, bool *need_interrupt); +typedef uint64_t (*local_runqueue_try_add_and_get_load_fn_t_idx)(int index, struct sandbox *, bool *need_interrupt); typedef bool (*local_runqueue_is_empty_fn_t)(void); typedef bool (*local_runqueue_is_empty_fn_t_idx)(int index); typedef void (*local_runqueue_delete_fn_t)(struct sandbox *sandbox); @@ -18,22 +20,26 @@ typedef int (*local_runqueue_get_length_fn_t_idx)(int index); typedef void (*local_runqueue_print_in_order_fn_t_idx)(int index); struct local_runqueue_config { - local_runqueue_add_fn_t add_fn; - local_runqueue_add_fn_t_idx add_fn_idx; - local_runqueue_try_add_fn_t_idx try_add_fn_idx; - local_runqueue_is_empty_fn_t is_empty_fn; - local_runqueue_is_empty_fn_t_idx is_empty_fn_idx; - local_runqueue_delete_fn_t delete_fn; - local_runqueue_get_next_fn_t get_next_fn; - local_runqueue_get_height_fn_t get_height_fn; - local_runqueue_get_length_fn_t get_length_fn; - local_runqueue_get_length_fn_t_idx get_length_fn_idx; - local_runqueue_print_in_order_fn_t_idx print_in_order_fn_idx; + local_runqueue_add_fn_t add_fn; + local_runqueue_add_fn_t_idx add_fn_idx; + local_runqueue_try_add_fn_t_idx try_add_fn_idx; + local_runqueue_try_add_and_get_len_fn_t_idx try_add_and_get_len_fn_t_idx; + local_runqueue_try_add_and_get_load_fn_t_idx try_add_and_get_load_fn_t_idx; + local_runqueue_is_empty_fn_t is_empty_fn; + local_runqueue_is_empty_fn_t_idx is_empty_fn_idx; + local_runqueue_delete_fn_t delete_fn; + local_runqueue_get_next_fn_t get_next_fn; + local_runqueue_get_height_fn_t get_height_fn; + local_runqueue_get_length_fn_t get_length_fn; + local_runqueue_get_length_fn_t_idx get_length_fn_idx; + local_runqueue_print_in_order_fn_t_idx print_in_order_fn_idx; }; void local_runqueue_add(struct sandbox *); void local_runqueue_add_index(int index, struct sandbox *); uint64_t local_runqueue_try_add_index(int index, struct sandbox *, bool *need_interrupt); +uint32_t local_runqueue_add_and_get_length_index(int index, struct sandbox *, bool *need_interrupt); +uint64_t local_runqueue_add_and_get_load_index(int index, struct sandbox *, bool *need_interrupt); void local_runqueue_delete(struct sandbox *); bool local_runqueue_is_empty(); bool local_runqueue_is_empty_index(int index); diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 7469676df..37a5c625e 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -620,6 +620,228 @@ void edf_interrupt_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, } } +void jsq_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { + + if (first_request_comming == false){ + t_start = time(NULL); + first_request_comming = true; + } + + uint8_t kMsgSize = 16; + + struct tenant *tenant = tenant_database_find_by_port(port); + assert(tenant != NULL); + struct route *route = http_router_match_request_type(&tenant->router, req_type); + if (route == NULL) { + debuglog("Did not match any routes\n"); + dispatcher_send_response(req_handle, DIPATCH_ROUNTE_ERROR, strlen(DIPATCH_ROUNTE_ERROR)); + return; + } + + /* + * Perform admissions control. + * If 0, workload was rejected, so close with 429 "Too Many Requests" and continue + * TODO: Consider providing a Retry-After header + */ + uint64_t work_admitted = admissions_control_decide(route->admissions_info.estimate); + if (work_admitted == 0) { + dispatcher_send_response(req_handle, WORK_ADMITTED_ERROR, strlen(WORK_ADMITTED_ERROR)); + return; + } + + total_requests++; + requests_counter[dispatcher_thread_idx][req_type]++; + /* Allocate a Sandbox */ + //session->state = HTTP_SESSION_EXECUTING; + struct sandbox *sandbox = sandbox_alloc(route->module, NULL, route, tenant, work_admitted, req_handle, dispatcher_thread_idx); + if (unlikely(sandbox == NULL)) { + debuglog("Failed to allocate sandbox\n"); + dispatcher_send_response(req_handle, SANDBOX_ALLOCATION_ERROR, strlen(SANDBOX_ALLOCATION_ERROR)); + return; + } + + /* Reset estimated execution time and relative deadline for exponential service time simulation */ + if (runtime_exponential_service_time_simulation_enabled) { + int exp_num = atoi((const char *)msg); + if (exp_num == 1) { + sandbox->estimated_cost = base_simulated_service_time; + } else { + sandbox->estimated_cost = base_simulated_service_time * exp_num * (1 - LOSS_PERCENTAGE); + } + sandbox->relative_deadline = 10 * sandbox->estimated_cost; + sandbox->absolute_deadline = sandbox->timestamp_of.allocation + sandbox->relative_deadline; + } + + /* copy the received data since it will be released by erpc */ + sandbox->rpc_request_body = malloc(size); + if (!sandbox->rpc_request_body) { + panic("malloc request body failed\n"); + } + + memcpy(sandbox->rpc_request_body, msg, size); + sandbox->rpc_request_body_size = size; + + uint64_t min_queue_len = UINT64_MAX; + int thread_id = 0; /* This thread can server the request by waiting for a while */ + int candidate_thread_with_interrupt = -1; /* This thread can server the request immediately by interrupting + the current one */ + + next_loop_start_index++; + if (next_loop_start_index == current_active_workers) { + next_loop_start_index = 0; + } + + for (uint32_t i = next_loop_start_index; i < next_loop_start_index + current_active_workers; ++i) { + int true_idx = i % current_active_workers; + bool need_interrupt; + uint64_t waiting_queue_len = local_runqueue_add_and_get_length_index(worker_list[true_idx], sandbox, &need_interrupt); + /* The local queue is empty, the worker is idle, can be served this request immediately + * without interrupting + */ + if (waiting_queue_len == 0 && need_interrupt == false) { + local_runqueue_add_index(worker_list[true_idx], sandbox); + //mem_log("listener %d %d is idle, choose it\n", dispatcher_thread_idx, worker_list[true_idx]); + return; + } else if (waiting_queue_len == 0 && need_interrupt == true) {//The worker can serve the request immediately + // by interrupting the current one + /* We already have a candidate worker, continue to find a + * better worker without needing interrupt or a worker that has the minimum queue length + */ + + candidate_thread_with_interrupt = worker_list[true_idx]; + } else { + if (min_queue_len > waiting_queue_len) { + min_queue_len = waiting_queue_len; + thread_id = worker_list[true_idx]; + } + } + } + + if (candidate_thread_with_interrupt != -1) { + //urgent_request[candidate_thread_with_interrupt] = sandbox; + local_runqueue_add_index(candidate_thread_with_interrupt, sandbox); + //mem_log("listener %d %d can be interrupted immediately for req deadline %lu\n", dispatcher_thread_idx, + // candidate_thread_with_interrupt, sandbox->absolute_deadline); + + preempt_worker(candidate_thread_with_interrupt); + dispatcher_try_interrupts++; + } else { + local_runqueue_add_index(thread_id, sandbox); + } +} + +void lld_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { + + if (first_request_comming == false){ + t_start = time(NULL); + first_request_comming = true; + } + + uint8_t kMsgSize = 16; + + struct tenant *tenant = tenant_database_find_by_port(port); + assert(tenant != NULL); + struct route *route = http_router_match_request_type(&tenant->router, req_type); + if (route == NULL) { + debuglog("Did not match any routes\n"); + dispatcher_send_response(req_handle, DIPATCH_ROUNTE_ERROR, strlen(DIPATCH_ROUNTE_ERROR)); + return; + } + + /* + * Perform admissions control. + * If 0, workload was rejected, so close with 429 "Too Many Requests" and continue + * TODO: Consider providing a Retry-After header + */ + uint64_t work_admitted = admissions_control_decide(route->admissions_info.estimate); + if (work_admitted == 0) { + dispatcher_send_response(req_handle, WORK_ADMITTED_ERROR, strlen(WORK_ADMITTED_ERROR)); + return; + } + + total_requests++; + requests_counter[dispatcher_thread_idx][req_type]++; + /* Allocate a Sandbox */ + //session->state = HTTP_SESSION_EXECUTING; + struct sandbox *sandbox = sandbox_alloc(route->module, NULL, route, tenant, work_admitted, req_handle, dispatcher_thread_idx); + if (unlikely(sandbox == NULL)) { + debuglog("Failed to allocate sandbox\n"); + dispatcher_send_response(req_handle, SANDBOX_ALLOCATION_ERROR, strlen(SANDBOX_ALLOCATION_ERROR)); + return; + } + + /* Reset estimated execution time and relative deadline for exponential service time simulation */ + if (runtime_exponential_service_time_simulation_enabled) { + int exp_num = atoi((const char *)msg); + if (exp_num == 1) { + sandbox->estimated_cost = base_simulated_service_time; + } else { + sandbox->estimated_cost = base_simulated_service_time * exp_num * (1 - LOSS_PERCENTAGE); + } + sandbox->relative_deadline = 10 * sandbox->estimated_cost; + sandbox->absolute_deadline = sandbox->timestamp_of.allocation + sandbox->relative_deadline; + } + + /* copy the received data since it will be released by erpc */ + sandbox->rpc_request_body = malloc(size); + if (!sandbox->rpc_request_body) { + panic("malloc request body failed\n"); + } + + memcpy(sandbox->rpc_request_body, msg, size); + sandbox->rpc_request_body_size = size; + + uint64_t min_load = UINT64_MAX; + int thread_id = 0; /* This thread can server the request by waiting for a while */ + int candidate_thread_with_interrupt = -1; /* This thread can server the request immediately by interrupting + the current one */ + + next_loop_start_index++; + if (next_loop_start_index == current_active_workers) { + next_loop_start_index = 0; + } + + //uint64_t waiting_times[3] = {0}; + int violate_deadline_workers = 0; + for (uint32_t i = next_loop_start_index; i < next_loop_start_index + current_active_workers; ++i) { + int true_idx = i % current_active_workers; + bool need_interrupt; + uint64_t load = local_runqueue_add_and_get_load_index(worker_list[true_idx], sandbox, &need_interrupt); + /* The local queue is empty, the worker is idle, can be served this request immediately + * without interrupting + */ + if (load == 0 && need_interrupt == false) { + local_runqueue_add_index(worker_list[true_idx], sandbox); + //mem_log("listener %d %d is idle, choose it\n", dispatcher_thread_idx, worker_list[true_idx]); + return; + } else if (load == 0 && need_interrupt == true) {//The worker can serve the request immediately + // by interrupting the current one + /* We already have a candidate worker, continue to find a + * better worker without needing interrupt or a worker that has the minimum queue length + */ + + candidate_thread_with_interrupt = worker_list[true_idx]; + } else { + if (min_load > load) { + min_load = load; + thread_id = worker_list[true_idx]; + } + } + } + + if (candidate_thread_with_interrupt != -1) { + //urgent_request[candidate_thread_with_interrupt] = sandbox; + local_runqueue_add_index(candidate_thread_with_interrupt, sandbox); + //mem_log("listener %d %d can be interrupted immediately for req deadline %lu\n", dispatcher_thread_idx, + // candidate_thread_with_interrupt, sandbox->absolute_deadline); + + preempt_worker(candidate_thread_with_interrupt); + dispatcher_try_interrupts++; + } else { + local_runqueue_add_index(thread_id, sandbox); + } +} + void rr_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { if (first_request_comming == false){ @@ -681,6 +903,114 @@ void rr_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t siz memcpy(sandbox->rpc_request_body, msg, size); sandbox->rpc_request_body_size = size; + int thread_id = 0; /* This thread can server the request by waiting for a while */ + int candidate_thread_with_interrupt = -1; /* This thread can server the request immediately by interrupting + the current one */ + + next_loop_start_index++; + if (next_loop_start_index == current_active_workers) { + next_loop_start_index = 0; + } + + for (uint32_t i = next_loop_start_index; i < next_loop_start_index + current_active_workers; ++i) { + int true_idx = i % current_active_workers; + bool need_interrupt; + uint64_t waiting_queue_len = local_runqueue_add_and_get_length_index(worker_list[true_idx], sandbox, &need_interrupt); + /* The local queue is empty, the worker is idle, can be served this request immediately + * without interrupting + */ + if (waiting_queue_len == 0 && need_interrupt == false) { + local_runqueue_add_index(worker_list[true_idx], sandbox); + //mem_log("listener %d %d is idle, choose it\n", dispatcher_thread_idx, worker_list[true_idx]); + return; + } else if (waiting_queue_len == 0 && need_interrupt == true) {//The worker can serve the request immediately + // by interrupting the current one + /* We already have a candidate worker, continue to find a + * better worker without needing interrupt or a worker that has the minimum queue length + */ + + candidate_thread_with_interrupt = worker_list[true_idx]; + } + } + + if (candidate_thread_with_interrupt != -1) { + //urgent_request[candidate_thread_with_interrupt] = sandbox; + local_runqueue_add_index(candidate_thread_with_interrupt, sandbox); + //mem_log("listener %d %d can be interrupted immediately for req deadline %lu\n", dispatcher_thread_idx, + // candidate_thread_with_interrupt, sandbox->absolute_deadline); + + preempt_worker(candidate_thread_with_interrupt); + dispatcher_try_interrupts++; + } else { + if (rr_index == worker_end_id + 1) { + rr_index = worker_start_id; + } + local_runqueue_add_index(rr_index, sandbox); + rr_index++; + } +} + +void rr_req_handler2(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { + + if (first_request_comming == false){ + t_start = time(NULL); + first_request_comming = true; + } + + uint8_t kMsgSize = 16; + + struct tenant *tenant = tenant_database_find_by_port(port); + assert(tenant != NULL); + struct route *route = http_router_match_request_type(&tenant->router, req_type); + if (route == NULL) { + debuglog("Did not match any routes\n"); + dispatcher_send_response(req_handle, DIPATCH_ROUNTE_ERROR, strlen(DIPATCH_ROUNTE_ERROR)); + return; + } + + /* + * Perform admissions control. + * If 0, workload was rejected, so close with 429 "Too Many Requests" and continue + * TODO: Consider providing a Retry-After header + */ + uint64_t work_admitted = admissions_control_decide(route->admissions_info.estimate); + if (work_admitted == 0) { + dispatcher_send_response(req_handle, WORK_ADMITTED_ERROR, strlen(WORK_ADMITTED_ERROR)); + return; + } + + total_requests++; + requests_counter[dispatcher_thread_idx][req_type]++; + /* Allocate a Sandbox */ + //session->state = HTTP_SESSION_EXECUTING; + struct sandbox *sandbox = sandbox_alloc(route->module, NULL, route, tenant, work_admitted, req_handle, dispatcher_thread_idx); + if (unlikely(sandbox == NULL)) { + debuglog("Failed to allocate sandbox\n"); + dispatcher_send_response(req_handle, SANDBOX_ALLOCATION_ERROR, strlen(SANDBOX_ALLOCATION_ERROR)); + return; + } + + /* Reset estimated execution time and relative deadline for exponential service time simulation */ + if (runtime_exponential_service_time_simulation_enabled) { + int exp_num = atoi((const char *)msg); + if (exp_num == 1) { + sandbox->estimated_cost = base_simulated_service_time; + } else { + sandbox->estimated_cost = base_simulated_service_time * exp_num * (1 - LOSS_PERCENTAGE); + } + sandbox->relative_deadline = 10 * sandbox->estimated_cost; + sandbox->absolute_deadline = sandbox->timestamp_of.allocation + sandbox->relative_deadline; + } + + /* copy the received data since it will be released by erpc */ + sandbox->rpc_request_body = malloc(size); + if (!sandbox->rpc_request_body) { + panic("malloc request body failed\n"); + } + + memcpy(sandbox->rpc_request_body, msg, size); + sandbox->rpc_request_body_size = size; + if (rr_index == worker_end_id + 1) { rr_index = worker_start_id; } @@ -688,7 +1018,7 @@ void rr_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t siz rr_index++; } -void jsq_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { +void jsq_req_handler2(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { if (first_request_comming == false){ t_start = time(NULL); @@ -768,7 +1098,7 @@ void jsq_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t si local_runqueue_add_index(min_index, sandbox); } -void lld_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { +void lld_req_handler2(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { if (first_request_comming == false){ t_start = time(NULL); diff --git a/runtime/src/local_runqueue.c b/runtime/src/local_runqueue.c index 21680dae1..2ea5bdd4c 100644 --- a/runtime/src/local_runqueue.c +++ b/runtime/src/local_runqueue.c @@ -75,6 +75,20 @@ local_runqueue_try_add_index(int index, struct sandbox *sandbox, bool *need_inte assert(local_runqueue.try_add_fn_idx != NULL); return local_runqueue.try_add_fn_idx(index, sandbox, need_interrupt); } + +uint32_t +local_runqueue_add_and_get_length_index(int index, struct sandbox *sandbox, bool *need_interrupt) +{ + assert(local_runqueue.try_add_and_get_len_fn_t_idx != NULL); + return local_runqueue.try_add_and_get_len_fn_t_idx(index, sandbox, need_interrupt); +} + +uint64_t +local_runqueue_add_and_get_load_index(int index, struct sandbox *sandbox, bool *need_interrupt) +{ + assert(local_runqueue.try_add_and_get_load_fn_t_idx != NULL); + return local_runqueue.try_add_and_get_load_fn_t_idx(index, sandbox, need_interrupt); +} /** * Delete a sandbox from the run queue * @param sandbox to delete diff --git a/runtime/src/local_runqueue_minheap.c b/runtime/src/local_runqueue_minheap.c index 7f2c4c1d1..2dfcab5c1 100644 --- a/runtime/src/local_runqueue_minheap.c +++ b/runtime/src/local_runqueue_minheap.c @@ -98,6 +98,55 @@ local_runqueue_minheap_add_index(int index, struct sandbox *sandbox) } +uint32_t +local_runqueue_minheap_try_add_and_get_len_index(int index, struct sandbox *sandbox, bool *need_interrupt) { + struct priority_queue *local_queue = worker_queues[index]; + assert(local_queue != NULL); + + if (priority_queue_length(local_queue) == 0) { + /* The worker is idle */ + *need_interrupt = false; + return 0; + } else if (current_sandboxes[index] != NULL && + current_sandboxes[index]->srsf_remaining_slack > 0 && + sandbox_is_preemptable(current_sandboxes[index]) == true && + sandbox_get_priority(sandbox) < sandbox_get_priority(current_sandboxes[index])) { + /* The new one has a higher priority than the current one, need to interrupt the current one */ + *need_interrupt = true; + return 0; + } else { + /* Current sandbox cannot be interrupted because its priority is higher or its RS is 0, just find + a right location to add the new sandbox to the tree + */ + need_interrupt = false; + return priority_queue_length(local_queue); + } +} + +uint64_t +local_runqueue_minheap_try_add_and_get_load_index(int index, struct sandbox *sandbox, bool *need_interrupt) { + struct priority_queue *local_queue = worker_queues[index]; + assert(local_queue != NULL); + + if (priority_queue_length(local_queue) == 0) { + /* The worker is idle */ + *need_interrupt = false; + return 0; + } else if (current_sandboxes[index] != NULL && + current_sandboxes[index]->srsf_remaining_slack > 0 && + sandbox_is_preemptable(current_sandboxes[index]) == true && + sandbox_get_priority(sandbox) < sandbox_get_priority(current_sandboxes[index])) { + /* The new one has a higher priority than the current one, need to interrupt the current one */ + *need_interrupt = true; + return 0; + } else { + /* Current sandbox cannot be interrupted because its priority is higher or its RS is 0, just find + a right location to add the new sandbox to the tree + */ + need_interrupt = false; + return worker_queuing_cost[index]; + } +} /** * Deletes a sandbox from the runqueue * @param sandbox to delete @@ -158,14 +207,16 @@ local_runqueue_minheap_initialize() worker_queues[global_worker_thread_idx] = local_runqueue_minheap; /* Register Function Pointers for Abstract Scheduling API */ - struct local_runqueue_config config = { .add_fn = local_runqueue_minheap_add, - .add_fn_idx = local_runqueue_minheap_add_index, - .is_empty_fn = local_runqueue_minheap_is_empty, - .is_empty_fn_idx = local_runqueue_minheap_is_empty_index, - .delete_fn = local_runqueue_minheap_delete, - .get_length_fn = local_runqueue_minheap_get_len, - .get_length_fn_idx = local_runqueue_minheap_get_len_index, - .get_next_fn = local_runqueue_minheap_get_next }; + struct local_runqueue_config config = { .add_fn = local_runqueue_minheap_add, + .add_fn_idx = local_runqueue_minheap_add_index, + .try_add_and_get_len_fn_t_idx = local_runqueue_minheap_try_add_and_get_len_index, + .try_add_and_get_load_fn_t_idx = local_runqueue_minheap_try_add_and_get_load_index, + .is_empty_fn = local_runqueue_minheap_is_empty, + .is_empty_fn_idx = local_runqueue_minheap_is_empty_index, + .delete_fn = local_runqueue_minheap_delete, + .get_length_fn = local_runqueue_minheap_get_len, + .get_length_fn_idx = local_runqueue_minheap_get_len_index, + .get_next_fn = local_runqueue_minheap_get_next }; local_runqueue_initialize(&config); } From 08c642327195d004e90e3000b860093dde6f9dd2 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 20 May 2025 16:11:37 -0600 Subject: [PATCH 167/198] update parse_batch.py --- runtime/tests/parse_batch.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/tests/parse_batch.py b/runtime/tests/parse_batch.py index 264c3297e..0c218a2da 100644 --- a/runtime/tests/parse_batch.py +++ b/runtime/tests/parse_batch.py @@ -159,8 +159,8 @@ def get_values(key, files_list, latency_dict, slow_down_dict, slow_down_99_9_dic if __name__ == "__main__": import json - #file_folders = ['SHINJUKU', 'SHINJUKU_25', 'DARC', 'EDF_SRSF_INTERRUPT'] - file_folders = ['SHINJUKU', 'DARC', 'EDF_INTERRUPT'] + file_folders = ['RR', 'EDF_INTERRUPT', 'JSQ', 'LLD'] + #file_folders = ['SHINJUKU', 'DARC', 'EDF_INTERRUPT'] #file_folders = ['SHINJUKU'] latency = defaultdict(list) slow_down = defaultdict(list) From b4b7dabe2109d5279140f7b87e3f44300816694f Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 20 May 2025 16:13:33 -0600 Subject: [PATCH 168/198] upload compare_dispatchers.sh --- runtime/tests/compare_dispatchers.sh | 71 ++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100755 runtime/tests/compare_dispatchers.sh diff --git a/runtime/tests/compare_dispatchers.sh b/runtime/tests/compare_dispatchers.sh new file mode 100755 index 000000000..db9b65927 --- /dev/null +++ b/runtime/tests/compare_dispatchers.sh @@ -0,0 +1,71 @@ +#!/bin/bash +ulimit -n 655350 + +function usage { + echo "$0 [worker num] [listener num] [first worker core id] [dispatcher policy, SHINJUKU, EDF_INTERRUPT, DARC, TO_GLOBAL_QUEUE, RR, JSQ, LLD] [server log file] [disable busy loop] [disable autoscaling] [disable service time simulation] [json config]" + exit 1 +} + +if [ $# != 9 ] ; then + usage + exit 1; +fi + +worker_num=$1 +listener_num=$2 +first_worker_core_id=$3 +dispatcher_policy=$4 +scheduler_policy="EDF" +server_log=$5 +disable_busy_loop=$6 +disable_autoscaling=$7 +disable_service_ts_simulation=$8 +json_config=$9 + +if [ "$scheduler_policy" = "FIFO" ]; then + worker_group_size=1 +else + worker_group_size=$((worker_num / listener_num)) +fi + +disable_preemption=true + +declare project_path="$( + cd "$(dirname "$0")/../.." + pwd +)" +echo $project_path +path=`pwd` +export SLEDGE_DISABLE_PREEMPTION=$disable_preemption +export SLEDGE_DISABLE_BUSY_LOOP=$disable_busy_loop +export SLEDGE_DISABLE_AUTOSCALING=$disable_autoscaling +#export SLEDGE_SIGALRM_HANDLER=TRIAGED +export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=$disable_service_ts_simulation +export SLEDGE_FIRST_WORKER_COREID=$first_worker_core_id +export SLEDGE_NWORKERS=$worker_num +export SLEDGE_NLISTENERS=$listener_num +export SLEDGE_WORKER_GROUP_SIZE=$worker_group_size +export SLEDGE_SCHEDULER=$scheduler_policy +#export SLEDGE_DISPATCHER=DARC +export SLEDGE_DISPATCHER=$dispatcher_policy +export SLEDGE_SCHEDULER=$scheduler_policy +#export SLEDGE_DISPATCHER=EDF_INTERRUPT +export SLEDGE_SANDBOX_PERF_LOG=$path/$server_log +#echo $SLEDGE_SANDBOX_PERF_LOG +cd $project_path/runtime/bin +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_fibonacci.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_big_fibonacci.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_armcifar10.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_png2bmp.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_image_processing.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/mulitple_linear_chain.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_multiple_image_processing3.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/hash.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/empty.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/fib.json +LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/$json_config +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/my_fibonacci.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_sodresize.json +#LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/my_sodresize.json + From abb5a6f1c41ab1aa63edd615bb8ea7e5b80d793a Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 20 May 2025 17:28:53 -0600 Subject: [PATCH 169/198] upload vision_apps_dispatcher.json --- runtime/tests/vision_apps_dispatcher.json | 36 +++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 runtime/tests/vision_apps_dispatcher.json diff --git a/runtime/tests/vision_apps_dispatcher.json b/runtime/tests/vision_apps_dispatcher.json new file mode 100644 index 000000000..0b874be06 --- /dev/null +++ b/runtime/tests/vision_apps_dispatcher.json @@ -0,0 +1,36 @@ +[ + { + "name": "gwu", + "port": 31850, + "replenishment-period-us": 0, + "max-budget-us": 0, + "routes": [ + { + "route": "/sift", + "request-type": 1, + "n-resas": 3, + "group-id": 1, + "path": "sift.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 113, + "relative-deadline-us": 11300, + "http-resp-content-type": "text/plain" + }, + { + "route": "/cifar10", + "request-type": 2, + "n-resas": 1, + "group-id": 2, + "path": "cifar10.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 2060, + "relative-deadline-us": 20600, + "http-resp-content-type": "text/plain" + } + + ] + + } + +] + From a485c7bd55dfd44969c629e3f098e6af96c73c4d Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 22 May 2025 14:18:08 -0600 Subject: [PATCH 170/198] add new support for LLD + FIFO: Dispatcher assign requests to workers with LLD and without preempt, worker schedule its local queue task with Round Robin and timer interrupt --- runtime/include/erpc_handler.h | 1 + runtime/include/http_router.h | 14 +++- runtime/include/ps_list.h | 2 + runtime/include/scheduler.h | 25 ++++-- runtime/include/scheduler_options.h | 1 + runtime/src/listener_thread.c | 7 +- runtime/src/local_runqueue_list.c | 125 +++++++++++++++++++++++++--- runtime/src/main.c | 5 ++ runtime/src/scheduler.c | 1 + 9 files changed, 159 insertions(+), 22 deletions(-) diff --git a/runtime/include/erpc_handler.h b/runtime/include/erpc_handler.h index c67ada041..eefaf13b6 100644 --- a/runtime/include/erpc_handler.h +++ b/runtime/include/erpc_handler.h @@ -8,3 +8,4 @@ void enqueue_to_global_queue_req_handler(void *req_handle, uint8_t req_type, uin void rr_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); void jsq_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); void lld_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); +void lld_req_handler_without_interrupt(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); diff --git a/runtime/include/http_router.h b/runtime/include/http_router.h index 28fa7c2b6..cce8883c4 100644 --- a/runtime/include/http_router.h +++ b/runtime/include/http_router.h @@ -77,9 +77,19 @@ http_router_add_route(http_router_t *router, struct route_config *config, struct if (erpc_register_req_func(config->request_type, jsq_req_handler, 0) != 0) { panic("register erpc function for join shortest queue distribution failed\n"); } - } else if (dispatcher == DISPATCHER_LLD) { + } else if (dispatcher == DISPATCHER_LLD && scheduler == SCHEDULER_EDF) { + /* Dispatcher assign requests to workers with LLD + interrupt, and each worker schedule its + local queue tasks with EDF + */ if (erpc_register_req_func(config->request_type, lld_req_handler, 0) != 0) { - panic("register erpc function for leatest load distribution failed\n"); + panic("register erpc function for leatest load distribution with edf failed\n"); + } + } else if (dispatcher == DISPATCHER_LLD && scheduler == SCHEDULER_FIFO) { + /* Dispatcher assign requests to workers with LLD and no interrupt, and each worker schedule + its local queue tasks with Round Robin with fixed interval preemption + */ + if (erpc_register_req_func(config->request_type, lld_req_handler_without_interrupt, 0) != 0) { + panic("register erpc function for leatest load distribution with fifo failed\n"); } } diff --git a/runtime/include/ps_list.h b/runtime/include/ps_list.h index fb2ec30ff..7a893d6b1 100644 --- a/runtime/include/ps_list.h +++ b/runtime/include/ps_list.h @@ -49,6 +49,7 @@ #ifndef PS_LIST_H #define PS_LIST_H +#include "lock.h" struct ps_list { struct ps_list *n, *p; }; @@ -60,6 +61,7 @@ struct ps_list { */ struct ps_list_head { struct ps_list l; + lock_t lock; }; #define PS_LIST_DEF_NAME list diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index 2b8545615..f83ae28fd 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -155,8 +155,12 @@ scheduler_fifo_get_next() struct sandbox *global = NULL; if (local == NULL) { + if (disable_get_req_from_GQ) { + return NULL; + } + /* If the local runqueue is empty, pull from global request scheduler */ - if (global_request_scheduler_remove(&global) < 0) goto done; + if (global_request_scheduler_remove(&global) < 0) return NULL; if (global->state == SANDBOX_INITIALIZED) { /* add by xiaosu */ @@ -172,11 +176,20 @@ scheduler_fifo_get_next() } else if (local == current_sandbox_get()) { /* Execute Round Robin Scheduling Logic if the head is the current sandbox */ local_runqueue_list_rotate(); - } - - -done: - return local_runqueue_get_next(); + } + + local = local_runqueue_get_next(); + if (local->state == SANDBOX_INITIALIZED) { + /* add by xiaosu */ + uint64_t now = __getcycles(); + local->timestamp_of.dispatched = now; + local->duration_of_state[SANDBOX_INITIALIZED] = 0; + local->timestamp_of.last_state_change = now; + /* end by xiaosu */ + sandbox_prepare_execution_environment(local); + sandbox_set_as_runnable(local, SANDBOX_INITIALIZED); + } + return local; } static inline struct sandbox * diff --git a/runtime/include/scheduler_options.h b/runtime/include/scheduler_options.h index 930dbd640..b918f4664 100644 --- a/runtime/include/scheduler_options.h +++ b/runtime/include/scheduler_options.h @@ -9,3 +9,4 @@ enum SCHEDULER }; extern enum SCHEDULER scheduler; +extern bool disable_get_req_from_GQ; diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 37a5c625e..ad40b6aaf 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -40,6 +40,7 @@ uint32_t worker_new_sandbox[1024] = {0}; struct perf_window * worker_perf_windows[1024]; struct priority_queue * worker_queues[1024]; struct binary_tree * worker_binary_trees[1024]; +struct ps_list_head * worker_fifo_queue[1024]; struct request_fifo_queue * worker_circular_queue[1024]; struct request_fifo_queue * worker_preempted_queue[1024]; @@ -950,7 +951,7 @@ void rr_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t siz } } -void rr_req_handler2(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { +void rr_req_handler_without_interrupt(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { if (first_request_comming == false){ t_start = time(NULL); @@ -1018,7 +1019,7 @@ void rr_req_handler2(void *req_handle, uint8_t req_type, uint8_t *msg, size_t si rr_index++; } -void jsq_req_handler2(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { +void jsq_req_handler_without_interrupt(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { if (first_request_comming == false){ t_start = time(NULL); @@ -1098,7 +1099,7 @@ void jsq_req_handler2(void *req_handle, uint8_t req_type, uint8_t *msg, size_t s local_runqueue_add_index(min_index, sandbox); } -void lld_req_handler2(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { +void lld_req_handler_without_interrupt(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port) { if (first_request_comming == false){ t_start = time(NULL); diff --git a/runtime/src/local_runqueue_list.c b/runtime/src/local_runqueue_list.c index 20e19c768..697a3c645 100644 --- a/runtime/src/local_runqueue_list.c +++ b/runtime/src/local_runqueue_list.c @@ -6,14 +6,38 @@ #include "local_runqueue.h" #include "sandbox_functions.h" +extern thread_local int global_worker_thread_idx; +extern _Atomic uint32_t local_queue_length[1024]; +extern uint32_t max_local_queue_length[1024]; +extern struct ps_list_head * worker_fifo_queue[1024]; thread_local static struct ps_list_head local_runqueue_list; +int +local_runqueue_list_get_length_index(int index) +{ + return local_queue_length[index]; +} + +int +local_runqueue_list_get_length() +{ + return local_queue_length[global_worker_thread_idx]; +} + bool local_runqueue_list_is_empty() { return ps_list_head_empty(&local_runqueue_list); } +bool +local_runqueue_list_is_empty_index(int index) +{ + struct ps_list_head *local_queue = worker_fifo_queue[index]; + assert(local_queue != NULL); + return ps_list_head_empty(local_queue); +} + /* Get the sandbox at the head of the thread local runqueue */ struct sandbox * local_runqueue_list_get_head() @@ -21,6 +45,17 @@ local_runqueue_list_get_head() return ps_list_head_first_d(&local_runqueue_list, struct sandbox); } +/** + * Removes the sandbox from the thread-local runqueue + * @param sandbox sandbox + */ +void +local_runqueue_list_remove_nolock(struct sandbox *sandbox_to_remove) +{ + ps_list_rem_d(sandbox_to_remove); + atomic_fetch_sub(&local_queue_length[global_worker_thread_idx], 1); +} + /** * Removes the sandbox from the thread-local runqueue * @param sandbox sandbox @@ -28,7 +63,11 @@ local_runqueue_list_get_head() void local_runqueue_list_remove(struct sandbox *sandbox_to_remove) { + lock_node_t node = {}; + lock_lock(&local_runqueue_list.lock, &node); ps_list_rem_d(sandbox_to_remove); + lock_unlock(&local_runqueue_list.lock, &node); + atomic_fetch_sub(&local_queue_length[global_worker_thread_idx], 1); } struct sandbox * @@ -36,11 +75,13 @@ local_runqueue_list_remove_and_return() { struct sandbox *sandbox_to_remove = ps_list_head_first_d(&local_runqueue_list, struct sandbox); ps_list_rem_d(sandbox_to_remove); + atomic_fetch_sub(&local_queue_length[global_worker_thread_idx], 1); return sandbox_to_remove; } /** - * Append a sandbox to the tail of the runqueue + * Append a sandbox to the tail of the runqueue, only called by the self thread + * Only called by the self thread and pull requests from the GQ, no need lock * @returns the appended sandbox */ void @@ -49,18 +90,59 @@ local_runqueue_list_append(struct sandbox *sandbox_to_append) assert(sandbox_to_append != NULL); assert(ps_list_singleton_d(sandbox_to_append)); ps_list_head_append_d(&local_runqueue_list, sandbox_to_append); + atomic_fetch_add(&local_queue_length[global_worker_thread_idx], 1); + if (local_queue_length[global_worker_thread_idx] > max_local_queue_length[global_worker_thread_idx]) { + max_local_queue_length[global_worker_thread_idx] = local_queue_length[global_worker_thread_idx]; + } +} + +/** + * Append a sandbox to the tail of the runqueue, will be called by the listener thread, need lock + * @returns the appended sandbox + */ +void +local_runqueue_list_append_index(int index, struct sandbox *sandbox_to_append) +{ + struct ps_list_head *local_queue = worker_fifo_queue[index]; + assert(local_queue != NULL); + assert(sandbox_to_append != NULL); + assert(ps_list_singleton_d(sandbox_to_append)); + lock_node_t node = {}; + lock_lock(&local_queue->lock, &node); + ps_list_head_append_d(local_queue, sandbox_to_append); + lock_unlock(&local_queue->lock, &node); + atomic_fetch_add(&local_queue_length[index], 1); + if (local_queue_length[index] > max_local_queue_length[index]) { + max_local_queue_length[index] = local_queue_length[index]; + } } /* Remove sandbox from head of runqueue and add it to tail */ void local_runqueue_list_rotate() { - /* If runqueue is size one, skip round robin logic since tail equals head */ - if (ps_list_head_one_node(&local_runqueue_list)) return; + if (dispatcher == DISPATCHER_LLD) { + /* need lock */ + lock_node_t node = {}; + lock_lock(&local_runqueue_list.lock, &node); + /* If runqueue is size one, skip round robin logic since tail equals head */ + if (ps_list_head_one_node(&local_runqueue_list)) { + lock_unlock(&local_runqueue_list.lock, &node); + return; + } + + struct sandbox *sandbox_at_head = local_runqueue_list_remove_and_return(); + assert(sandbox_at_head->state == SANDBOX_INTERRUPTED); + local_runqueue_list_append(sandbox_at_head); + lock_unlock(&local_runqueue_list.lock, &node); + } else { /* no need lock */ + /* If runqueue is size one, skip round robin logic since tail equals head */ + if (ps_list_head_one_node(&local_runqueue_list)) return; - struct sandbox *sandbox_at_head = local_runqueue_list_remove_and_return(); - assert(sandbox_at_head->state == SANDBOX_INTERRUPTED); - local_runqueue_list_append(sandbox_at_head); + struct sandbox *sandbox_at_head = local_runqueue_list_remove_and_return(); + assert(sandbox_at_head->state == SANDBOX_INTERRUPTED); + local_runqueue_list_append(sandbox_at_head); + } } /** @@ -68,22 +150,43 @@ local_runqueue_list_rotate() * @return the sandbox to execute or NULL if none are available */ struct sandbox * -local_runqueue_list_get_next() +local_runqueue_list_get_next_nolock() { if (local_runqueue_list_is_empty()) return NULL; return local_runqueue_list_get_head(); } +struct sandbox * +local_runqueue_list_get_next() +{ + if (local_runqueue_list_is_empty()) return NULL; + lock_node_t node = {}; + lock_lock(&local_runqueue_list.lock, &node); + struct sandbox *sandbox = local_runqueue_list_get_head(); + lock_unlock(&local_runqueue_list.lock, &node); + return sandbox; +} + void local_runqueue_list_initialize() { ps_list_head_init(&local_runqueue_list); + worker_fifo_queue[global_worker_thread_idx] = &local_runqueue_list; /* Register Function Pointers for Abstract Scheduling API */ - struct local_runqueue_config config = { .add_fn = local_runqueue_list_append, - .is_empty_fn = local_runqueue_list_is_empty, - .delete_fn = local_runqueue_list_remove, - .get_next_fn = local_runqueue_list_get_next }; + struct local_runqueue_config config = { .add_fn = local_runqueue_list_append, + .add_fn_idx = local_runqueue_list_append_index, + .get_length_fn_idx = local_runqueue_list_get_length_index, + .get_length_fn = local_runqueue_list_get_length, + .is_empty_fn = local_runqueue_list_is_empty, + .is_empty_fn_idx = local_runqueue_list_is_empty_index}; + if (dispatcher == DISPATCHER_LLD) { + config.delete_fn = local_runqueue_list_remove; + config.get_next_fn = local_runqueue_list_get_next; + } else {// must be DISPATCHER_TO_GLOBAL_QUEUE + config.delete_fn = local_runqueue_list_remove_nolock; + config.get_next_fn = local_runqueue_list_get_next_nolock; + } local_runqueue_initialize(&config); }; diff --git a/runtime/src/main.c b/runtime/src/main.c index 2273efa95..7feff4de4 100644 --- a/runtime/src/main.c +++ b/runtime/src/main.c @@ -266,6 +266,11 @@ runtime_configure() } pretty_print_key_value("Scheduler Policy", "%s\n", scheduler_print(scheduler)); + char* disable_get_req_from_global_queue = getenv("SLEDGE_DISABLE_GET_REQUESTS_FROM_GQ"); + if (disable_get_req_from_global_queue != NULL && strcmp(disable_get_req_from_global_queue, "false") != 0) disable_get_req_from_GQ = true; + pretty_print_key_value("Enable getting req from GQ", "%s\n", + disable_get_req_from_GQ == false ? PRETTY_PRINT_GREEN_ENABLED : PRETTY_PRINT_RED_DISABLED); + /* Dispatcher Policy */ char *dispatcher_policy = getenv("SLEDGE_DISPATCHER"); if (dispatcher_policy == NULL) dispatcher_policy = "EDF_INTERRUPT"; diff --git a/runtime/src/scheduler.c b/runtime/src/scheduler.c index e6c67b135..6f6b67b7b 100644 --- a/runtime/src/scheduler.c +++ b/runtime/src/scheduler.c @@ -1,3 +1,4 @@ #include "scheduler.h" enum SCHEDULER scheduler = SCHEDULER_EDF; +bool disable_get_req_from_GQ = false; From 37d15477da25ea47fe6f11f62a5f455953733041 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Thu, 22 May 2025 19:43:27 -0600 Subject: [PATCH 171/198] 1. replace Semaphore with condition variable to avoid signal missing and decrase performance issue. 2. Add checking runtime configuration variable validation --- runtime/include/scheduler.h | 11 ++++------- runtime/src/local_runqueue.c | 11 +++++++---- runtime/src/main.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index f83ae28fd..67f3acd25 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -512,24 +512,21 @@ scheduler_idle_loop() } /* If queue is empty, then sleep to wait for the condition variable or sempahore */ if (!runtime_worker_busy_loop_enabled) { - /*struct timespec endT; - int64_t delta_us = 0; pthread_mutex_lock(&mutexs[global_worker_thread_idx]); if (local_runqueue_is_empty()) { pthread_cond_wait(&conds[global_worker_thread_idx], &mutexs[global_worker_thread_idx]); - clock_gettime(CLOCK_MONOTONIC, &endT); - delta_us = (endT.tv_sec - startT[global_worker_thread_idx].tv_sec) * 1000000 + (endT.tv_nsec - startT[global_worker_thread_idx].tv_nsec) / 1000; } pthread_mutex_unlock(&mutexs[global_worker_thread_idx]); - printf("worker %d delta %ld\n", global_worker_thread_idx, delta_us); + /* Semaphore could lost signal and cause worker block for a short time decrasing performance, + so not use the following code but condition variable */ - if (local_runqueue_is_empty()) { + /*if (local_runqueue_is_empty()) { sem_wait(&semlock[global_worker_thread_idx]); //struct timespec endT; //clock_gettime(CLOCK_MONOTONIC, &endT); //int64_t delta_us = (endT.tv_sec - startT[global_worker_thread_idx].tv_sec) * 1000000 + (endT.tv_nsec - startT[global_worker_thread_idx].tv_nsec) / 1000; //printf("worker %d delta %ld\n", global_worker_thread_idx, delta_us); - } + }*/ } } } diff --git a/runtime/src/local_runqueue.c b/runtime/src/local_runqueue.c index 2ea5bdd4c..826911e38 100644 --- a/runtime/src/local_runqueue.c +++ b/runtime/src/local_runqueue.c @@ -44,7 +44,7 @@ local_runqueue_add_index(int index, struct sandbox *sandbox) /* wakeup worker if it is empty before we add a new request */ if (!runtime_worker_busy_loop_enabled) { - /*pthread_mutex_lock(&mutexs[index]); + pthread_mutex_lock(&mutexs[index]); if (local_runqueue_is_empty_index(index)) { local_runqueue.add_fn_idx(index, sandbox); //atomic_fetch_add(&local_runqueue_count[index], 1); @@ -54,15 +54,18 @@ local_runqueue_add_index(int index, struct sandbox *sandbox) } else { pthread_mutex_unlock(&mutexs[index]); local_runqueue.add_fn_idx(index, sandbox); - }*/ + } - if (local_runqueue_is_empty_index(index)) { + /* Semaphore could lost signal and cause worker block for a short time decrasing performance, + so not use the following code but condition variable + */ + /*if (local_runqueue_is_empty_index(index)) { local_runqueue.add_fn_idx(index, sandbox); //clock_gettime(CLOCK_MONOTONIC, &startT[index]); sem_post(&semlock[index]); } else { local_runqueue.add_fn_idx(index, sandbox); - } + }*/ } else { local_runqueue.add_fn_idx(index, sandbox); } diff --git a/runtime/src/main.c b/runtime/src/main.c index 7feff4de4..2fef8c3a8 100644 --- a/runtime/src/main.c +++ b/runtime/src/main.c @@ -244,6 +244,36 @@ runtime_start_runtime_worker_threads() } } +void +runtime_config_validate() +{ + if (dispatcher == DISPATCHER_TO_GLOBAL_QUEUE) { + if (runtime_worker_busy_loop_enabled == false) { + panic("Must enable busy loop if dispatcher is TO_GLOBAL_QUEUE\n"); + + } + + if (disable_get_req_from_GQ == true) { + panic("Must enable get request from GQ if dispatcher is TO_GLOBAL_QUEUE\n"); + } + + if (scheduler != SCHEDULER_FIFO) { + panic("Must use FIFO scheduler if dispatcher is TO_GLOBAL_QUEUE\n"); + } + } else { + if (disable_get_req_from_GQ == false) { + panic("Must disable get requests from GQ if dispatcher is not TO_GLOBAL_QUEUE\n"); + } + } + + if (dispatcher == DISPATCHER_RR || dispatcher == DISPATCHER_JSQ || dispatcher == DISPATCHER_EDF_INTERRUPT + || dispatcher == DISPATCHER_SHINJUKU || dispatcher == DISPATCHER_DARC || dispatcher == DISPATCHER_LLD && scheduler == SCHEDULER_EDF) { + if (runtime_preemption_enabled == true) { + panic("Must disable preemption if dispatcher is RR, JSQ, EDF_INTERRUPT, or LLD + EDF\n"); + } + } + +} void runtime_configure() { @@ -324,6 +354,9 @@ runtime_configure() pretty_print_key_value("Worker busy loop", "%s\n", runtime_worker_busy_loop_enabled ? PRETTY_PRINT_GREEN_ENABLED : PRETTY_PRINT_RED_DISABLED); + + /* Check validation */ + runtime_config_validate(); /* Runtime Quantum */ char *quantum_raw = getenv("SLEDGE_QUANTUM_US"); if (quantum_raw != NULL) { From 492fbb6a7f647d281577de281956bb8a2c76850a Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 23 May 2025 00:40:19 -0600 Subject: [PATCH 172/198] update start_test.sh --- runtime/tests/start_test.sh | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/runtime/tests/start_test.sh b/runtime/tests/start_test.sh index bd39a6848..c4c7f66c0 100755 --- a/runtime/tests/start_test.sh +++ b/runtime/tests/start_test.sh @@ -1,12 +1,21 @@ #!/bin/bash + +#1. For LLD + worker FIFO, dispatcher assign requests to worker with LLD, and worker schedule local queue task with RR, so SLEDGE_DISABLE_GET_REQUESTS_FROM_GQ +# should be true, SLEDGE_DISABLE_PREEMPTION should be false +#2. For TO_GLOBAL_QUEUE + worker FIFO, dispatcher put requests to a global queue, and each worker compete to get requests from the global queue, so +# SLEDGE_DISABLE_GET_REQUESTS_FROM_GQ should be false, SLEDGE_DISABLE_PREEMPTION doesnt matter, for scalability test, set SLEDGE_DISABLE_PREEMPTION to true to +# remove context switch. +#3. Other non FIFO schedulers, dispatcher assign requests to worker and interrupt workers, so SLEDGE_DISABLE_PREEMPTION should be true, +# SLEDGE_DISABLE_GET_REQUESTS_FROM_GQ should be true. + ulimit -n 655350 function usage { - echo "$0 [worker num] [listener num] [first worker core id] [dispatcher policy, SHINJUKU, EDF_INTERRUPT, DARC or TO_GLOBAL_QUEUE] [scheduler policy, EDF or FIFO] [server log file] [disable busy loop] [disable autoscaling] [disable service time simulation] [json config]" + echo "$0 [worker num] [listener num] [first worker core id] [dispatcher policy, SHINJUKU, EDF_INTERRUPT, DARC, LLD, or TO_GLOBAL_QUEUE] [scheduler policy, EDF or FIFO] [server log file] [disable busy loop] [disable service time simulation] [disable get requests from GQ] [disable preemption] [json config]" exit 1 } -if [ $# != 10 ] ; then +if [ $# != 11 ] ; then usage exit 1; fi @@ -18,12 +27,14 @@ dispatcher_policy=$4 scheduler_policy=$5 server_log=$6 disable_busy_loop=$7 -disable_autoscaling=$8 -disable_service_ts_simulation=$9 -json_config=${10} +disable_autoscaling=true +disable_service_ts_simulation=$8 +disable_get_req_from_GQ=${9} +disable_preemption=${10} +json_config=${11} if [ "$scheduler_policy" = "FIFO" ]; then - worker_group_size=1 + worker_group_size=$worker_num else worker_group_size=$((worker_num / listener_num)) fi @@ -34,7 +45,9 @@ declare project_path="$( )" echo $project_path path=`pwd` -export SLEDGE_DISABLE_PREEMPTION=true +export SLEDGE_DISABLE_PREEMPTION=$disable_preemption +#only works for FIFO scheduler +export SLEDGE_DISABLE_GET_REQUESTS_FROM_GQ=$disable_get_req_from_GQ export SLEDGE_DISABLE_BUSY_LOOP=$disable_busy_loop export SLEDGE_DISABLE_AUTOSCALING=$disable_autoscaling #export SLEDGE_SIGALRM_HANDLER=TRIAGED From d873ca097b358c4e705ec5cd8ae5deba1454c3be Mon Sep 17 00:00:00 2001 From: xiaosuGW Date: Fri, 23 May 2025 12:51:27 -0600 Subject: [PATCH 173/198] Recover to use Semaphore since it has a better performance than condition variable based on the test --- runtime/include/scheduler.h | 13 +++++-------- runtime/src/local_runqueue.c | 10 +++++----- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index 67f3acd25..55cf24afc 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -512,21 +512,18 @@ scheduler_idle_loop() } /* If queue is empty, then sleep to wait for the condition variable or sempahore */ if (!runtime_worker_busy_loop_enabled) { - pthread_mutex_lock(&mutexs[global_worker_thread_idx]); + /*pthread_mutex_lock(&mutexs[global_worker_thread_idx]); if (local_runqueue_is_empty()) { pthread_cond_wait(&conds[global_worker_thread_idx], &mutexs[global_worker_thread_idx]); } pthread_mutex_unlock(&mutexs[global_worker_thread_idx]); + */ /* Semaphore could lost signal and cause worker block for a short time decrasing performance, - so not use the following code but condition variable + but based on test, it seems Semaphore has a better performance than condition variable */ - /*if (local_runqueue_is_empty()) { + if (local_runqueue_is_empty()) { sem_wait(&semlock[global_worker_thread_idx]); - //struct timespec endT; - //clock_gettime(CLOCK_MONOTONIC, &endT); - //int64_t delta_us = (endT.tv_sec - startT[global_worker_thread_idx].tv_sec) * 1000000 + (endT.tv_nsec - startT[global_worker_thread_idx].tv_nsec) / 1000; - //printf("worker %d delta %ld\n", global_worker_thread_idx, delta_us); - }*/ + } } } } diff --git a/runtime/src/local_runqueue.c b/runtime/src/local_runqueue.c index 826911e38..a7e243326 100644 --- a/runtime/src/local_runqueue.c +++ b/runtime/src/local_runqueue.c @@ -44,7 +44,7 @@ local_runqueue_add_index(int index, struct sandbox *sandbox) /* wakeup worker if it is empty before we add a new request */ if (!runtime_worker_busy_loop_enabled) { - pthread_mutex_lock(&mutexs[index]); + /*pthread_mutex_lock(&mutexs[index]); if (local_runqueue_is_empty_index(index)) { local_runqueue.add_fn_idx(index, sandbox); //atomic_fetch_add(&local_runqueue_count[index], 1); @@ -54,18 +54,18 @@ local_runqueue_add_index(int index, struct sandbox *sandbox) } else { pthread_mutex_unlock(&mutexs[index]); local_runqueue.add_fn_idx(index, sandbox); - } + }*/ /* Semaphore could lost signal and cause worker block for a short time decrasing performance, - so not use the following code but condition variable + but based on test, it seems Semaphore has a better performance than condition variable */ - /*if (local_runqueue_is_empty_index(index)) { + if (local_runqueue_is_empty_index(index)) { local_runqueue.add_fn_idx(index, sandbox); //clock_gettime(CLOCK_MONOTONIC, &startT[index]); sem_post(&semlock[index]); } else { local_runqueue.add_fn_idx(index, sandbox); - }*/ + } } else { local_runqueue.add_fn_idx(index, sandbox); } From e68c20d9b856e2ab256c387db919e49f0acc8a54 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 23 May 2025 14:46:36 -0600 Subject: [PATCH 174/198] upload get_ctx.sh --- runtime/tests/get_ctx.sh | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100755 runtime/tests/get_ctx.sh diff --git a/runtime/tests/get_ctx.sh b/runtime/tests/get_ctx.sh new file mode 100755 index 000000000..4a4a3fedc --- /dev/null +++ b/runtime/tests/get_ctx.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +function usage { + echo "$0 [concurrency]" + exit 1 +} + +if [ $# != 1 ] ; then + usage + exit 1; +fi + +concurrency=$1 +output="${concurrency}_ctx.txt" +pid=`ps -ef|grep "sledgert"|grep -v grep |awk '{print $2}'` +total_switches=0 + +if [ -z "$pid" ] || [ ! -d "/proc/$pid" ]; then + echo "PID $pid not found or no longer exists, skipping" | tee -a $output + exit 1 +fi + +echo "PID $pid:" | tee -a $output + +for tid in $(ls /proc/$pid/task); do + thread_name=$(cat /proc/$pid/task/$tid/comm 2>/dev/null) + + if [ "$thread_name" = "worker_thread" ]; then + if [ -f "/proc/$pid/task/$tid/sched" ]; then + tid_switches=$(grep nr_switches /proc/$pid/task/$tid/sched | awk '{print $3}') + echo " TID $tid (name=$thread_name): nr_switches = $tid_switches" | tee -a $output + total_switches=$((total_switches + tid_switches)) + fi + fi +done + +echo "----------------------------------------" | tee -a $output +echo "Total nr_switches for all 'worker_thread' threads: $total_switches" | tee -a $output +echo "Results saved to $output" From 1a0f19b68411cac40fbfcb8c59076c47ca8ef6e5 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 23 May 2025 14:48:10 -0600 Subject: [PATCH 175/198] update start_func_density_test.sh and compare_dispatchers.sh --- runtime/tests/compare_dispatchers.sh | 11 ++++++----- runtime/tests/start_func_density_test.sh | 4 ++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/runtime/tests/compare_dispatchers.sh b/runtime/tests/compare_dispatchers.sh index db9b65927..46395e209 100755 --- a/runtime/tests/compare_dispatchers.sh +++ b/runtime/tests/compare_dispatchers.sh @@ -2,11 +2,11 @@ ulimit -n 655350 function usage { - echo "$0 [worker num] [listener num] [first worker core id] [dispatcher policy, SHINJUKU, EDF_INTERRUPT, DARC, TO_GLOBAL_QUEUE, RR, JSQ, LLD] [server log file] [disable busy loop] [disable autoscaling] [disable service time simulation] [json config]" + echo "$0 [worker num] [listener num] [first worker core id] [dispatcher policy, EDF_INTERRUPT, RR, JSQ, LLD] [server log file] [disable busy loop] [disable service time simulation] [json config]" exit 1 } -if [ $# != 9 ] ; then +if [ $# != 8 ] ; then usage exit 1; fi @@ -18,9 +18,9 @@ dispatcher_policy=$4 scheduler_policy="EDF" server_log=$5 disable_busy_loop=$6 -disable_autoscaling=$7 -disable_service_ts_simulation=$8 -json_config=$9 +disable_autoscaling="true" +disable_service_ts_simulation=$7 +json_config=$8 if [ "$scheduler_policy" = "FIFO" ]; then worker_group_size=1 @@ -37,6 +37,7 @@ declare project_path="$( echo $project_path path=`pwd` export SLEDGE_DISABLE_PREEMPTION=$disable_preemption +export SLEDGE_DISABLE_GET_REQUESTS_FROM_GQ=true export SLEDGE_DISABLE_BUSY_LOOP=$disable_busy_loop export SLEDGE_DISABLE_AUTOSCALING=$disable_autoscaling #export SLEDGE_SIGALRM_HANDLER=TRIAGED diff --git a/runtime/tests/start_func_density_test.sh b/runtime/tests/start_func_density_test.sh index edf627a10..81d46cd3a 100755 --- a/runtime/tests/start_func_density_test.sh +++ b/runtime/tests/start_func_density_test.sh @@ -32,8 +32,12 @@ declare project_path="$( echo $project_path path=`pwd` export SLEDGE_DISABLE_PREEMPTION=true +#only works for TO_GLOBAL_QUEUE and FIFO +export SLEDGE_DISABLE_GET_REQUESTS_FROM_GQ=false export SLEDGE_DISABLE_BUSY_LOOP=$disable_busy_loop export SLEDGE_DISABLE_AUTOSCALING=true +#only works for FIFO scheduler +export SLEDGE_DISABLE_GET_REQUESTS_FROM_GQ=false export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=true #export SLEDGE_SIGALRM_HANDLER=TRIAGED export SLEDGE_FIRST_WORKER_COREID=$first_worker_core_id From 9bac4a61cedb0a9f1abc99eb454e031d02455b52 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Fri, 23 May 2025 14:58:32 -0600 Subject: [PATCH 176/198] update increase_req_type.patch --- runtime/increase_req_type.patch | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/runtime/increase_req_type.patch b/runtime/increase_req_type.patch index 08460689d..481dfa2ac 100644 --- a/runtime/increase_req_type.patch +++ b/runtime/increase_req_type.patch @@ -1,8 +1,8 @@ diff --git a/runtime/include/erpc_handler.h b/runtime/include/erpc_handler.h -index b506eb8..4424a97 100644 +index eefaf13..47324f8 100644 --- a/runtime/include/erpc_handler.h +++ b/runtime/include/erpc_handler.h -@@ -1,7 +1,7 @@ +@@ -1,10 +1,10 @@ #pragma once #include @@ -12,11 +12,14 @@ index b506eb8..4424a97 100644 void shinjuku_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); -void enqueue_to_global_queue_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); +void enqueue_to_global_queue_req_handler(void *req_handle, uint16_t req_type, uint8_t *msg, size_t size, uint16_t port); + void rr_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); + void jsq_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); + void lld_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); diff --git a/runtime/include/http_router.h b/runtime/include/http_router.h -index c8e5a7e..1ca37b1 100644 +index cce8883..e0da7ee 100644 --- a/runtime/include/http_router.h +++ b/runtime/include/http_router.h -@@ -96,7 +96,7 @@ http_router_match_route(http_router_t *router, char *route) +@@ -118,7 +118,7 @@ http_router_match_route(http_router_t *router, char *route) } static inline struct route * @@ -367,10 +370,10 @@ index 711db96..443b227 100644 * Initializes perf window * @param admissions_info diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c -index a8d2fc4..f4244b7 100644 +index ad40b6a..9a00119 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c -@@ -472,7 +472,7 @@ on_client_socket_epoll_event(struct epoll_event *evt) +@@ -474,7 +474,7 @@ on_client_socket_epoll_event(struct epoll_event *evt) * @param msg the payload of the rpc request. It is the input parameter fot the function * @param size the size of the msg */ @@ -379,7 +382,7 @@ index a8d2fc4..f4244b7 100644 if (first_request_comming == false){ t_start = time(NULL); -@@ -988,7 +988,7 @@ void shinjuku_dispatch() { +@@ -1547,7 +1547,7 @@ void shinjuku_dispatch() { } } @@ -389,7 +392,7 @@ index a8d2fc4..f4244b7 100644 if (first_request_comming == false){ t_start = time(NULL); diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c -index 67a8d9f..24440e5 100644 +index 70a919e..478f8df 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c @@ -24,16 +24,17 @@ @@ -420,7 +423,7 @@ index 67a8d9f..24440e5 100644 extern uint32_t runtime_worker_group_size; extern FILE *sandbox_perf_log; -@@ -101,6 +102,7 @@ worker_thread_main(void *argument) +@@ -102,6 +103,7 @@ worker_thread_main(void *argument) // runtime_set_pthread_prio(pthread_self(), 2); pthread_setschedprio(pthread_self(), -20); From 5822ac1b639e4bc153ed7587c56e058074ed1098 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Sun, 25 May 2025 11:46:23 -0600 Subject: [PATCH 177/198] make getting batch size from FIFO queue as a configurable variable --- runtime/include/scheduler.h | 31 +++++++++++++++++-------------- runtime/src/local_runqueue_list.c | 1 + runtime/src/main.c | 9 +++++++++ 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index 55cf24afc..066a20456 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -40,6 +40,7 @@ extern thread_local int dispatcher_id; extern pthread_mutex_t mutexs[1024]; extern pthread_cond_t conds[1024]; extern sem_t semlock[1024]; +extern uint32_t runtime_fifo_queue_batch_size; /** * This scheduler provides for cooperative and preemptive multitasking in a OS process's userspace. @@ -159,19 +160,21 @@ scheduler_fifo_get_next() return NULL; } - /* If the local runqueue is empty, pull from global request scheduler */ - if (global_request_scheduler_remove(&global) < 0) return NULL; - - if (global->state == SANDBOX_INITIALIZED) { - /* add by xiaosu */ - uint64_t now = __getcycles(); - global->timestamp_of.dispatched = now; - global->duration_of_state[SANDBOX_INITIALIZED] = 0; - global->timestamp_of.last_state_change = now; - /* end by xiaosu */ - sandbox_prepare_execution_environment(global); - local_runqueue_add(global); - sandbox_set_as_runnable(global, SANDBOX_INITIALIZED); + /* If the local runqueue is empty, pull a batch of requests from global request scheduler */ + for (int i = 0; i < runtime_fifo_queue_batch_size; i++ ) { + if (global_request_scheduler_remove(&global) < 0) break; + + if (global->state == SANDBOX_INITIALIZED) { + /* add by xiaosu */ + uint64_t now = __getcycles(); + global->timestamp_of.dispatched = now; + global->duration_of_state[SANDBOX_INITIALIZED] = 0; + global->timestamp_of.last_state_change = now; + /* end by xiaosu */ + sandbox_prepare_execution_environment(global); + local_runqueue_add(global); + sandbox_set_as_runnable(global, SANDBOX_INITIALIZED); + } } } else if (local == current_sandbox_get()) { /* Execute Round Robin Scheduling Logic if the head is the current sandbox */ @@ -179,7 +182,7 @@ scheduler_fifo_get_next() } local = local_runqueue_get_next(); - if (local->state == SANDBOX_INITIALIZED) { + if (local && local->state == SANDBOX_INITIALIZED) { /* add by xiaosu */ uint64_t now = __getcycles(); local->timestamp_of.dispatched = now; diff --git a/runtime/src/local_runqueue_list.c b/runtime/src/local_runqueue_list.c index 697a3c645..f7306c677 100644 --- a/runtime/src/local_runqueue_list.c +++ b/runtime/src/local_runqueue_list.c @@ -11,6 +11,7 @@ extern _Atomic uint32_t local_queue_length[1024]; extern uint32_t max_local_queue_length[1024]; extern struct ps_list_head * worker_fifo_queue[1024]; thread_local static struct ps_list_head local_runqueue_list; +uint32_t runtime_fifo_queue_batch_size = 1; int local_runqueue_list_get_length_index(int index) diff --git a/runtime/src/main.c b/runtime/src/main.c index 2fef8c3a8..4f13201b7 100644 --- a/runtime/src/main.c +++ b/runtime/src/main.c @@ -355,6 +355,15 @@ runtime_configure() runtime_worker_busy_loop_enabled ? PRETTY_PRINT_GREEN_ENABLED : PRETTY_PRINT_RED_DISABLED); + /* Runtime local FIFO queue batch size */ + char *batch_size = getenv("SLEDGE_FIFO_QUEUE_BATCH_SIZE"); + if (batch_size != NULL) { + runtime_fifo_queue_batch_size = atoi(batch_size); + if (runtime_fifo_queue_batch_size == 0) { + panic("Fifo queue batch size must be larger than 0\n"); + } + } + /* Check validation */ runtime_config_validate(); /* Runtime Quantum */ From f94383f3cde9a79600818a1d0d049d48d9f0988b Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Mon, 26 May 2025 01:34:30 -0600 Subject: [PATCH 178/198] update test scripts and vision_apps_dispatcher.json --- runtime/tests/compare_dispatchers.sh | 22 +++++++++++----------- runtime/tests/start_test.sh | 1 + runtime/tests/vision_apps_dispatcher.json | 2 +- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/runtime/tests/compare_dispatchers.sh b/runtime/tests/compare_dispatchers.sh index 46395e209..34ea09dd8 100755 --- a/runtime/tests/compare_dispatchers.sh +++ b/runtime/tests/compare_dispatchers.sh @@ -2,11 +2,11 @@ ulimit -n 655350 function usage { - echo "$0 [worker num] [listener num] [first worker core id] [dispatcher policy, EDF_INTERRUPT, RR, JSQ, LLD] [server log file] [disable busy loop] [disable service time simulation] [json config]" + echo "$0 [worker num] [listener num] [first worker core id] [dispatcher policy, EDF_INTERRUPT, RR, JSQ, LLD] [scheduler policy] [server log file] [disable busy loop] [disable service time simulation] [disable preempt] [disable get req from GQ] [json config]" exit 1 } -if [ $# != 8 ] ; then +if [ $# != 11 ] ; then usage exit 1; fi @@ -15,21 +15,21 @@ worker_num=$1 listener_num=$2 first_worker_core_id=$3 dispatcher_policy=$4 -scheduler_policy="EDF" -server_log=$5 -disable_busy_loop=$6 +scheduler_policy=$5 +server_log=$6 +disable_busy_loop=$7 +disable_service_ts_simulation=$8 +disable_preempt=$9 +disable_get_req_from_GQ=${10} disable_autoscaling="true" -disable_service_ts_simulation=$7 -json_config=$8 +json_config=${11} if [ "$scheduler_policy" = "FIFO" ]; then - worker_group_size=1 + worker_group_size=$worker_num else worker_group_size=$((worker_num / listener_num)) fi -disable_preemption=true - declare project_path="$( cd "$(dirname "$0")/../.." pwd @@ -37,7 +37,7 @@ declare project_path="$( echo $project_path path=`pwd` export SLEDGE_DISABLE_PREEMPTION=$disable_preemption -export SLEDGE_DISABLE_GET_REQUESTS_FROM_GQ=true +export SLEDGE_DISABLE_GET_REQUESTS_FROM_GQ=$disable_get_req_from_GQ export SLEDGE_DISABLE_BUSY_LOOP=$disable_busy_loop export SLEDGE_DISABLE_AUTOSCALING=$disable_autoscaling #export SLEDGE_SIGALRM_HANDLER=TRIAGED diff --git a/runtime/tests/start_test.sh b/runtime/tests/start_test.sh index c4c7f66c0..e92f03eb3 100755 --- a/runtime/tests/start_test.sh +++ b/runtime/tests/start_test.sh @@ -48,6 +48,7 @@ path=`pwd` export SLEDGE_DISABLE_PREEMPTION=$disable_preemption #only works for FIFO scheduler export SLEDGE_DISABLE_GET_REQUESTS_FROM_GQ=$disable_get_req_from_GQ +export SLEDGE_FIFO_QUEUE_BATCH_SIZE=5 export SLEDGE_DISABLE_BUSY_LOOP=$disable_busy_loop export SLEDGE_DISABLE_AUTOSCALING=$disable_autoscaling #export SLEDGE_SIGALRM_HANDLER=TRIAGED diff --git a/runtime/tests/vision_apps_dispatcher.json b/runtime/tests/vision_apps_dispatcher.json index 0b874be06..c9ffcb9ba 100644 --- a/runtime/tests/vision_apps_dispatcher.json +++ b/runtime/tests/vision_apps_dispatcher.json @@ -13,7 +13,7 @@ "path": "sift.wasm.so", "admissions-percentile": 70, "expected-execution-us": 113, - "relative-deadline-us": 11300, + "relative-deadline-us": 1130, "http-resp-content-type": "text/plain" }, { From 3db9e08d3924e0cf2679c981fa29942385b99ea4 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 27 May 2025 00:14:49 -0600 Subject: [PATCH 179/198] update compare_dispatchers.sh --- runtime/tests/compare_dispatchers.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/tests/compare_dispatchers.sh b/runtime/tests/compare_dispatchers.sh index 34ea09dd8..77bf031fd 100755 --- a/runtime/tests/compare_dispatchers.sh +++ b/runtime/tests/compare_dispatchers.sh @@ -36,7 +36,7 @@ declare project_path="$( )" echo $project_path path=`pwd` -export SLEDGE_DISABLE_PREEMPTION=$disable_preemption +export SLEDGE_DISABLE_PREEMPTION=$disable_preempt export SLEDGE_DISABLE_GET_REQUESTS_FROM_GQ=$disable_get_req_from_GQ export SLEDGE_DISABLE_BUSY_LOOP=$disable_busy_loop export SLEDGE_DISABLE_AUTOSCALING=$disable_autoscaling From c20c5263aed1aaa54a43274e50585d0736a2e4bb Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 27 May 2025 00:17:45 -0600 Subject: [PATCH 180/198] upload applications_Makefile_patch --- applications/applications_Makefile_patch | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 applications/applications_Makefile_patch diff --git a/applications/applications_Makefile_patch b/applications/applications_Makefile_patch new file mode 100644 index 000000000..efe3f7952 --- /dev/null +++ b/applications/applications_Makefile_patch @@ -0,0 +1,30 @@ +diff --git a/applications/Makefile b/applications/Makefile +index 1ec969c..08cd49c 100644 +--- a/applications/Makefile ++++ b/applications/Makefile +@@ -21,6 +21,9 @@ dist: + all: \ + cifar10.install \ + empty.install \ ++ sift.install \ ++ hash.install \ ++ multi_ncut.install \ + fibonacci.install \ + gocr.install \ + gps_ekf.install \ +@@ -90,6 +93,15 @@ exit.install: ../runtime/bin/exit.wasm.so + .PHONY: fibonacci.install + fibonacci.install: ../runtime/bin/fibonacci.wasm.so + ++.PHONY: multi_ncut.install ++fibonacci.install: ../runtime/bin/multi_ncut.wasm.so ++ ++.PHONY: sift.install ++fibonacci.install: ../runtime/bin/sift.wasm.so ++ ++.PHONY: hash.install ++hash.install: ../runtime/bin/hash.wasm.so ++ + .PHONY: asc-fib.install + asc-fib.install: ../runtime/bin/asc-fib.wasm.so + From 2a6f98eea5fbe99d2799b3a76dc020c845add908 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 27 May 2025 00:35:25 -0600 Subject: [PATCH 181/198] update debug.sh --- runtime/tests/debug.sh | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/runtime/tests/debug.sh b/runtime/tests/debug.sh index 4b5becd1e..9123eaa5a 100755 --- a/runtime/tests/debug.sh +++ b/runtime/tests/debug.sh @@ -11,20 +11,21 @@ declare project_path="$( path=`pwd` echo $project_path cd $project_path/runtime/bin -export SLEDGE_DISABLE_BUSY_LOOP=false +export SLEDGE_DISABLE_BUSY_LOOP=true export SLEDGE_DISABLE_AUTOSCALING=true -export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=true -export SLEDGE_DISABLE_PREEMPTION=true +export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=false +export SLEDGE_DISABLE_GET_REQUESTS_FROM_GQ=true +export SLEDGE_DISABLE_PREEMPTION=false export SLEDGE_SANDBOX_PERF_LOG=$path/server.log -export SLEDGE_NWORKERS=1 +export SLEDGE_NWORKERS=6 export SLEDGE_FIRST_WORKER_COREID=4 export SLEDGE_NLISTENERS=1 -export SLEDGE_WORKER_GROUP_SIZE=1 +export SLEDGE_WORKER_GROUP_SIZE=6 export SLEDGE_SCHEDULER=FIFO #export SLEDGE_DISPATCHER=DARC #export SLEDGE_DISPATCHER=EDF_INTERRUPT #export SLEDGE_DISPATCHER=SHINJUKU -export SLEDGE_DISPATCHER=TO_GLOBAL_QUEUE +export SLEDGE_DISPATCHER=LLD export LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" #gdb --eval-command="handle SIGUSR1 nostop" \ # --eval-command="set pagination off" \ From 883055e79a32868de147e4633b585600c05cbc03 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 27 May 2025 16:14:30 -0600 Subject: [PATCH 182/198] change dispatcher - RR, JSQ, and LLD to use original algorithms working with each worker with fixed interval interrupt + EDF --- runtime/include/erpc_handler.h | 2 ++ runtime/include/http_router.h | 9 ++++++--- runtime/src/main.c | 8 +++++--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/runtime/include/erpc_handler.h b/runtime/include/erpc_handler.h index eefaf13b6..4991d3716 100644 --- a/runtime/include/erpc_handler.h +++ b/runtime/include/erpc_handler.h @@ -6,6 +6,8 @@ void darc_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t s void shinjuku_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); void enqueue_to_global_queue_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); void rr_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); +void rr_req_handler_without_interrupt(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); void jsq_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); +void jsq_req_handler_without_interrupt(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); void lld_req_handler(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); void lld_req_handler_without_interrupt(void *req_handle, uint8_t req_type, uint8_t *msg, size_t size, uint16_t port); diff --git a/runtime/include/http_router.h b/runtime/include/http_router.h index cce8883c4..bb19ee348 100644 --- a/runtime/include/http_router.h +++ b/runtime/include/http_router.h @@ -70,18 +70,21 @@ http_router_add_route(http_router_t *router, struct route_config *config, struct panic("register erpc function for enqueuing to global queue failed\n"); } } else if (dispatcher == DISPATCHER_RR) { - if (erpc_register_req_func(config->request_type, rr_req_handler, 0) != 0) { + //if (erpc_register_req_func(config->request_type, rr_req_handler, 0) != 0) { + if (erpc_register_req_func(config->request_type, rr_req_handler_without_interrupt, 0) != 0) { panic("register erpc function for round robain distribution failed\n"); } } else if (dispatcher == DISPATCHER_JSQ) { - if (erpc_register_req_func(config->request_type, jsq_req_handler, 0) != 0) { + //if (erpc_register_req_func(config->request_type, jsq_req_handler, 0) != 0) { + if (erpc_register_req_func(config->request_type, jsq_req_handler_without_interrupt, 0) != 0) { panic("register erpc function for join shortest queue distribution failed\n"); } } else if (dispatcher == DISPATCHER_LLD && scheduler == SCHEDULER_EDF) { /* Dispatcher assign requests to workers with LLD + interrupt, and each worker schedule its local queue tasks with EDF */ - if (erpc_register_req_func(config->request_type, lld_req_handler, 0) != 0) { + //if (erpc_register_req_func(config->request_type, lld_req_handler, 0) != 0) { + if (erpc_register_req_func(config->request_type, lld_req_handler_without_interrupt, 0) != 0) { panic("register erpc function for leatest load distribution with edf failed\n"); } } else if (dispatcher == DISPATCHER_LLD && scheduler == SCHEDULER_FIFO) { diff --git a/runtime/src/main.c b/runtime/src/main.c index 4f13201b7..73a4b5e03 100644 --- a/runtime/src/main.c +++ b/runtime/src/main.c @@ -266,10 +266,12 @@ runtime_config_validate() } } - if (dispatcher == DISPATCHER_RR || dispatcher == DISPATCHER_JSQ || dispatcher == DISPATCHER_EDF_INTERRUPT - || dispatcher == DISPATCHER_SHINJUKU || dispatcher == DISPATCHER_DARC || dispatcher == DISPATCHER_LLD && scheduler == SCHEDULER_EDF) { + //if (dispatcher == DISPATCHER_RR || dispatcher == DISPATCHER_JSQ || dispatcher == DISPATCHER_EDF_INTERRUPT + // || dispatcher == DISPATCHER_SHINJUKU || dispatcher == DISPATCHER_DARC || dispatcher == DISPATCHER_LLD && scheduler == SCHEDULER_EDF) { + if (dispatcher == DISPATCHER_EDF_INTERRUPT || dispatcher == DISPATCHER_SHINJUKU || dispatcher == DISPATCHER_DARC) { if (runtime_preemption_enabled == true) { - panic("Must disable preemption if dispatcher is RR, JSQ, EDF_INTERRUPT, or LLD + EDF\n"); + //panic("Must disable preemption if dispatcher is RR, JSQ, EDF_INTERRUPT, or LLD + EDF\n"); + panic("Must disable preemption if dispatcher is SHINJUKU, DARC or EDF_INTERRUPT\n"); } } From 51332cf23d992ae6595fcaa52f6a37cef56d3473 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 27 May 2025 16:16:47 -0600 Subject: [PATCH 183/198] update applications_Makefile_patch --- runtime/tests/applications_Makefile_patch | 30 +++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 runtime/tests/applications_Makefile_patch diff --git a/runtime/tests/applications_Makefile_patch b/runtime/tests/applications_Makefile_patch new file mode 100644 index 000000000..efe3f7952 --- /dev/null +++ b/runtime/tests/applications_Makefile_patch @@ -0,0 +1,30 @@ +diff --git a/applications/Makefile b/applications/Makefile +index 1ec969c..08cd49c 100644 +--- a/applications/Makefile ++++ b/applications/Makefile +@@ -21,6 +21,9 @@ dist: + all: \ + cifar10.install \ + empty.install \ ++ sift.install \ ++ hash.install \ ++ multi_ncut.install \ + fibonacci.install \ + gocr.install \ + gps_ekf.install \ +@@ -90,6 +93,15 @@ exit.install: ../runtime/bin/exit.wasm.so + .PHONY: fibonacci.install + fibonacci.install: ../runtime/bin/fibonacci.wasm.so + ++.PHONY: multi_ncut.install ++fibonacci.install: ../runtime/bin/multi_ncut.wasm.so ++ ++.PHONY: sift.install ++fibonacci.install: ../runtime/bin/sift.wasm.so ++ ++.PHONY: hash.install ++hash.install: ../runtime/bin/hash.wasm.so ++ + .PHONY: asc-fib.install + asc-fib.install: ../runtime/bin/asc-fib.wasm.so + From 6ef68660aab96082b59d3b76b3f4f6bea8182583 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Sat, 7 Jun 2025 16:15:49 -0600 Subject: [PATCH 184/198] add max local queue count for minheap runqueue --- runtime/src/local_runqueue_minheap.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/runtime/src/local_runqueue_minheap.c b/runtime/src/local_runqueue_minheap.c index 2dfcab5c1..cd5be2948 100644 --- a/runtime/src/local_runqueue_minheap.c +++ b/runtime/src/local_runqueue_minheap.c @@ -14,6 +14,7 @@ extern struct priority_queue* worker_queues[1024]; extern _Atomic uint32_t local_queue_length[1024]; +extern uint32_t max_local_queue_length[1024]; extern thread_local int global_worker_thread_idx; _Atomic uint64_t worker_queuing_cost[1024]; /* index is thread id, each queue's total execution cost of queuing requests */ extern struct perf_window * worker_perf_windows[1024]; /* index is thread id, each queue's perf windows, each queue can @@ -68,6 +69,10 @@ local_runqueue_minheap_add_index(int index, struct sandbox *sandbox) } atomic_fetch_add(&local_queue_length[index], 1); + if (local_queue_length[index] > max_local_queue_length[index]) { + max_local_queue_length[index] = local_queue_length[index]; + } + uint32_t uid = sandbox->route->admissions_info.uid; /* Set estimated exeuction time for the sandbox */ From 942f26aeb8dd9e6c73eb77f1bfd48815567ddf76 Mon Sep 17 00:00:00 2001 From: Xiaosu Lyu Date: Tue, 10 Jun 2025 11:06:45 -0600 Subject: [PATCH 185/198] upload parse_avg_throughput.sh and measure_throughput.sh --- .../ori_sledge_tests/measure_throughput.sh | 23 ++++++++++++++- .../ori_sledge_tests/parse_avg_throughput.sh | 28 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100755 runtime/tests/ori_sledge_tests/parse_avg_throughput.sh diff --git a/runtime/tests/ori_sledge_tests/measure_throughput.sh b/runtime/tests/ori_sledge_tests/measure_throughput.sh index 422ca3558..19582973b 100755 --- a/runtime/tests/ori_sledge_tests/measure_throughput.sh +++ b/runtime/tests/ori_sledge_tests/measure_throughput.sh @@ -1,2 +1,23 @@ +#!/bin/bash + +if [ $# -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +num_runs=$1 +chmod 400 ./id_rsa +remote_ip="128.110.218.253" + ulimit -n 655350 -hey -disable-compression -disable-redirects -cpus 15 -z "20"s -c "400" -m POST "http://10.10.1.1:31850/empty" +path="/my_mount/old_sledge/sledge-serverless-framework/runtime/tests" + +for i in $(seq 1 $num_runs); do + ssh -o stricthostkeychecking=no -i ./id_rsa xiaosuGW@$remote_ip "$path/start.sh > 1.txt 2>&1 &" + sleep 5 + echo "Running test $i..." + hey -disable-compression -disable-redirects -cpus 20 -z "20"s -c "300" -m POST "http://10.10.1.1:31850/empty" > "output_$i.txt" + ssh -o stricthostkeychecking=no -i ./id_rsa xiaosuGW@$remote_ip "sudo $path/kill_sledge.sh" +done + +echo "All tests completed." diff --git a/runtime/tests/ori_sledge_tests/parse_avg_throughput.sh b/runtime/tests/ori_sledge_tests/parse_avg_throughput.sh new file mode 100755 index 000000000..8857324ca --- /dev/null +++ b/runtime/tests/ori_sledge_tests/parse_avg_throughput.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# 文件名匹配模式,例如 output_*.txt +files="output_*.txt" + +# 初始化总和和计数 +total=0 +count=0 + +# 遍历每个文件 +for file in $files; do + if [ -f "$file" ]; then + # 提取 Requests/sec 后的数字 + value=$(grep "Requests/sec:" "$file" | awk '{print $2}') + if [[ $value =~ ^[0-9.]+$ ]]; then + total=$(echo "$total + $value" | bc) + count=$((count + 1)) + fi + fi +done + +# 计算平均值 +if [ $count -gt 0 ]; then + average=$(echo "scale=4; $total / $count" | bc) + echo "Average Requests/sec: $average" +else + echo "No valid data found." +fi From 7ba489618a403272e96da2a3fe1b5236780241d4 Mon Sep 17 00:00:00 2001 From: xiaosuGW Date: Mon, 20 Oct 2025 23:44:53 -0600 Subject: [PATCH 186/198] 1. add eRPC as a sub-module in .gitmodules. 2. update Makefile --- .gitmodules | 3 +++ Makefile | 6 +++++- runtime/Makefile | 8 ++++---- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/.gitmodules b/.gitmodules index 6bf13ebca..8b83d0680 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,3 +12,6 @@ [submodule "jsmn"] path = runtime/thirdparty/jsmn url = https://github.com/gwsystems/jsmn.git +[submodule "eRPC"] + path = eRPC + url = https://github.com/lyuxiaosu/eRPC.git diff --git a/Makefile b/Makefile index 4ff4ab7f2..5ba644cfd 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ SHELL:=/bin/bash .PHONY: all -all: awsm libsledge runtime applications +all: awsm erpc libsledge runtime applications .PHONY: clean clean: awsm.clean libsledge.clean runtime.clean applications.clean @@ -31,6 +31,10 @@ libsledge: libsledge.clean: make -C libsledge clean +.PHONY: erpc +erpc: + eRPC/c_interface/build.sh + # sledgert: the runtime that executes *.so modules .PHONY: runtime runtime: diff --git a/runtime/Makefile b/runtime/Makefile index 8f4fc7648..efecbcb16 100644 --- a/runtime/Makefile +++ b/runtime/Makefile @@ -118,12 +118,12 @@ CFLAGS += -D${ARCH} # allowing the libraries acess to such symbols. The libm math library is used several places, including # in backing functions that implement the WebAssembly instruction set. LDFLAGS += -Wl,--whole-archive -ldpdk -Wl,--no-whole-archive -Wl,--export-dynamic -ldl -lm -lstdc++ -lnuma -ldl -libverbs -lmlx4 -lmlx5 -LDFLAGS += -L /users/xiaosuGW/eRPC/c_interface/build +LDFLAGS += -L ../eRPC/c_interface/build # Our third-party dependencies build into a single dist directory to simplify configuration here. LDFLAGS += -Lthirdparty/dist/lib/ INCLUDES += -Iinclude/ -Ithirdparty/dist/include/ -I../libsledge/include/ -INCLUDES += -I/users/xiaosuGW/eRPC/c_interface +INCLUDES += -I../eRPC/c_interface INCLUDES += -I /usr/include/dpdk @@ -139,7 +139,7 @@ JSMNCFLAGS += -DJSMN_STRICT # Force sledgert to rebuild when header files change # This is a bit fragile, as it does not recurse subdirectories when detecting last changed times -HEADER_DEPS = thirdparty/dist/include/*.h include/*.h include/arch/x86_64/*.h include/arch/aarch64/*.h /users/xiaosuGW/eRPC/c_interface/*.h +HEADER_DEPS = thirdparty/dist/include/*.h include/*.h include/arch/x86_64/*.h include/arch/aarch64/*.h ../eRPC/c_interface/*.h .PHONY: all all: thirdparty runtime @@ -151,7 +151,7 @@ clean: thirdparty.clean runtime.clean bin/${BINARY_NAME}: ${HEADER_DEPS} ${CFILES} @echo "Compiling runtime" @mkdir -p bin/ - @${CC} ${INCLUDES} ${CFLAGS} ${LDFLAGS} ${JSMNCFLAGS} -L/usr/lib/ ${CFILES} -L/users/xiaosuGW/eRPC/c_interface/build -lerpc_c_interface -o bin/${BINARY_NAME} + @${CC} ${INCLUDES} ${CFLAGS} ${LDFLAGS} ${JSMNCFLAGS} -L/usr/lib/ ${CFILES} -L../eRPC/c_interface/build -lerpc_c_interface -o bin/${BINARY_NAME} .PHONY: runtime runtime: bin/${BINARY_NAME} From 4a5d5b627d321ce30c5ee338b58d644f10696747 Mon Sep 17 00:00:00 2001 From: xiaosuGW Date: Mon, 20 Oct 2025 23:50:00 -0600 Subject: [PATCH 187/198] update .gitmodules --- .gitmodules | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index 8b83d0680..6bf13ebca 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,6 +12,3 @@ [submodule "jsmn"] path = runtime/thirdparty/jsmn url = https://github.com/gwsystems/jsmn.git -[submodule "eRPC"] - path = eRPC - url = https://github.com/lyuxiaosu/eRPC.git From 16129f1a14b97d57c7e2386ceb95a2dceef2cbb0 Mon Sep 17 00:00:00 2001 From: xiaosuGW Date: Mon, 20 Oct 2025 23:54:22 -0600 Subject: [PATCH 188/198] Add new submodule eRPC --- .gitmodules | 3 +++ eRPC | 1 + 2 files changed, 4 insertions(+) create mode 160000 eRPC diff --git a/.gitmodules b/.gitmodules index 6bf13ebca..2aa945212 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,3 +12,6 @@ [submodule "jsmn"] path = runtime/thirdparty/jsmn url = https://github.com/gwsystems/jsmn.git +[submodule "eRPC"] + path = eRPC + url = https://github.com/lyuxiaosu/eRPC diff --git a/eRPC b/eRPC new file mode 160000 index 000000000..c608d9e54 --- /dev/null +++ b/eRPC @@ -0,0 +1 @@ +Subproject commit c608d9e54a2ea2dfb2dc758e1e3a1bf684dfd352 From 013c810c52af0e144e1d3e3ffb745ec82f5b31ee Mon Sep 17 00:00:00 2001 From: xiaosuGW Date: Tue, 21 Oct 2025 00:31:22 -0600 Subject: [PATCH 189/198] update Makefile --- Makefile | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 5ba644cfd..db40ffa6e 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ SHELL:=/bin/bash all: awsm erpc libsledge runtime applications .PHONY: clean -clean: awsm.clean libsledge.clean runtime.clean applications.clean +clean: awsm.clean erpc.clean libsledge.clean runtime.clean applications.clean .PHONY: submodules submodules: @@ -33,7 +33,13 @@ libsledge.clean: .PHONY: erpc erpc: - eRPC/c_interface/build.sh + @echo "Building eRPC interface..." + cd eRPC/c_interface && ./build.sh + @echo "eRPC build complete." + +.PHONY: erpc.clean +erpc.clean: + cd eRPC/c_interface && make clean # sledgert: the runtime that executes *.so modules .PHONY: runtime From 55177ddb0f027dd86f78a2764f200ddf77d7440c Mon Sep 17 00:00:00 2001 From: lyuxiaosu Date: Mon, 20 Oct 2025 23:37:28 -0700 Subject: [PATCH 190/198] Update README.md --- README.md | 97 ++++++++++++++++--------------------------------------- 1 file changed, 28 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index ee6e99f93..20a91a836 100644 --- a/README.md +++ b/README.md @@ -1,49 +1,29 @@ -# SLEdge - -**SLEdge** is a lightweight serverless solution suitable for edge computing. It builds on WebAssembly sandboxing provided by the [aWsm compiler](https://github.com/gwsystems/aWsm). - -## Setting up a development environment - -### Native on Debian Host - -```sh -git clone https://github.com/gwsystems/sledge-serverless-framework.git -cd sledge-serverless-framework -./install_deb.sh -source ~/.bashrc -make install -make test -``` - -### Docker - -**Note: These steps require Docker. Make sure you've got it installed!** - -[Docker Installation Instructions](https://docs.docker.com/install/) - -We provide a Docker build environment configured with the dependencies and toolchain needed to build the SLEdge runtime and serverless functions. - -To setup this environment, run: - -```bash -./devenv.sh setup -``` - -### Using the Docker container to compile your serverless functions - -To enter the docker environment, run: - -```bash -./devenv.sh run -``` - -The first time you enter this environment, run the following to copy the sledgert binary to /sledge/runtime/bin. - -```bash -cd /sledge/runtime -make clean all -``` - +# SLEdgeScale + +**SLEdgeScale** is an ultra-low-latency, high-density, and task-deadline-aware serverless computing solution suitable for edge environments, extending **SLEdge**. It leverages WebAssembly sandboxing provided by the [aWsm compiler](https://github.com/gwsystems/aWsm) and kernel-bypass RPC offered by [eRPC](https://github.com/erpc-io/eRPC). + +## Setting up a development environment (Native on Debian Host) +SLEdgeScale was developed and tested on [Cloudlab](https://www.cloudlab.us) nodes (d6515) equipped with Mellanox NICs. A public [profile](https://www.cloudlab.us/p/GWCloudLab/sledge-rpc2) is available on CloudLab for easily creating a development environment for eRPC with node d6515. If you plan to set up the environment on machines with Intel NICs or other machines, please refer to the [eRPC](https://github.com/erpc-io/eRPC) repository for details about environment configuration, including driver and DPDK installation. For Mellanox NICs, please follow [this](https://docs.nvidia.com/networking/display/mlnxofedv590560125/installing+mlnx_ofed) guide to install *MLNX_OFED*. + +For using CloudLab profile to create the development environment: +Choose the [profile](https://www.cloudlab.us/p/GWCloudLab/sledge-rpc2) and use the following configuration: +Number of Nodes: 2 +Select OS image: SLEDGE +Optional physical node type : d6515 + +Now the environment is prepared for eRPC. The following steps are to build and install SLEdgeScale: +1. Git clone this repo and checkout branch *compare_dispatchers* +2. Extend the root filesystem. Run `sledge-serverless-framework/runtime/tests/add_partition.sh` +3. Move `sledge-serverless-framework` to `/my_mount/` +4. Disable multiple threads. Run `sudo sledge-serverless-framework/runtime/tests/no_hyperthreads.sh` +5. Build: + ```sh + cd sledge-serverless-framework + ./install_deb.sh + source $HOME/.cargo/env + source ~/.bashrc + make install + ``` There are a set of benchmarking applications in the `/sledge/applications` directory. Run the following to compile all benchmarks runtime tests using the aWsm compiler and then copy all resulting `.wasm.so` files to /sledge/runtime/bin. ```bash @@ -51,33 +31,12 @@ cd /sledge/applications/ make clean all ``` -You now have everything that you need to execute your first serverless function on SLEdge - -To exit the container: - -```bash -exit -``` - -To stop the Docker container: - -```bash -./devenv.sh stop -``` - -### Deleting Docker Build Containers - -If you are finished working with the SLEdge runtime and wish to remove it, run the following command to delete our Docker build and runtime images. - -```bash -./devenv.sh rma -``` +You now have everything that you need to execute your first serverless function on SLEdgeScale -And then simply delete this repository. ## Running your first serverless function -An SLEdge serverless function consists of a shared library (\*.so) and a JSON configuration file that determines how the runtime should execute the serverless function. As an example, here is the configuration file for our sample fibonacci function: +An SLEdgeScale serverless function consists of a shared library (\*.so) and a JSON configuration file that determines how the runtime should execute the serverless function. As an example, here is the configuration file for our sample fibonacci function: ```json [ From 08326bd8a2a8fdb5e7eb029f485642c12060190a Mon Sep 17 00:00:00 2001 From: lyuxiaosu Date: Mon, 20 Oct 2025 23:40:02 -0700 Subject: [PATCH 191/198] Update README.md --- README.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 20a91a836..985508c22 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,18 @@ Optional physical node type : d6515 Now the environment is prepared for eRPC. The following steps are to build and install SLEdgeScale: 1. Git clone this repo and checkout branch *compare_dispatchers* -2. Extend the root filesystem. Run `sledge-serverless-framework/runtime/tests/add_partition.sh` -3. Move `sledge-serverless-framework` to `/my_mount/` -4. Disable multiple threads. Run `sudo sledge-serverless-framework/runtime/tests/no_hyperthreads.sh` -5. Build: +2. Extend the root filesystem: + ```sh + cd sledge-serverless-framework/runtime/tests + ./add_partition.sh + ``` +4. Move `sledge-serverless-framework` to `/my_mount/` +5. Disable multiple threads: + ```sh + cd sledge-serverless-framework/runtime/tests + sudo ./no_hyperthreads.sh + ``` +7. Build: ```sh cd sledge-serverless-framework ./install_deb.sh From a4df9ac1b4b8e72343344c409d6c46510adbcb18 Mon Sep 17 00:00:00 2001 From: lyuxiaosu Date: Wed, 22 Oct 2025 00:17:48 -0700 Subject: [PATCH 192/198] Update README.md --- README.md | 76 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 56 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 985508c22..892d2c0bd 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,7 @@ cd /sledge/applications/ make clean all ``` -You now have everything that you need to execute your first serverless function on SLEdgeScale - +All binary files are generated in `sledge-serverless-framework/runtime/bin`. You now have everything that you need to execute your first serverless function on SLEdgeScale ## Running your first serverless function @@ -48,25 +47,65 @@ An SLEdgeScale serverless function consists of a shared library (\*.so) and a JS ```json [ - { - "name": "GWU", - "port": 10010, - "routes": [ - { - "route": "/fib", - "path": "fibonacci.wasm.so", - "expected-execution-us": 6000, - "relative-deadline-us": 20000, - "http-resp-content-type": "text/plain" - } - ] - } -] + { + "name": "gwu", + "port": 31850, + "replenishment-period-us": 0, + "max-budget-us": 0, + "routes": [ + { + "route": "/fib", + "request-type": 1, + "n-resas": 1, + "group-id": 1, + "path": "fibonacci.wasm.so", + "admissions-percentile": 70, + "expected-execution-us": 5, + "relative-deadline-us": 50, + "http-resp-content-type": "text/plain" + } + ] + + } +] ``` -The `port` and `route` fields are used to determine the path where our serverless function will be served served. +`port`:Refers to the UDP port. +`request-type` and `path`: Used to determine which serverless function will be served; `request-type` must be unique per function. +`route`: An inherited field from SLEdge. It is not used currently but is kept to avoid parse errors. +`n-resas`: Specifies the number of CPU cores reserved for this serverless function. It is used by the DARC algorithm. +`group-id`: Specifies the group identifier used in the DARC algorithm. +`expected-execution-us`: Specifies the function’s expected execution time in microseconds. This is used for testing; SLEdgeScale also estimates execution time online. +`relative-deadline-us`: Specifies the request deadline in microseconds. +`http-resp-content-type`: Not used currently but is kept to avoid parse errors. + +### Start the SLEdgeScale Server +We need to export some environment variables before start the server. The commonly used environment variables are: +`SLEDGE_DISABLE_PREEMPTION`: Disables the timer that sends a SIGALRM signal every 5 ms for preemption. Must disable in SLEdgeScale. +`SLEDGE_DISABLE_GET_REQUESTS_FROM_GQ`: Disable workers fetching requests from the global queue. Disabled in SLEdgeScale; optional in SLEdge. +#only works for FIFO scheduler +export SLEDGE_DISABLE_GET_REQUESTS_FROM_GQ=$disable_get_req_from_GQ +export SLEDGE_FIFO_QUEUE_BATCH_SIZE=5 +export SLEDGE_DISABLE_BUSY_LOOP=$disable_busy_loop +export SLEDGE_DISABLE_AUTOSCALING=$disable_autoscaling +#export SLEDGE_SIGALRM_HANDLER=TRIAGED +export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=$disable_service_ts_simulation +export SLEDGE_FIRST_WORKER_COREID=$first_worker_core_id +export SLEDGE_NWORKERS=$worker_num +export SLEDGE_NLISTENERS=$listener_num +export SLEDGE_WORKER_GROUP_SIZE=$worker_group_size +export SLEDGE_SCHEDULER=$scheduler_policy +#export SLEDGE_DISPATCHER=DARC +export SLEDGE_DISPATCHER=$dispatcher_policy +export SLEDGE_SCHEDULER=$scheduler_policy +#export SLEDGE_DISPATCHER=EDF_INTERRUPT +export SLEDGE_SANDBOX_PERF_LOG=$path/$server_log + +Now run the sledgert binary, passing the JSON file of the serverless function we want to serve. Because serverless functions are loaded by SLEdge as shared libraries, we want to add the `applications/` directory to LD_LIBRARY_PATH. +```bash +LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../../tests/fibonacci/bimodal/spec.json In our case, we are running the SLEdge runtime on localhost, so our function is available at `localhost:10010/fib`. Our fibonacci function will parse a single argument from the HTTP POST body that we send. The expected Content-Type is "text/plain". @@ -81,10 +120,7 @@ From the root project directory of the host environment (not the Docker containe cd runtime/bin/ ``` -Now run the sledgert binary, passing the JSON file of the serverless function we want to serve. Because serverless functions are loaded by SLEdge as shared libraries, we want to add the `applications/` directory to LD_LIBRARY_PATH. -```bash -LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../../tests/fibonacci/bimodal/spec.json ``` While you don't see any output to the console, the runtime is running in the foreground. From 7f954d4ef3275df761ecc075e1f37d4addaaa53b Mon Sep 17 00:00:00 2001 From: lyuxiaosu Date: Wed, 22 Oct 2025 10:38:49 -0700 Subject: [PATCH 193/198] Update README.md --- README.md | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 892d2c0bd..09573d8f0 100644 --- a/README.md +++ b/README.md @@ -76,25 +76,36 @@ An SLEdgeScale serverless function consists of a shared library (\*.so) and a JS `route`: An inherited field from SLEdge. It is not used currently but is kept to avoid parse errors. `n-resas`: Specifies the number of CPU cores reserved for this serverless function. It is used by the DARC algorithm. `group-id`: Specifies the group identifier used in the DARC algorithm. -`expected-execution-us`: Specifies the function’s expected execution time in microseconds. This is used for testing; SLEdgeScale also estimates execution time online. +`expected-execution-us`: Currently not used. SLEdgeScale will estimate execution time online. `relative-deadline-us`: Specifies the request deadline in microseconds. `http-resp-content-type`: Not used currently but is kept to avoid parse errors. ### Start the SLEdgeScale Server We need to export some environment variables before start the server. The commonly used environment variables are: `SLEDGE_DISABLE_PREEMPTION`: Disables the timer that sends a SIGALRM signal every 5 ms for preemption. Must disable in SLEdgeScale. -`SLEDGE_DISABLE_GET_REQUESTS_FROM_GQ`: Disable workers fetching requests from the global queue. Disabled in SLEdgeScale; optional in SLEdge. -#only works for FIFO scheduler -export SLEDGE_DISABLE_GET_REQUESTS_FROM_GQ=$disable_get_req_from_GQ -export SLEDGE_FIFO_QUEUE_BATCH_SIZE=5 -export SLEDGE_DISABLE_BUSY_LOOP=$disable_busy_loop -export SLEDGE_DISABLE_AUTOSCALING=$disable_autoscaling -#export SLEDGE_SIGALRM_HANDLER=TRIAGED -export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=$disable_service_ts_simulation -export SLEDGE_FIRST_WORKER_COREID=$first_worker_core_id -export SLEDGE_NWORKERS=$worker_num -export SLEDGE_NLISTENERS=$listener_num -export SLEDGE_WORKER_GROUP_SIZE=$worker_group_size +`SLEDGE_DISPATCHER`: Specifies the dispatcher policy. There are seven types of dispatchers: +- SHINJUKU: Requests are enqueued to each dispatcher's typed queue. +- EDF_INTERRUPT: The dispatcher policy used by SLEdgeScale. +- DARC: Requests are enqueued to each dispatcher's typed queue. +- LLD: The dispatcher selects the worker with the least loaded queue to enqueue a request.. +- TO_GLOBAL_QUEUE: The dispatcher policy used by SLEdge. All dispatchers enqueue requests to a global queue. +- RR: The dispatcher selects a worker in a round-robin fashion. +- JSQ: The dispatcher selects the worker with the shortest queue to enqueue a request. + +`SLEDGE_DISABLE_GET_REQUESTS_FROM_GQ`: Disable workers fetching requests from the global queue. Must be disabled if the dispatcher policy is not set to TO_GLOBAL_QUEUE. +`SLEDGE_SCHEDULER`: Specifies the scheduler policy. There are two types of schedulers: +- FIFO: First-In-First-Out. Must use the TO_GLOBAL_QUEUE dispatch policy when using FIFO. +- EDF: Earliest-deadline-first. + +`SLEDGE_FIFO_QUEUE_BATCH_SIZE`: When using the FIFO scheduler, specifies how many requests are fetched from the global queue to the local queue each time the local queue becomes empty. +`SLEDGE_DISABLE_BUSY_LOOP`: Disables the worker’s busy loop for fetching requests from the local or global queue. The busy loop must be enabled if the dispatcher policy is set to `TO_GLOBAL_QUEUE`. +`SLEDGE_DISABLE_AUTOSCALING`: Currently not used;always set to `true`. +`SLEDGE_SIGALRM_HANDLER`: Always set to `TRIAGED` to avoid performance issues. +`SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION`: For the `hash` function, enabling this option allows SLEdgeScale to estimate the function’s execution time based on the input number. For other types of functions, this should be disabled. +`SLEDGE_FIRST_WORKER_COREID`: Specifies the ID of the first core for the worker thread. Cores 0–2 are reserved, so numbering should start from 3. +`SLEDGE_NWORKERS`: Specifies the total number of workers in the system. +`SLEDGE_NLISTENERS`: Specifies the total number of dispachers in the system. +`SLEDGE_WORKER_GROUP_SIZE`: Specifies SLEdgeScale calculates the number of workers in each worker group based on this value. export SLEDGE_SCHEDULER=$scheduler_policy #export SLEDGE_DISPATCHER=DARC export SLEDGE_DISPATCHER=$dispatcher_policy From 257bc505449354ad398ca49750f41441b779dfc9 Mon Sep 17 00:00:00 2001 From: lyuxiaosu Date: Thu, 23 Oct 2025 00:07:06 -0700 Subject: [PATCH 194/198] Update README.md --- README.md | 51 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 09573d8f0..191992dc3 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,9 @@ An SLEdgeScale serverless function consists of a shared library (\*.so) and a JS ### Start the SLEdgeScale Server We need to export some environment variables before start the server. The commonly used environment variables are: + `SLEDGE_DISABLE_PREEMPTION`: Disables the timer that sends a SIGALRM signal every 5 ms for preemption. Must disable in SLEdgeScale. + `SLEDGE_DISPATCHER`: Specifies the dispatcher policy. There are seven types of dispatchers: - SHINJUKU: Requests are enqueued to each dispatcher's typed queue. - EDF_INTERRUPT: The dispatcher policy used by SLEdgeScale. @@ -92,27 +94,56 @@ We need to export some environment variables before start the server. The common - RR: The dispatcher selects a worker in a round-robin fashion. - JSQ: The dispatcher selects the worker with the shortest queue to enqueue a request. -`SLEDGE_DISABLE_GET_REQUESTS_FROM_GQ`: Disable workers fetching requests from the global queue. Must be disabled if the dispatcher policy is not set to TO_GLOBAL_QUEUE. +`SLEDGE_DISABLE_GET_REQUESTS_FROM_GQ`: Disable workers fetching requests from the global queue. Must be disabled if the dispatcher policy is not set to TO_GLOBAL_QUEUE. + `SLEDGE_SCHEDULER`: Specifies the scheduler policy. There are two types of schedulers: - FIFO: First-In-First-Out. Must use the TO_GLOBAL_QUEUE dispatch policy when using FIFO. - EDF: Earliest-deadline-first. `SLEDGE_FIFO_QUEUE_BATCH_SIZE`: When using the FIFO scheduler, specifies how many requests are fetched from the global queue to the local queue each time the local queue becomes empty. + `SLEDGE_DISABLE_BUSY_LOOP`: Disables the worker’s busy loop for fetching requests from the local or global queue. The busy loop must be enabled if the dispatcher policy is set to `TO_GLOBAL_QUEUE`. + `SLEDGE_DISABLE_AUTOSCALING`: Currently not used;always set to `true`. -`SLEDGE_SIGALRM_HANDLER`: Always set to `TRIAGED` to avoid performance issues. + `SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION`: For the `hash` function, enabling this option allows SLEdgeScale to estimate the function’s execution time based on the input number. For other types of functions, this should be disabled. + `SLEDGE_FIRST_WORKER_COREID`: Specifies the ID of the first core for the worker thread. Cores 0–2 are reserved, so numbering should start from 3. -`SLEDGE_NWORKERS`: Specifies the total number of workers in the system. -`SLEDGE_NLISTENERS`: Specifies the total number of dispachers in the system. -`SLEDGE_WORKER_GROUP_SIZE`: Specifies SLEdgeScale calculates the number of workers in each worker group based on this value. -export SLEDGE_SCHEDULER=$scheduler_policy -#export SLEDGE_DISPATCHER=DARC -export SLEDGE_DISPATCHER=$dispatcher_policy -export SLEDGE_SCHEDULER=$scheduler_policy -#export SLEDGE_DISPATCHER=EDF_INTERRUPT + +`SLEDGE_NWORKERS`: The total number of workers in the system. + +`SLEDGE_NLISTENERS`: The total number of dispachers in the system. + +`SLEDGE_WORKER_GROUP_SIZE`: The number of workers in each worker group. Its value is equal to SLEDGE_NWORKERS / SLEDGE_NLISTENERS + +`SLEDGE_SANDBOX_PERF_LOG`: Server log file path + +Now use the following example script to start server side: +```sh +declare project_path="$( + cd "$(dirname "$0")/../.." + pwd +)" +echo $project_path +path=`pwd` +export SLEDGE_DISABLE_PREEMPTION=true +export SLEDGE_DISABLE_GET_REQUESTS_FROM_GQ=true +export SLEDGE_FIFO_QUEUE_BATCH_SIZE=5 +export SLEDGE_DISABLE_BUSY_LOOP=true +export SLEDGE_DISABLE_AUTOSCALING=true +export SLEDGE_DISABLE_EXPONENTIAL_SERVICE_TIME_SIMULATION=true +export SLEDGE_FIRST_WORKER_COREID=3 +export SLEDGE_NWORKERS=1 +export SLEDGE_NLISTENERS=1 +export SLEDGE_WORKER_GROUP_SIZE=1 +export SLEDGE_SCHEDULER=EDF +export SLEDGE_DISPATCHER=EDF_INTERRUPT export SLEDGE_SANDBOX_PERF_LOG=$path/$server_log +cd $project_path/runtime/bin +LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/fib.json +``` + Now run the sledgert binary, passing the JSON file of the serverless function we want to serve. Because serverless functions are loaded by SLEdge as shared libraries, we want to add the `applications/` directory to LD_LIBRARY_PATH. ```bash From 86f564a40d33e276e58c42f7d0b4c82617bd7434 Mon Sep 17 00:00:00 2001 From: lyuxiaosu Date: Thu, 23 Oct 2025 16:04:42 -0700 Subject: [PATCH 195/198] Update README.md --- README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 191992dc3..6bf8aff3f 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,9 @@ An SLEdgeScale serverless function consists of a shared library (\*.so) and a JS `http-resp-content-type`: Not used currently but is kept to avoid parse errors. ### Start the SLEdgeScale Server -We need to export some environment variables before start the server. The commonly used environment variables are: +First, set the public IPs and ports for eRPC. Open `sledge-serverless-framework/eRPC/scripts/autorun_process_file` — the first line specifies the server IP and port, and the second line specifies the client IP and port. Make sure to apply the same change on the client machine as well. + +Then we need to export some environment variables before start the server. The commonly used environment variables are: `SLEDGE_DISABLE_PREEMPTION`: Disables the timer that sends a SIGALRM signal every 5 ms for preemption. Must disable in SLEdgeScale. @@ -118,8 +120,11 @@ We need to export some environment variables before start the server. The common `SLEDGE_SANDBOX_PERF_LOG`: Server log file path -Now use the following example script to start server side: +Now run the sledgert binary with the following script using sudo, passing the JSON file (e.g., the above Fibonacci function configuration) of the serverless function we want to serve. Because serverless functions are loaded by SLEdgeScale as shared libraries, we want to add the `applications/` directory to LD_LIBRARY_PATH: + ```sh +#!/bin/bash + declare project_path="$( cd "$(dirname "$0")/../.." pwd @@ -138,14 +143,12 @@ export SLEDGE_NLISTENERS=1 export SLEDGE_WORKER_GROUP_SIZE=1 export SLEDGE_SCHEDULER=EDF export SLEDGE_DISPATCHER=EDF_INTERRUPT -export SLEDGE_SANDBOX_PERF_LOG=$path/$server_log +export SLEDGE_SANDBOX_PERF_LOG=$path/server.log cd $project_path/runtime/bin LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/fib.json ``` -Now run the sledgert binary, passing the JSON file of the serverless function we want to serve. Because serverless functions are loaded by SLEdge as shared libraries, we want to add the `applications/` directory to LD_LIBRARY_PATH. - ```bash LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../../tests/fibonacci/bimodal/spec.json In our case, we are running the SLEdge runtime on localhost, so our function is available at `localhost:10010/fib`. From f75c175f27c31efe940132a106442f3f0c8f2a4e Mon Sep 17 00:00:00 2001 From: lyuxiaosu Date: Thu, 23 Oct 2025 23:44:42 -0700 Subject: [PATCH 196/198] Update README.md --- README.md | 94 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 49 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 6bf8aff3f..344d736d1 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ All binary files are generated in `sledge-serverless-framework/runtime/bin`. You ## Running your first serverless function -An SLEdgeScale serverless function consists of a shared library (\*.so) and a JSON configuration file that determines how the runtime should execute the serverless function. As an example, here is the configuration file for our sample fibonacci function: +An SLEdgeScale serverless function consists of a shared library (\*.so) and a JSON configuration file that determines how the runtime should execute the serverless function. We first need to prepare this configuration file. As an example, here is the configuration file for our sample fibonacci function: ```json [ @@ -148,61 +148,65 @@ export SLEDGE_SANDBOX_PERF_LOG=$path/server.log cd $project_path/runtime/bin LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/fib.json ``` - -```bash -LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../../tests/fibonacci/bimodal/spec.json -In our case, we are running the SLEdge runtime on localhost, so our function is available at `localhost:10010/fib`. - -Our fibonacci function will parse a single argument from the HTTP POST body that we send. The expected Content-Type is "text/plain". - -Now that we understand roughly how the SLEdge runtime interacts with serverless function, let's run Fibonacci! - -The fastest way to check it out is just to click on the following URL on your Web browser: [http://localhost:10010/fib?10](http://localhost:10010/fib?10) - -From the root project directory of the host environment (not the Docker container!), navigate to the binary directory - -```bash -cd runtime/bin/ +### Start the client to send requests +First git clone the client code: +```sh +git clone https://github.com/lyuxiaosu/eRPC.git ``` - - +There are several client implementations under eRPC/apps, and you can also create your own customized client. In our setup, we use `openloop_client`, which is an open-loop client that sends requests following a Poisson distribution. +Edit `autorun_app_file`, `autorun_process_file`, and build: +```sh +cd eRPC +echo "openloop_client" > ./scripts/autorun_app_file +./build.sh ``` +Our fibonacci function will parse a single argument from the rpc request that we send. Create the configuration file `eRPC/apps/openloop_client/conf` for `openloop_client`: +``` +--test_ms 10000 +--sm_verbose 0 +--num_server_threads 1 +--window_size 10 +--req_size 5 +--resp_size 32 +--num_processes 2 +--numa_0_ports 0 +--numa_1_ports 1,3 +--req_type 1 +--rps 1000 +--req_parameter 20 +--warmup_rps 200 +``` +`test_ms`: Define the test duration time in milliseconds. -While you don't see any output to the console, the runtime is running in the foreground. - -Let's now invoke our serverless function to compute the 10th fibonacci number. We'll use `cURL` and [HTTPie](https://httpie.org/) to send a HTTP GET and POST requests with the parameter we want to pass to my serverless function. Feel free to use whatever other network client you prefer! - -Open a **new** terminal session and execute the following - -```bash -# HTTP GET method: -http localhost:10010/fib?10 -curl localhost:10010/fib?10 +`num_server_threads`: Specifies how many dispatcher threads to run on the server. -# HTTP POST method: -echo "10" | http POST localhost:10010/fib -curl -i -d 10 localhost:10010/fib -``` +`req_size`: The size of the request package in bytes -You should receive the following in response. The serverless function says that the 10th fibonacci number is 55, which seems to be correct! +`resp_size`: The size of the response package in bytes -```bash -HTTP/1.1 200 OK -Server: SLEdge -Connection: close -Content-Type: text/plain -Content-Length: 3 +`req_type`: The request type -55 -``` +`req_parameter`: The parameter carried by the request. Here is the fibonacci number. -When done, terminal the SLEdge runtime with `Ctrl+c` -## Running Test Workloads +Now we have everything, let's run Fibonacci! -Various synthetic and real-world tests can be found in `runtime/tests`. Generally, each experiment can be run by Make rules in the top level `test.mk`. +```sh +cd eRPC +./scripts/do.sh 1 0 -`make -f test.mk all` +``` +The results is saved at `client.log`: +``` +thread id, type id, latency, cpu time +0 1 64.492000 23 +0 1 46.649000 23 +0 1 45.806000 23 +0 1 45.877000 22 +0 1 45.416000 22 +... +``` +The first column is the thread ID, the second column is the request type, the third column is the end-to-end latency in microseconds, and the fourth column is the execution time in microseconds. ## Problems or Feedback? From 4684c47b8439d0107c6d00e601022f3715d2c148 Mon Sep 17 00:00:00 2001 From: lyuxiaosu Date: Wed, 29 Oct 2025 12:07:39 -0700 Subject: [PATCH 197/198] Update README.md --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 344d736d1..d42781492 100644 --- a/README.md +++ b/README.md @@ -208,6 +208,14 @@ thread id, type id, latency, cpu time ``` The first column is the thread ID, the second column is the request type, the third column is the end-to-end latency in microseconds, and the fourth column is the execution time in microseconds. +### Test High Density +Since the High Density experiment involves a large number of RPC types, we need to modify the maximum number of RPC types supported by eRPC, as well as some parts of the SledgeScale code. These changes are temporary and not part of the permanent code base. +Please run: +``` +./apply_patch.sh +``` +in the `eRPC` directory (on both the client and server sides) and in the `runtime` directory, and then recompile `eRPC` and the `runtime`. + ## Problems or Feedback? If you encountered bugs or have feedback, please let us know in our [issue tracker.](https://github.com/gwsystems/sledge-serverless-framework/issues) From 9b80e63767fcb8ec1365b3639f9517fbd26814a3 Mon Sep 17 00:00:00 2001 From: lyuxiaosu Date: Wed, 29 Oct 2025 12:08:32 -0700 Subject: [PATCH 198/198] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d42781492..e9914274a 100644 --- a/README.md +++ b/README.md @@ -208,8 +208,8 @@ thread id, type id, latency, cpu time ``` The first column is the thread ID, the second column is the request type, the third column is the end-to-end latency in microseconds, and the fourth column is the execution time in microseconds. -### Test High Density -Since the High Density experiment involves a large number of RPC types, we need to modify the maximum number of RPC types supported by eRPC, as well as some parts of the SledgeScale code. These changes are temporary and not part of the permanent code base. +### High Density Test +Since the High Density experiment involves a large number of RPC types, we need to modify the maximum number of RPC types supported by eRPC, as well as some parts of the SLEdgeScale code. These changes are temporary and not part of the permanent code base. Please run: ``` ./apply_patch.sh