diff --git a/runtime/Makefile b/runtime/Makefile index f36e951..a90e9af 100644 --- a/runtime/Makefile +++ b/runtime/Makefile @@ -58,6 +58,7 @@ BINARY_NAME=sledgert # CFLAGS += -DLOG_REQUEST_ALLOCATION # CFLAGS += -DLOG_PREEMPTION # CFLAGS += -DLOG_MODULE_LOADING +# CFLAGS += -DOPT_AVOID_GLOBAL_QUEUE # This dumps per module *.csv files containing the cycle a sandbox has been in RUNNING when each # page is allocated. This helps understand the relationship to memory allocation and execution time. diff --git a/runtime/include/sandbox_request.h b/runtime/include/sandbox_request.h index 5287ffd..f816bcb 100644 --- a/runtime/include/sandbox_request.h +++ b/runtime/include/sandbox_request.h @@ -15,17 +15,17 @@ struct sandbox_request { uint64_t id; - bool request_from_outside; /* true is yes, false is no */ + bool request_from_outside; /* true is yes, false is no */ struct module * module; char * arguments; int socket_descriptor; struct sockaddr socket_address; uint64_t request_arrival_timestamp; /* cycles */ - uint64_t enqueue_timestamp; /* cycles */ + uint64_t enqueue_timestamp; /* cycles */ uint64_t absolute_deadline; /* cycles */ - char * previous_function_output; - ssize_t output_length; - ssize_t previous_request_length; /* previous request length */ + char * previous_function_output; + ssize_t output_length; + ssize_t previous_request_length; /* * Unitless estimate of the instantaneous fraction of system capacity required to run the request * Calculated by estimated execution time (cycles) * runtime_admissions_granularity / relative deadline (cycles) @@ -78,26 +78,26 @@ sandbox_request_allocate(struct module *module, bool request_from_outside, ssize assert(sandbox_request); /* Sets the ID to the value before the increment */ - sandbox_request->id = sandbox_request_count_postfix_increment(); + sandbox_request->id = sandbox_request_count_postfix_increment(); - sandbox_request->module = module; - sandbox_request->request_from_outside = request_from_outside; - sandbox_request->arguments = arguments; - sandbox_request->socket_descriptor = socket_descriptor; + sandbox_request->module = module; + sandbox_request->request_from_outside = request_from_outside; + sandbox_request->arguments = arguments; + sandbox_request->socket_descriptor = socket_descriptor; memcpy(&sandbox_request->socket_address, socket_address, sizeof(struct sockaddr)); - sandbox_request->request_arrival_timestamp = request_arrival_timestamp; - sandbox_request->enqueue_timestamp = enqueue_timestamp; - sandbox_request->absolute_deadline = request_arrival_timestamp + module->relative_deadline; - sandbox_request->previous_function_output = previous_function_output; - sandbox_request->output_length = output_length; - sandbox_request->previous_request_length = request_length; + sandbox_request->request_arrival_timestamp = request_arrival_timestamp; + sandbox_request->enqueue_timestamp = enqueue_timestamp; + sandbox_request->absolute_deadline = request_arrival_timestamp + module->relative_deadline; + sandbox_request->previous_function_output = previous_function_output; + sandbox_request->output_length = output_length; + sandbox_request->previous_request_length = request_length; /* * Admissions Control State * Assumption: an estimate of 0 should have been interpreted as a rejection */ assert(admissions_estimate != 0); - sandbox_request->admissions_estimate = admissions_estimate; + sandbox_request->admissions_estimate = admissions_estimate; sandbox_request_log_allocation(sandbox_request); diff --git a/runtime/include/worker_thread_execute_epoll_loop.h b/runtime/include/worker_thread_execute_epoll_loop.h index 942db72..96b922f 100644 --- a/runtime/include/worker_thread_execute_epoll_loop.h +++ b/runtime/include/worker_thread_execute_epoll_loop.h @@ -24,6 +24,7 @@ worker_thread_execute_epoll_loop(void) struct epoll_event epoll_events[RUNTIME_MAX_EPOLL_EVENTS]; int descriptor_count = epoll_wait(worker_thread_epoll_file_descriptor, epoll_events, RUNTIME_MAX_EPOLL_EVENTS, 0); + if (descriptor_count < 0) { if (errno == EINTR) continue; diff --git a/runtime/src/current_sandbox.c b/runtime/src/current_sandbox.c index dce1729..c6c4445 100644 --- a/runtime/src/current_sandbox.c +++ b/runtime/src/current_sandbox.c @@ -70,6 +70,10 @@ current_sandbox_start(void) sandbox_initialize_stdio(sandbox); struct module * next_module = sandbox->module->next_module; + /* + * Add the client fd to epoll if it is the first or last sandbox in the chain because they + * need to read and write from/to this fd + */ if (sandbox->request_from_outside || next_module == NULL) { sandbox_open_http(sandbox); } @@ -78,16 +82,18 @@ current_sandbox_start(void) if (sandbox_receive_request(sandbox) < 0) { error_message = "Unable to receive or parse client request\n"; goto err; - }; + } } else { - /* copy previous output to sandbox->request_response_data, as the input for the current sandbox.*/ - /* let sandbox->http_request->body points to sandbox->request_response_data*/ + /* + * Copy previous output to sandbox->request_response_data, as the input for the current sandbox. + * Let sandbox->http_request->body points to sandbox->request_response_data + */ assert(sandbox->previous_function_output != NULL); memcpy(sandbox->request_response_data, sandbox->previous_function_output, sandbox->output_length); - sandbox->http_request.body = sandbox->request_response_data; - sandbox->http_request.body_length = sandbox->output_length; - sandbox->request_length = sandbox->previous_request_length; - sandbox->request_response_data_length = sandbox->request_length; + sandbox->http_request.body = sandbox->request_response_data; + sandbox->http_request.body_length = sandbox->output_length; + sandbox->request_length = sandbox->previous_request_length; + sandbox->request_response_data_length = sandbox->request_length; } /* Initialize sandbox memory */ @@ -107,7 +113,12 @@ current_sandbox_start(void) if (next_module != NULL) { /* Generate a new request, copy the current sandbox's output to the next request's buffer, and put it to the global queue */ ssize_t output_length = sandbox->request_response_data_length - sandbox->request_length; - char * pre_func_output = (char *) malloc(output_length); + char * pre_func_output = (char *)malloc(output_length); + if (!pre_func_output) { + fprintf(stderr, "Failed to allocate memory for the previous output: %s\n", strerror(errno)); + goto err; + }; + memcpy(pre_func_output, sandbox->request_response_data + sandbox->request_length, output_length); uint64_t enqueue_timestamp = __getcycles(); struct sandbox_request *sandbox_request = @@ -116,11 +127,31 @@ current_sandbox_start(void) (const struct sockaddr *)&sandbox->client_address, sandbox->request_arrival_timestamp, enqueue_timestamp, true, pre_func_output, output_length); - /* TODO: all sandboxs in the chain share the same request id, but sandbox_request_allocate() will busy-wait to generate an unique - id, should we optimize it here?*/ - sandbox_request->id = sandbox->id; + /* TODO: All sandboxs in the chain share the same request id, but sandbox_request_allocate() + * will busy-wait to generate an unique id, should we optimize it here? + */ + sandbox_request->id = sandbox->id; +#ifdef OPT_AVOID_GLOBAL_QUEUE + /* TODO: The running time of the current sandbox contains the next sandbox's initialization time, does it matter? */ + if (sandbox->absolute_deadline == sandbox_request->absolute_deadline) { + /* Put the next sandbox to the local run queue to reduce the overhead of the global queue */ + struct sandbox *next_sandbox = sandbox_allocate(sandbox_request); + if (!next_sandbox) { + free(sandbox_request); + goto err; + } + + assert(next_sandbox->state == SANDBOX_INITIALIZED); + sandbox_set_as_runnable(next_sandbox, SANDBOX_INITIALIZED); + } else { + /* Add to the Global Sandbox Request Scheduler */ + global_request_scheduler_add(sandbox_request); + } +#else /* Add to the Global Sandbox Request Scheduler */ global_request_scheduler_add(sandbox_request); +#endif + /* Remove the client fd from epoll if it is the first sandbox in the chain */ if (sandbox->request_from_outside) { sandbox_remove_from_epoll(sandbox); } diff --git a/runtime/src/global_request_scheduler_minheap.c b/runtime/src/global_request_scheduler_minheap.c index 2a2da5f..3b3c12e 100644 --- a/runtime/src/global_request_scheduler_minheap.c +++ b/runtime/src/global_request_scheduler_minheap.c @@ -75,7 +75,8 @@ sandbox_request_get_priority_fn(void *element) * Initializes the variant and registers against the polymorphic interface */ void -global_request_scheduler_minheap_initialize() { +global_request_scheduler_minheap_initialize() +{ global_request_scheduler_minheap = priority_queue_initialize(4096, true, sandbox_request_get_priority_fn); struct global_request_scheduler_config config = { diff --git a/runtime/src/module.c b/runtime/src/module.c index 3f7cc04..d53f3e2 100644 --- a/runtime/src/module.c +++ b/runtime/src/module.c @@ -371,10 +371,10 @@ module_new_from_json(char *file_name) goto json_parse_err; } - int module_count = 0; - char *request_headers = NULL; - char *reponse_headers = NULL; - struct module *tail_module = NULL; + int module_count = 0; + char *request_headers = NULL; + char *reponse_headers = NULL; + struct module *tail_module = NULL; for (int i = 0; i < total_tokens; i++) { assert(tokens[i].type == JSMN_OBJECT); @@ -559,14 +559,9 @@ module_new_from_json(char *file_name) assert(module); - if (tail_module == NULL) { - tail_module = module; - tail_module->next_module = NULL; - } else { - tail_module->next_module = module; - tail_module = module; - tail_module->next_module = NULL; - } + if (tail_module != NULL) { tail_module->next_module = module; } + tail_module = module; + tail_module->next_module = NULL; module_set_http_info(module, request_count, request_headers, request_content_type, response_count, reponse_headers, response_content_type);