feature: added SJF scheduler

added REGRESSION based prediction support
pull/385/head
Emil Abbasov 1 year ago
parent 4ae8b02413
commit fdf75b4e8f

@ -116,7 +116,7 @@
"tenant.h": "c",
"route_config.h": "c",
"http_router.h": "c",
"admissions_info.h": "c",
"execution_histogram.h": "c",
"tcp_server.h": "c",
"stdint.h": "c",
"scheduler_options.h": "c",
@ -144,7 +144,20 @@
"algorithm": "c",
"stdio.h": "c",
"get_time.h": "c",
"unistd.h": "c"
"unistd.h": "c",
"wasi.h": "c",
"stat.h": "c",
"functional": "c",
"sandbox_state.h": "c",
"ratio": "c",
"tuple": "c",
"type_traits": "c",
"perf_window.h": "c",
"http_route_total.h": "c",
"sledge_abi_symbols.h": "c",
"mutex": "c",
"lock.h": "c",
"route_latency.h": "c"
},
"files.exclude": {
"**/.git": true,

@ -27,6 +27,7 @@ all: \
license_plate_detection.install \
resize_image.install \
cnn_face_detection.install \
get_jpeg_resolution.install \
scratch_storage_get.install \
scratch_storage_set.install \
scratch_storage_delete.install \
@ -109,6 +110,9 @@ license_plate_detection.install: ../runtime/bin/license_plate_detection.wasm.so
.PHONY: cnn_face_detection.install
cnn_face_detection.install: ../runtime/bin/cnn_face_detection.wasm.so
.PHONY: get_jpeg_resolution.install
get_jpeg_resolution.install: ../runtime/bin/get_jpeg_resolution.wasm.so
.PHONY: trap_divzero.install
trap_divzero.install: ../runtime/bin/trap_divzero.wasm.so

@ -1 +1 @@
Subproject commit e2ba697861201f2aaca37460842ab5c34c8d1716
Subproject commit ecd9f1056a882b46803940e18e85f970989dc1c6

@ -38,6 +38,10 @@ BINARY_NAME=sledgert
# Feature Toggles
CFLAGS += -DEXECUTION_HISTOGRAM
# CFLAGS += -DEXECUTION_REGRESSION
# It is recommended (not mandatory) to enable this flag along with the EXECUTION_HISTOGRAM flag:
# CFLAGS += -DADMISSIONS_CONTROL
# Debugging Flags
@ -56,6 +60,7 @@ BINARY_NAME=sledgert
# CFLAGS += -DLOG_TO_FILE
# Various Informational Logs for Debugging
# CFLAGS += -DLOG_EXECUTION_HISTOGRAM
# CFLAGS += -DLOG_ADMISSIONS_CONTROL
# CFLAGS += -DLOG_CONTEXT_SWITCHES
# CFLAGS += -DLOG_HTTP_PARSER

@ -1,18 +1,19 @@
#pragma once
#ifdef ADMISSIONS_CONTROL
#include <stdbool.h>
#include <stdint.h>
#ifdef ADMISSIONS_CONTROL
#define ADMISSIONS_CONTROL_GRANULARITY 1000000
extern _Atomic uint64_t admissions_control_admitted;
extern uint64_t admissions_control_capacity;
#endif
void admissions_control_initialize(void);
void admissions_control_add(uint64_t admissions_estimate);
void admissions_control_subtract(uint64_t admissions_estimate);
uint64_t admissions_control_calculate_estimate(uint64_t estimated_execution, uint64_t relative_deadline);
uint64_t admissions_control_calculate_estimate_us(uint32_t estimated_execution_us, uint32_t relative_deadline_us);
void admissions_control_log_decision(uint64_t admissions_estimate, bool admitted);
uint64_t admissions_control_decide(uint64_t admissions_estimate);
#endif

@ -1,15 +0,0 @@
#pragma once
#include "perf_window_t.h"
struct admissions_info {
struct perf_window perf_window;
uint8_t percentile; /* 50 - 99 */
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 */
};
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);

@ -4,6 +4,7 @@
#include "current_wasm_module_instance.h"
#include "sandbox_types.h"
#include "listener_thread.h"
/* current sandbox that is active.. */
extern thread_local struct sandbox *worker_thread_current_sandbox;
@ -46,8 +47,9 @@ current_sandbox_set(struct sandbox *sandbox)
/* Private */
.wasi_context = NULL,
};
worker_thread_current_sandbox = NULL;
runtime_worker_threads_deadline[worker_thread_idx] = UINT64_MAX;
worker_thread_current_sandbox = NULL;
/* This is because the event core does not maintain core-assigned deadline */
if (!listener_thread_is_running()) runtime_worker_threads_deadline[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,
@ -55,8 +57,9 @@ current_sandbox_set(struct sandbox *sandbox)
sledge_abi__current_wasm_module_instance.abi.table = sandbox->module->indirect_table;
wasm_globals_update_if_used(&sandbox->globals, 0,
&sledge_abi__current_wasm_module_instance.abi.wasmg_0);
worker_thread_current_sandbox = sandbox;
runtime_worker_threads_deadline[worker_thread_idx] = sandbox->absolute_deadline;
worker_thread_current_sandbox = sandbox;
if (!listener_thread_is_running())
runtime_worker_threads_deadline[worker_thread_idx] = sandbox->absolute_deadline;
}
}

@ -0,0 +1,14 @@
#pragma once
#include "perf_window_t.h"
struct execution_histogram {
struct perf_window perf_window;
uint8_t percentile; /* 50 - 99 */
int control_index; /* Precomputed Lookup index when perf_window is full */
uint64_t estimated_execution; /* cycles */
};
void execution_histogram_initialize(struct execution_histogram *execution_histogram, uint8_t percentile,
uint64_t expected_execution);
void execution_histogram_update(struct execution_histogram *execution_histogram, uint64_t execution_duration);

@ -0,0 +1,25 @@
#pragma once
#ifdef EXECUTION_REGRESSION
#include <stdint.h>
#include "http_session.h"
static inline uint64_t
get_regression_prediction(struct http_session *session)
{
/* Default Pre-processing - Extract payload size */
const int payload_size = session->http_request.body_length;
const double regression_params[2] = { payload_size, session->param2 };
/* Regression */
const struct regression_model model = session->route->regr_model;
const uint64_t prediction = (regression_params[0] / model.scale * model.beta1
+ regression_params[1] / model.scale * model.beta2)
+ model.bias;
return prediction;
}
#endif

@ -1,8 +1,6 @@
#pragma once
#include <stdlib.h>
#include <string.h>
#include "http.h"
#include "module.h"
#include "route_latency.h"
@ -22,7 +20,8 @@ http_router_init(http_router_t *router, size_t capacity)
}
static inline int
http_router_add_route(http_router_t *router, struct route_config *config, struct module *module)
http_router_add_route(http_router_t *router, struct route_config *config, struct module *module,
struct module *pre_module)
{
assert(router != NULL);
assert(config != NULL);
@ -40,10 +39,27 @@ http_router_add_route(http_router_t *router, struct route_config *config, struct
route_latency_init(&route.latency);
http_route_total_init(&route.metrics);
/* 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,
route.relative_deadline);
#ifdef EXECUTION_REGRESSION
/* Execution Regression setup */
assert(pre_module);
route.pre_module = pre_module;
route.regr_model.bias = config->model_bias / 1000.0;
route.regr_model.scale = config->model_scale / 1000.0;
route.regr_model.num_of_param = config->model_num_of_param;
route.regr_model.beta1 = config->model_beta1 / 1000.0;
route.regr_model.beta2 = config->model_beta2 / 1000.0;
#endif
const uint64_t expected_execution = route.relative_deadline / 2;
#ifdef ADMISSIONS_CONTROL
/* Addmissions Control setup */
route.execution_histogram.estimated_execution = expected_execution;
#endif
#ifdef EXECUTION_HISTOGRAM
/* Execution Histogram setup */
execution_histogram_initialize(&route.execution_histogram, config->admissions_percentile, expected_execution);
#endif
int rc = vec_route_t_push(router, route);
if (unlikely(rc == -1)) { return -1; }

@ -57,6 +57,9 @@ struct http_session {
uint64_t request_downloaded_timestamp;
uint64_t response_takeoff_timestamp;
uint64_t response_sent_timestamp;
bool did_preprocessing;
uint64_t preprocessing_duration;
double param2;
};
extern void http_session_perf_log_print_entry(struct http_session *http_session);

@ -15,8 +15,8 @@ static inline void
http_session_perf_log_print_header()
{
if (http_session_perf_log == NULL) { perror("http_session perf log"); }
fprintf(http_session_perf_log,
"tenant,route,state,header_len,resp_body_len,receive_duration,sent_duration,total_lifetime,proc_MHz\n");
fprintf(http_session_perf_log, "tenant,route,state,header_len,resp_body_len,receive_duration,sent_duration,"
"total_lifetime,preprocessing,proc_MHz\n");
}
static inline void

@ -1,22 +1,11 @@
#pragma once
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include "admissions_control.h"
#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"
#include "sledge_abi_symbols.h"
#include "wasm_stack.h"
#include "wasm_memory.h"
#include "wasm_table.h"
extern thread_local int worker_thread_idx;
@ -28,9 +17,15 @@ struct module_pool {
struct wasm_stack_pool stack;
} CACHE_PAD_ALIGNED;
enum module_type
{
APP_MODULE,
PREPROCESS_MODULE
};
struct module {
char *path;
uint32_t stack_size; /* a specification? */
char *path;
uint32_t stack_size; /* a specification? */
enum module_type type;
/* Handle and ABI Symbols for *.so file */
struct sledge_abi_symbols abi;
@ -41,12 +36,13 @@ struct module {
struct module_pool *pools;
} CACHE_PAD_ALIGNED;
/********************************
* Public Methods from module.c *
*******************************/
void module_free(struct module *module);
struct module *module_alloc(char *path);
struct module *module_alloc(char *path, enum module_type type);
/*************************
* Public Static Inlines *
@ -115,7 +111,8 @@ module_alloc_table(struct module *module)
static inline void
module_initialize_pools(struct module *module)
{
for (int i = 0; i < runtime_worker_threads_count; i++) {
/* Create only a single pool for the preprocessing module, since it is executed only by the event core. */
for (int i = 0; i < (module->type == APP_MODULE ? runtime_worker_threads_count : 1); i++) {
wasm_memory_pool_init(&module->pools[i].memory, false);
wasm_stack_pool_init(&module->pools[i].stack, false);
}
@ -124,7 +121,7 @@ module_initialize_pools(struct module *module)
static inline void
module_deinitialize_pools(struct module *module)
{
for (int i = 0; i < runtime_worker_threads_count; i++) {
for (int i = 0; i < (module->type == APP_MODULE ? runtime_worker_threads_count : 1); i++) {
wasm_memory_pool_deinit(&module->pools[i].memory);
wasm_stack_pool_deinit(&module->pools[i].stack);
}

@ -3,20 +3,30 @@
#include <stdint.h>
#include <stddef.h>
#include "admissions_info.h"
#include "execution_histogram.h"
#include "module.h"
#include "http_route_total.h"
#include "perf_window.h"
struct regression_model {
double bias;
double scale;
uint32_t num_of_param;
double beta1;
double beta2;
};
/* Assumption: entrypoint is always _start. This should be enhanced later */
struct route {
char *route;
struct http_route_total metrics;
struct module *module;
struct module *pre_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 execution_histogram execution_histogram;
struct perf_window latency;
struct regression_model regr_model;
};

@ -12,9 +12,14 @@ enum route_config_member
{
route_config_member_route,
route_config_member_path,
route_config_member_path_premodule,
route_config_member_admissions_percentile,
route_config_member_expected_execution_us,
route_config_member_relative_deadline_us,
route_config_member_model_bias,
route_config_member_model_scale,
route_config_member_model_num_of_param,
route_config_member_model_beta1,
route_config_member_model_beta2,
route_config_member_http_resp_content_type,
route_config_member_len
};
@ -22,9 +27,14 @@ enum route_config_member
struct route_config {
char *route;
char *path;
char *path_premodule;
uint8_t admissions_percentile;
uint32_t expected_execution_us;
uint32_t relative_deadline_us;
uint32_t model_bias;
uint32_t model_scale;
uint32_t model_num_of_param;
uint32_t model_beta1;
uint32_t model_beta2;
char *http_resp_content_type;
};
@ -44,9 +54,13 @@ route_config_print(struct route_config *config)
{
printf("[Route] Route: %s\n", config->route);
printf("[Route] Path: %s\n", config->path);
printf("[Route] Path of Preprocessing Module: %s\n", config->path_premodule);
printf("[Route] Admissions Percentile: %hhu\n", config->admissions_percentile);
printf("[Route] Expected Execution (us): %u\n", config->expected_execution_us);
printf("[Route] Relative Deadline (us): %u\n", config->relative_deadline_us);
printf("[Route] Model Bias: %u\n", config->model_bias);
printf("[Route] Model Scale: %u\n", config->model_scale);
printf("[Route] Model Num of Parameters: %u\n", config->model_num_of_param);
printf("[Route] Model Betas: [%u, %u]\n", config->model_beta1, config->model_beta2);
printf("[Route] HTTP Response Content Type: %s\n", config->http_resp_content_type);
}
@ -68,6 +82,11 @@ route_config_validate(struct route_config *config, bool *did_set)
return -1;
}
if (did_set[route_config_member_path_premodule] == false) {
fprintf(stderr, "path_premodule field is required\n");
return -1;
}
if (did_set[route_config_member_http_resp_content_type] == false) {
debuglog("http_resp_content_type not set, defaulting to text/plain\n");
config->http_resp_content_type = "text/plain";
@ -86,11 +105,6 @@ route_config_validate(struct route_config *config, bool *did_set)
}
#ifdef ADMISSIONS_CONTROL
if (did_set[route_config_member_expected_execution_us] == false) {
fprintf(stderr, "expected-execution-us is required\n");
return -1;
}
if (did_set[route_config_member_admissions_percentile] == false) {
fprintf(stderr, "admissions_percentile is required\n");
return -1;
@ -101,17 +115,6 @@ route_config_validate(struct route_config *config, bool *did_set)
config->admissions_percentile);
return -1;
}
/* If the ratio is too big, admissions control is too coarse */
uint32_t ratio = config->relative_deadline_us / config->expected_execution_us;
if (ratio > ADMISSIONS_CONTROL_GRANULARITY) {
fprintf(stderr,
"Ratio of Deadline to Execution time cannot exceed admissions control "
"granularity of "
"%d\n",
ADMISSIONS_CONTROL_GRANULARITY);
return -1;
}
#endif
}

@ -8,9 +8,14 @@
static const char *route_config_json_keys[route_config_member_len] = { "route",
"path",
"path_premodule",
"admissions-percentile",
"expected-execution-us",
"relative-deadline-us",
"model-bias",
"model-scale",
"model-num-of-param",
"model-beta1",
"model-beta2",
"http-resp-content-type" };
static inline int
@ -61,6 +66,11 @@ route_config_parse(struct route_config *config, const char *json_buf, jsmntok_t
if (route_config_set_key_once(did_set, route_config_member_path) == -1) return -1;
config->path = strndup(json_buf + tokens[i].start, tokens[i].end - tokens[i].start);
} else if (strcmp(key, route_config_json_keys[route_config_member_path_premodule]) == 0) {
if (!is_nonempty_string(tokens[i], key)) return -1;
if (route_config_set_key_once(did_set, route_config_member_path_premodule) == -1) return -1;
config->path_premodule = strndup(json_buf + tokens[i].start, tokens[i].end - tokens[i].start);
} else if (strcmp(key, route_config_json_keys[route_config_member_admissions_percentile]) == 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_admissions_percentile) == -1)
@ -70,15 +80,6 @@ route_config_parse(struct route_config *config, const char *json_buf, jsmntok_t
route_config_json_keys[route_config_member_admissions_percentile],
&config->admissions_percentile);
if (rc < 0) return -1;
} else if (strcmp(key, route_config_json_keys[route_config_member_expected_execution_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_expected_execution_us) == -1)
return -1;
int rc = parse_uint32_t(tokens[i], json_buf,
route_config_json_keys[route_config_member_expected_execution_us],
&config->expected_execution_us);
if (rc < 0) return -1;
} 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)
@ -88,6 +89,46 @@ route_config_parse(struct route_config *config, const char *json_buf, jsmntok_t
route_config_json_keys[route_config_member_relative_deadline_us],
&config->relative_deadline_us);
if (rc < 0) return -1;
} else if (strcmp(key, route_config_json_keys[route_config_member_model_bias]) == 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_model_bias) == -1) return -1;
int rc = parse_uint32_t(tokens[i], json_buf,
route_config_json_keys[route_config_member_model_bias],
&config->model_bias);
if (rc < 0) return -1;
} else if (strcmp(key, route_config_json_keys[route_config_member_model_scale]) == 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_model_scale) == -1) return -1;
int rc = parse_uint32_t(tokens[i], json_buf,
route_config_json_keys[route_config_member_model_scale],
&config->model_scale);
if (rc < 0) return -1;
} else if (strcmp(key, route_config_json_keys[route_config_member_model_num_of_param]) == 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_model_num_of_param) == -1) return -1;
int rc = parse_uint32_t(tokens[i], json_buf,
route_config_json_keys[route_config_member_model_num_of_param],
&config->model_num_of_param);
if (rc < 0) return -1;
} else if (strcmp(key, route_config_json_keys[route_config_member_model_beta1]) == 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_model_beta1) == -1) return -1;
int rc = parse_uint32_t(tokens[i], json_buf,
route_config_json_keys[route_config_member_model_beta1],
&config->model_beta1);
if (rc < 0) return -1;
} else if (strcmp(key, route_config_json_keys[route_config_member_model_beta2]) == 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_model_beta2) == -1) return -1;
int rc = parse_uint32_t(tokens[i], json_buf,
route_config_json_keys[route_config_member_model_beta2],
&config->model_beta2);
if (rc < 0) return -1;
} else if (strcmp(key, route_config_json_keys[route_config_member_http_resp_content_type]) == 0) {
if (!is_nonempty_string(tokens[i], key)) return -1;
if (route_config_set_key_once(did_set, route_config_member_http_resp_content_type) == -1)
@ -97,7 +138,7 @@ route_config_parse(struct route_config *config, const char *json_buf, jsmntok_t
tokens[i].end - tokens[i].start);
} else {
fprintf(stderr, "%s is not a valid key\n", key);
return -1;
// return -1;
}
}

@ -15,7 +15,7 @@ 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");
"running_sys,running_user,asleep,returned,complete,error,proc_MHz,payload_size\n");
}
/**
@ -36,8 +36,9 @@ sandbox_perf_log_print_entry(struct sandbox *sandbox)
* 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",
sandbox->id, sandbox->tenant->name, sandbox->route->route, sandbox_state_stringify(sandbox->state),
fprintf(sandbox_perf_log,
"%lu,%s,%s,%s,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%u,%u,%d,%d\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],
@ -45,7 +46,7 @@ sandbox_perf_log_print_entry(struct sandbox *sandbox)
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],
runtime_processor_speed_MHz);
runtime_processor_speed_MHz, sandbox->response_code, 0, sandbox->payload_size);
}
static inline void

@ -12,6 +12,8 @@
#include "sandbox_state_transition.h"
#include "sandbox_summarize_page_allocations.h"
#include "sandbox_types.h"
#include "execution_histogram.h"
#include "admissions_control.h"
/**
* Transitions a sandbox from the SANDBOX_RETURNED state to the SANDBOX_COMPLETE state.
@ -46,15 +48,24 @@ sandbox_set_as_complete(struct sandbox *sandbox, sandbox_state_t last_state)
sandbox_state_totals_increment(SANDBOX_COMPLETE);
sandbox_state_totals_decrement(last_state);
struct route *route = sandbox->route;
#ifdef EXECUTION_HISTOGRAM
/* Execution Histogram Post Processing */
const uint64_t execution_duration = sandbox->duration_of_state[SANDBOX_RUNNING_USER]
+ sandbox->duration_of_state[SANDBOX_RUNNING_SYS];
execution_histogram_update(&route->execution_histogram, execution_duration);
#endif
#ifdef ADMISSIONS_CONTROL
/* 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]);
admissions_control_subtract(sandbox->admissions_estimate);
#endif
/* Terminal State Logging for Sandbox */
sandbox_perf_log_print_entry(sandbox);
sandbox_summarize_page_allocations(sandbox);
route_latency_add(&sandbox->route->latency, sandbox->total_time);
route_latency_add(&route->latency, sandbox->total_time);
/* State Change Hooks */
sandbox_state_transition_from_hook(sandbox, last_state);

@ -13,6 +13,7 @@
#include "sandbox_state_transition.h"
#include "sandbox_summarize_page_allocations.h"
#include "panic.h"
#include "admissions_control.h"
/**
* Transitions a sandbox to the SANDBOX_ERROR state.
@ -48,14 +49,20 @@ sandbox_set_as_error(struct sandbox *sandbox, sandbox_state_t last_state)
/* State Change Bookkeeping */
assert(now > sandbox->timestamp_of.last_state_change);
sandbox->last_state_duration = now - sandbox->timestamp_of.last_state_change;
if (last_state == SANDBOX_RUNNING_SYS)
sandbox->remaining_exec = (sandbox->remaining_exec > sandbox->last_state_duration)
? sandbox->remaining_exec - sandbox->last_state_duration
: 0;
sandbox->duration_of_state[last_state] += sandbox->last_state_duration;
sandbox->timestamp_of.last_state_change = now;
sandbox_state_history_append(&sandbox->state_history, SANDBOX_ERROR);
sandbox_state_totals_increment(SANDBOX_ERROR);
sandbox_state_totals_decrement(last_state);
#ifdef ADMISSIONS_CONTROL
/* Admissions Control Post Processing */
admissions_control_subtract(sandbox->admissions_estimate);
#endif
/* Return HTTP session to listener core to be written back to client */
http_session_set_response_header(sandbox->http, 500);

@ -25,6 +25,10 @@ sandbox_set_as_interrupted(struct sandbox *sandbox, sandbox_state_t last_state)
/* State Change Bookkeeping */
assert(now > sandbox->timestamp_of.last_state_change);
sandbox->last_state_duration = now - sandbox->timestamp_of.last_state_change;
assert(last_state == SANDBOX_RUNNING_USER);
sandbox->remaining_exec = (sandbox->remaining_exec > sandbox->last_state_duration)
? sandbox->remaining_exec - sandbox->last_state_duration
: 0;
sandbox->duration_of_state[last_state] += sandbox->last_state_duration;
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 */

@ -45,6 +45,9 @@ sandbox_set_as_returned(struct sandbox *sandbox, sandbox_state_t last_state)
/* State Change Bookkeeping */
assert(now > sandbox->timestamp_of.last_state_change);
sandbox->last_state_duration = now - sandbox->timestamp_of.last_state_change;
sandbox->remaining_exec = (sandbox->remaining_exec > sandbox->last_state_duration)
? sandbox->remaining_exec - sandbox->last_state_duration
: 0;
sandbox->duration_of_state[last_state] += sandbox->last_state_duration;
sandbox->timestamp_of.last_state_change = now;
sandbox_state_history_append(&sandbox->state_history, SANDBOX_RETURNED);
@ -60,5 +63,7 @@ sandbox_set_as_returned(struct sandbox *sandbox, sandbox_state_t last_state)
sandbox_state_transition_from_hook(sandbox, last_state);
sandbox_state_transition_to_hook(sandbox, SANDBOX_RETURNED);
assert(sandbox->response_code == 0);
sandbox->response_code = 200;
sandbox_process_scheduler_updates(sandbox);
}

@ -41,6 +41,11 @@ sandbox_set_as_running_sys(struct sandbox *sandbox, sandbox_state_t last_state)
/* State Change Bookkeeping */
assert(now > sandbox->timestamp_of.last_state_change);
sandbox->last_state_duration = now - sandbox->timestamp_of.last_state_change;
if (last_state == SANDBOX_RUNNING_USER) {
sandbox->remaining_exec = (sandbox->remaining_exec > sandbox->last_state_duration)
? sandbox->remaining_exec - sandbox->last_state_duration
: 0;
}
sandbox->duration_of_state[last_state] += sandbox->last_state_duration;
sandbox->timestamp_of.last_state_change = now;
sandbox_state_history_append(&sandbox->state_history, SANDBOX_RUNNING_SYS);
@ -55,6 +60,8 @@ sandbox_set_as_running_sys(struct sandbox *sandbox, sandbox_state_t last_state)
static inline void
sandbox_syscall(struct sandbox *sandbox)
{
if (sandbox->module->type == PREPROCESS_MODULE) return;
assert(sandbox->state == SANDBOX_RUNNING_USER);
sandbox_set_as_running_sys(sandbox, SANDBOX_RUNNING_USER);

@ -37,6 +37,11 @@ sandbox_set_as_running_user(struct sandbox *sandbox, sandbox_state_t last_state)
/* State Change Bookkeeping */
assert(now > sandbox->timestamp_of.last_state_change);
sandbox->last_state_duration = now - sandbox->timestamp_of.last_state_change;
if (last_state == SANDBOX_RUNNING_SYS) {
sandbox->remaining_exec = (sandbox->remaining_exec > sandbox->last_state_duration)
? sandbox->remaining_exec - sandbox->last_state_duration
: 0;
}
sandbox->duration_of_state[last_state] += sandbox->last_state_duration;
sandbox->timestamp_of.last_state_change = now;
sandbox_state_history_append(&sandbox->state_history, SANDBOX_RUNNING_USER);
@ -61,6 +66,8 @@ sandbox_set_as_running_user(struct sandbox *sandbox, sandbox_state_t last_state)
static inline void
sandbox_return(struct sandbox *sandbox)
{
if (sandbox->module->type == PREPROCESS_MODULE) return;
assert(sandbox->state == SANDBOX_RUNNING_SYS);
sandbox_set_as_running_user(sandbox, SANDBOX_RUNNING_SYS);
}

@ -38,6 +38,7 @@ struct sandbox {
uint64_t id;
sandbox_state_t state;
struct sandbox_state_history state_history;
uint16_t response_code;
/* Accounting Info */
@ -61,10 +62,12 @@ struct sandbox {
uint64_t duration_of_state[SANDBOX_STATE_COUNT];
uint64_t last_state_duration;
uint64_t remaining_exec;
uint64_t absolute_deadline;
uint64_t admissions_estimate; /* estimated execution time (cycles) * runtime_admissions_granularity / relative
deadline (cycles) */
uint64_t total_time; /* Total time from Request to Response */
int payload_size;
/* System Interface State */
int32_t return_value;

@ -106,6 +106,31 @@ done:
return local_runqueue_get_next();
}
static inline struct sandbox *
scheduler_sjf_get_next()
{
struct sandbox *local = local_runqueue_get_next();
uint64_t local_rem_exec = local == NULL ? UINT64_MAX : local->remaining_exec;
struct sandbox *global = NULL;
uint64_t global_remaining_exec = 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_remaining_exec < local_rem_exec) {
if (global_request_scheduler_remove_if_earlier(&global, local_rem_exec) == 0) {
assert(global != NULL);
assert(global->remaining_exec < local_rem_exec);
sandbox_prepare_execution_environment(global);
assert(global->state == SANDBOX_INITIALIZED);
sandbox_set_as_runnable(global, SANDBOX_INITIALIZED);
}
}
/* Return what is at the head of the local runqueue or NULL if empty */
return local_runqueue_get_next();
}
static inline struct sandbox *
scheduler_edf_get_next()
{
@ -163,6 +188,8 @@ scheduler_get_next()
return scheduler_mtdbf_get_next();
case SCHEDULER_MTDS:
return scheduler_mtds_get_next();
case SCHEDULER_SJF:
return scheduler_sjf_get_next();
case SCHEDULER_EDF:
return scheduler_edf_get_next();
case SCHEDULER_FIFO:
@ -177,12 +204,13 @@ scheduler_initialize()
{
switch (scheduler) {
case SCHEDULER_MTDBF:
// global_request_scheduler_mtdbf_initialize();
/* TODO: loading */
break;
case SCHEDULER_MTDS:
global_request_scheduler_mtds_initialize();
break;
case SCHEDULER_EDF:
case SCHEDULER_SJF:
global_request_scheduler_minheap_initialize();
break;
case SCHEDULER_FIFO:
@ -204,6 +232,7 @@ scheduler_runqueue_initialize()
local_runqueue_mtds_initialize();
break;
case SCHEDULER_EDF:
case SCHEDULER_SJF:
local_runqueue_minheap_initialize();
break;
case SCHEDULER_FIFO:
@ -222,6 +251,8 @@ scheduler_print(enum SCHEDULER variant)
return "FIFO";
case SCHEDULER_EDF:
return "EDF";
case SCHEDULER_SJF:
return "SJF";
case SCHEDULER_MTDS:
return "MTDS";
case SCHEDULER_MTDBF:
@ -287,6 +318,7 @@ scheduler_process_policy_specific_updates_on_interrupts(struct sandbox *interrup
case SCHEDULER_FIFO:
return;
case SCHEDULER_EDF:
case SCHEDULER_SJF:
return;
case SCHEDULER_MTDS:
local_timeout_queue_process_promotions();

@ -2,10 +2,11 @@
enum SCHEDULER
{
SCHEDULER_FIFO = 0,
SCHEDULER_EDF = 1,
SCHEDULER_MTDS = 2,
SCHEDULER_MTDBF = 3
SCHEDULER_FIFO,
SCHEDULER_EDF,
SCHEDULER_SJF,
SCHEDULER_MTDS,
SCHEDULER_MTDBF
};
extern enum SCHEDULER scheduler;

@ -96,7 +96,7 @@ tenant_config_parse(struct tenant_config *config, const char *json_buf, jsmntok_
} else {
fprintf(stderr, "%s is not a valid key\n", key);
return -1;
// return -1;
}
}

@ -3,7 +3,6 @@
#include <stdint.h>
#include <string.h>
#include "admissions_info.h"
#include "http.h"
#include "listener_thread.h"
#include "module_database.h"
@ -30,6 +29,7 @@ tenant_policy_specific_init(struct tenant *tenant, struct tenant_config *config)
case SCHEDULER_FIFO:
break;
case SCHEDULER_EDF:
case SCHEDULER_SJF:
break;
case SCHEDULER_MTDS:
/* Deferable Server Initialization */
@ -103,7 +103,7 @@ tenant_alloc(struct tenant_config *config)
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);
module = module_alloc(config->routes[i].path, APP_MODULE);
if (module != NULL) {
module_database_add(&tenant->module_db, module);
config->routes[i].path = NULL;
@ -115,8 +115,27 @@ tenant_alloc(struct tenant_config *config)
assert(module != NULL);
struct module *pre_module = NULL;
#ifdef EXECUTION_REGRESSION
pre_module = module_database_find_by_path(&tenant->module_db, config->routes[i].path_premodule);
if (pre_module == NULL) {
/* Ownership of path moves here */
pre_module = module_alloc(config->routes[i].path_premodule, PREPROCESS_MODULE);
if (pre_module != NULL) {
module_database_add(&tenant->module_db, pre_module);
config->routes[i].path_premodule = NULL;
}
} else {
free(config->routes[i].path_premodule);
config->routes[i].path_premodule = NULL;
}
assert(pre_module != NULL);
#endif
/* Ownership of config's route and http_resp_content_type move here */
int rc = http_router_add_route(&tenant->router, &config->routes[i], module);
int rc = http_router_add_route(&tenant->router, &config->routes[i], module, pre_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);
@ -160,5 +179,6 @@ get_next_timeout_of_tenant(uint64_t replenishment_period)
* @param tenant
* @returns 0 on success, -1 on error
*/
int tenant_listen(struct tenant *tenant);
int listener_thread_register_tenant(struct tenant *tenant);
int tenant_listen(struct tenant *tenant);
int listener_thread_register_tenant(struct tenant *tenant);
void tenant_preprocess(struct http_session *session);

@ -8,6 +8,8 @@
#include "panic.h"
#include "runtime.h"
#ifdef ADMISSIONS_CONTROL
/*
* Unitless estimate of the instantaneous fraction of system capacity required to complete all previously
* admitted work. This is used to calculate free capacity as part of admissions control
@ -19,40 +21,32 @@
* success or failure)
*/
#ifdef ADMISSIONS_CONTROL
_Atomic uint64_t admissions_control_admitted;
uint64_t admissions_control_capacity;
const double admissions_control_overhead = 0.2;
#endif
void
admissions_control_initialize()
{
#ifdef ADMISSIONS_CONTROL
atomic_init(&admissions_control_admitted, 0);
admissions_control_capacity = runtime_worker_threads_count * ADMISSIONS_CONTROL_GRANULARITY
* ((double)1.0 - admissions_control_overhead);
#endif
}
void
admissions_control_add(uint64_t admissions_estimate)
{
#ifdef ADMISSIONS_CONTROL
assert(admissions_estimate > 0);
atomic_fetch_add(&admissions_control_admitted, admissions_estimate);
#ifdef LOG_ADMISSIONS_CONTROL
debuglog("Runtime Admitted: %lu / %lu\n", admissions_control_admitted, admissions_control_capacity);
#endif
#endif /* ADMISSIONS_CONTROL */
}
void
admissions_control_subtract(uint64_t admissions_estimate)
{
#ifdef ADMISSIONS_CONTROL
/* Assumption: Should never underflow */
if (unlikely(admissions_estimate > admissions_control_admitted)) panic("Admissions Estimate underflow\n");
@ -61,14 +55,11 @@ admissions_control_subtract(uint64_t admissions_estimate)
#ifdef LOG_ADMISSIONS_CONTROL
debuglog("Runtime Admitted: %lu / %lu\n", admissions_control_admitted, admissions_control_capacity);
#endif
#endif /* ADMISSIONS_CONTROL */
}
uint64_t
admissions_control_calculate_estimate(uint64_t estimated_execution, uint64_t relative_deadline)
{
#ifdef ADMISSIONS_CONTROL
assert(relative_deadline != 0);
uint64_t admissions_estimate = (estimated_execution * (uint64_t)ADMISSIONS_CONTROL_GRANULARITY)
/ relative_deadline;
@ -76,31 +67,15 @@ admissions_control_calculate_estimate(uint64_t estimated_execution, uint64_t rel
panic("Ratio of Deadline to Execution time cannot exceed %d\n", ADMISSIONS_CONTROL_GRANULARITY);
return admissions_estimate;
#else
return 0;
#endif
}
uint64_t
admissions_control_calculate_estimate_us(uint32_t estimated_execution_us, uint32_t relative_deadline_us)
{
#ifdef ADMISSIONS_CONTROL
assert(relative_deadline_us != 0);
return (uint64_t)((uint64_t)(estimated_execution_us * ADMISSIONS_CONTROL_GRANULARITY)) / relative_deadline_us;
#else
return 0;
#endif
}
void
admissions_control_log_decision(uint64_t admissions_estimate, bool admitted)
{
#ifdef ADMISSIONS_CONTROL
#ifdef LOG_ADMISSIONS_CONTROL
debuglog("Admitted: %lu, Capacity: %lu, Estimate: %lu, Admitted? %s\n", admissions_control_admitted,
admissions_control_capacity, admissions_estimate, admitted ? "yes" : "no");
#endif /* LOG_ADMISSIONS_CONTROL */
#endif /* ADMISSIONS_CONTROL */
}
uint64_t
@ -108,7 +83,6 @@ admissions_control_decide(uint64_t admissions_estimate)
{
uint64_t work_admitted = 1; /* Nominal non-zero value in case admissions control is disabled */
#ifdef ADMISSIONS_CONTROL
if (unlikely(admissions_estimate == 0)) panic("Admissions estimate should never be zero");
uint64_t total_admitted = atomic_load(&admissions_control_admitted);
@ -121,7 +95,8 @@ admissions_control_decide(uint64_t admissions_estimate)
admissions_control_add(admissions_estimate);
work_admitted = admissions_estimate;
}
#endif /* ADMISSIONS_CONTROL */
return work_admitted;
}
#endif /* ADMISSIONS_CONTROL */

@ -1,56 +0,0 @@
#include "admissions_control.h"
#include "admissions_info.h"
#include "debuglog.h"
#include "perf_window.h"
/**
* Initializes perf window
* @param admissions_info
*/
void
admissions_info_initialize(struct admissions_info *admissions_info, uint8_t percentile, uint64_t expected_execution,
uint64_t relative_deadline)
{
#ifdef ADMISSIONS_CONTROL
assert(relative_deadline > 0);
assert(expected_execution > 0);
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);
assert(admissions_info != NULL);
perf_window_initialize(&admissions_info->perf_window);
if (unlikely(percentile < 50 || percentile > 99)) panic("Invalid admissions percentile");
admissions_info->percentile = percentile;
admissions_info->control_index = PERF_WINDOW_CAPACITY * percentile / 100;
#ifdef LOG_ADMISSIONS_CONTROL
debuglog("Percentile: %u\n", admissions_info->percentile);
debuglog("Control Index: %d\n", admissions_info->control_index);
#endif
#endif
}
/*
* Adds an execution value to the perf window and calculates and caches and updated estimate
* @param admissions_info
* @param execution_duration
*/
void
admissions_info_update(struct admissions_info *admissions_info, uint64_t execution_duration)
{
#ifdef ADMISSIONS_CONTROL
struct perf_window *perf_window = &admissions_info->perf_window;
lock_node_t node = {};
lock_lock(&perf_window->lock, &node);
perf_window_add(perf_window, execution_duration);
uint64_t estimated_execution = perf_window_get_percentile(perf_window, admissions_info->percentile,
admissions_info->control_index);
admissions_info->estimate = admissions_control_calculate_estimate(estimated_execution,
admissions_info->relative_deadline);
lock_unlock(&perf_window->lock, &node);
#endif
}

@ -194,5 +194,5 @@ current_sandbox_start(void)
current_sandbox_wasm_trap_handler(rc);
}
current_sandbox_fini();
if (sandbox->module->type == APP_MODULE) current_sandbox_fini();
}

@ -0,0 +1,50 @@
#ifdef EXECUTION_HISTOGRAM
#include "execution_histogram.h"
#include "debuglog.h"
#include "perf_window.h"
/**
* Initializes execution_histogram and its perf window
* @param execution_histogram
*/
void
execution_histogram_initialize(struct execution_histogram *execution_histogram, uint8_t percentile,
uint64_t expected_execution)
{
assert(expected_execution > 0);
execution_histogram->estimated_execution = expected_execution;
assert(execution_histogram != NULL);
perf_window_initialize(&execution_histogram->perf_window);
if (unlikely(percentile < 50 || percentile > 99)) panic("Invalid percentile");
execution_histogram->percentile = percentile;
execution_histogram->control_index = PERF_WINDOW_CAPACITY * percentile / 100;
#ifdef LOG_EXECUTION_HISTOGRAM
debuglog("Percentile: %u\n", execution_histogram->percentile);
debuglog("Control Index: %d\n", execution_histogram->control_index);
#endif
}
/*
* Adds an execution value to the perf window
* @param execution_histogram
* @param execution_duration
*/
void
execution_histogram_update(struct execution_histogram *execution_histogram, uint64_t execution_duration)
{
struct perf_window *perf_window = &execution_histogram->perf_window;
lock_node_t node = {};
lock_lock(&perf_window->lock, &node);
perf_window_add(perf_window, execution_duration);
uint64_t estimated_execution = perf_window_get_percentile(perf_window, execution_histogram->percentile,
execution_histogram->control_index);
execution_histogram->estimated_execution = estimated_execution;
lock_unlock(&perf_window->lock, &node);
}
#endif

@ -2,7 +2,7 @@
#include "global_request_scheduler_deque.h"
#include "runtime.h"
#define GLOBAL_REQUEST_SCHEDULER_DEQUE_CAPACITY (1 << 19)
#define GLOBAL_REQUEST_SCHEDULER_DEQUE_CAPACITY (1 << 12)
static struct deque_sandbox *global_request_scheduler_deque;

@ -43,10 +43,10 @@ global_request_scheduler_minheap_remove(struct sandbox **removed_sandbox)
* @returns 0 if successful, -ENOENT if empty or if request isn't earlier than target_deadline
*/
int
global_request_scheduler_minheap_remove_if_earlier(struct sandbox **removed_sandbox, uint64_t target_deadline)
global_request_scheduler_minheap_remove_if_earlier(struct sandbox **removed_sandbox, uint64_t target_latest_start)
{
return priority_queue_dequeue_if_earlier(global_request_scheduler_minheap, (void **)removed_sandbox,
target_deadline);
target_latest_start);
}
/**
@ -65,6 +65,8 @@ uint64_t
sandbox_get_priority_fn(void *element)
{
struct sandbox *sandbox = (struct sandbox *)element;
if (scheduler == SCHEDULER_SJF) return sandbox->remaining_exec;
assert(scheduler == SCHEDULER_EDF);
return sandbox->absolute_deadline;
};

@ -18,8 +18,8 @@ http_session_perf_log_print_entry(struct http_session *http_session)
const uint64_t sent_duration = http_session->response_sent_timestamp - http_session->response_takeoff_timestamp;
const uint64_t total_lifetime = http_session->response_sent_timestamp - http_session->request_arrival_timestamp;
fprintf(http_session_perf_log, "%s,%s,%u,%lu,%lu,%lu,%lu,%lu,%u\n", http_session->tenant->name,
fprintf(http_session_perf_log, "%s,%s,%u,%lu,%lu,%lu,%lu,%lu,%lu,%u\n", http_session->tenant->name,
http_session->http_request.full_url, http_session->state, http_session->response_header_written,
http_session->response_body_written, receive_duration, sent_duration, total_lifetime,
runtime_processor_speed_MHz);
http_session->preprocessing_duration, runtime_processor_speed_MHz);
}

@ -12,6 +12,8 @@
#include "tenant.h"
#include "tenant_functions.h"
#include "http_session_perf_log.h"
#include "sandbox_perf_log.h"
#include "execution_regression.h"
static void listener_thread_unregister_http_session(struct http_session *http);
static void panic_on_epoll_error(struct epoll_event *evt);
@ -193,11 +195,34 @@ on_client_request_receiving(struct http_session *session)
{
/* Read HTTP request */
int rc = http_session_receive_request(session, (void_star_cb)listener_thread_register_http_session);
if (likely(rc == 0)) {
/* Check if the route is accurate only when the URL is downloaded. Stop downloading if inaccurate. */
if (session->route == NULL && strlen(session->http_request.full_url) > 0) {
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;
}
if (rc == 0) {
#ifdef EXECUTION_REGRESSION
if (!session->did_preprocessing) tenant_preprocess(session);
#endif
on_client_request_received(session);
return;
} else if (unlikely(rc == -EAGAIN)) {
/* session blocked and registered to epoll so continue to next handle */
} else if (rc == -EAGAIN) {
/* session blocked and registered to epoll, so continue to next handle */
#ifdef EXECUTION_REGRESSION
/* try tenant preprocessing if min 4k Bytes received */
if (!session->did_preprocessing && session->http_request.body_length_read > 4096)
tenant_preprocess(session);
#endif
return;
} else if (rc < 0) {
debuglog("Failed to receive or parse request\n");
@ -215,30 +240,29 @@ on_client_request_received(struct http_session *session)
{
assert(session->state == HTTP_SESSION_RECEIVED_REQUEST);
session->request_downloaded_timestamp = __getcycles();
struct route *route = session->route;
uint64_t estimated_execution = route->execution_histogram.estimated_execution;
uint64_t work_admitted = 1;
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;
#ifdef EXECUTION_REGRESSION
estimated_execution = get_regression_prediction(session);
#endif
#ifdef ADMISSIONS_CONTROL
/*
* 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);
uint64_t admissions_estimate = admissions_control_calculate_estimate(estimated_execution,
route->relative_deadline);
work_admitted = admissions_control_decide(admissions_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;
}
#endif
/* Allocate a Sandbox */
session->state = HTTP_SESSION_EXECUTING;
@ -251,9 +275,15 @@ on_client_request_received(struct http_session *session)
return;
}
sandbox->remaining_exec = estimated_execution;
/* 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");
// debuglog("Failed to add sandbox to global queue\n");
sandbox->response_code = 4290;
sandbox->state = SANDBOX_ERROR;
sandbox_perf_log_print_entry(sandbox);
sandbox->http = NULL;
sandbox_free(sandbox);
session->state = HTTP_SESSION_EXECUTION_COMPLETE;
http_session_set_response_header(session, 429);

@ -40,7 +40,7 @@ enum RUNTIME_SIGALRM_HANDLER runtime_sigalrm_handler = RUNTIME_SIGALRM_HANDLER_B
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;
@ -105,7 +105,7 @@ runtime_allocate_available_cores()
static inline void
runtime_get_processor_speed_MHz(void)
{
char *proc_mhz_raw = getenv("PROC_MHZ");
char *proc_mhz_raw = getenv("SLEDGE_PROC_MHZ");
FILE *cmd = NULL;
if (proc_mhz_raw != NULL) {
@ -127,6 +127,7 @@ runtime_get_processor_speed_MHz(void)
char buff[16];
size_t n = fread(buff, 1, sizeof(buff) - 1, cmd);
buff[n] = '\0';
pclose(cmd);
float processor_speed_MHz;
n = sscanf(buff, "%f", &processor_speed_MHz);
@ -139,7 +140,6 @@ runtime_get_processor_speed_MHz(void)
pretty_print_key_value("Worker CPU Freq", "%u MHz\n", runtime_processor_speed_MHz);
done:
pclose(cmd);
return;
err:
goto done;
@ -208,10 +208,12 @@ runtime_configure()
scheduler = SCHEDULER_MTDS;
} else if (strcmp(scheduler_policy, "EDF") == 0) {
scheduler = SCHEDULER_EDF;
} else if (strcmp(scheduler_policy, "SJF") == 0) {
scheduler = SCHEDULER_SJF;
} else if (strcmp(scheduler_policy, "FIFO") == 0) {
scheduler = SCHEDULER_FIFO;
} else {
panic("Invalid scheduler policy: %s. Must be {MTDBF|MTDS|EDF|FIFO}\n", scheduler_policy);
panic("Invalid scheduler policy: %s. Must be {MTDBF|MTDS|EDF|SJF|FIFO}\n", scheduler_policy);
}
pretty_print_key_value("Scheduler Policy", "%s\n", scheduler_print(scheduler));
@ -284,6 +286,18 @@ log_compiletime_config()
pretty_print_key_disabled("Admissions Control");
#endif
#ifdef EXECUTION_HISTOGRAM
pretty_print_key_enabled("Execution Histogram");
#else
pretty_print_key_disabled("Execution Histogram");
#endif
#ifdef EXECUTION_REGRESSION
pretty_print_key_enabled("Execution Regression");
#else
pretty_print_key_disabled("Execution Regression");
#endif
/* Debugging Flags */
printf("Static Compiler Flags (Debugging):\n");

@ -44,7 +44,8 @@ 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->pools = calloc((module->type == APP_MODULE ? runtime_worker_threads_count : 1),
sizeof(struct module_pool));
module->path = path;
@ -106,7 +107,7 @@ module_free(struct module *module)
*/
struct module *
module_alloc(char *path)
module_alloc(char *path, enum module_type type)
{
size_t alignment = (size_t)CACHE_PAD;
size_t size_to_alloc = (size_t)round_to_cache_pad(sizeof(struct module));
@ -120,6 +121,7 @@ module_alloc(char *path)
};
memset(module, 0, size_to_alloc);
module->type = type;
int rc = module_init(module, path);
if (rc < 0) goto init_err;

@ -118,7 +118,11 @@ runtime_initialize(void)
signal(SIGQUIT, runtime_cleanup);
http_parser_settings_initialize();
#ifdef ADMISSIONS_CONTROL
/* Admissions Control Setup */
admissions_control_initialize();
#endif
}
static void

@ -154,6 +154,7 @@ sandbox_init(struct sandbox *sandbox, struct module *module, struct http_session
sandbox->route = route;
sandbox->absolute_deadline = sandbox->timestamp_of.allocation + sandbox->route->relative_deadline;
sandbox->payload_size = session->http_request.body_length;
/*
* Admissions Control State

@ -1,5 +1,6 @@
#include "tenant.h"
#include "tenant_functions.h"
#include "current_sandbox.h"
/**
* Start the tenant as a server listening at tenant->port
@ -23,3 +24,47 @@ err:
rc = -1;
goto done;
}
#ifdef EXECUTION_REGRESSION
void
tenant_preprocess(struct http_session *session)
{
const uint64_t start = __getcycles();
/* Tenant Pre-processing - Extract other useful parameters */
struct sandbox *pre_sandbox = sandbox_alloc(session->route->pre_module, session, session->route,
session->tenant, 1);
if (sandbox_prepare_execution_environment(pre_sandbox)) panic("pre_sandbox environment setup failed");
pre_sandbox->state = SANDBOX_RUNNING_SYS;
assert(current_sandbox_get() == NULL);
current_sandbox_set(pre_sandbox);
current_sandbox_start();
auto_buf_flush(&session->response_body);
char *endptr;
long num = strtol(session->response_body.data, &endptr, 10);
if (endptr == session->response_body.data) {
printf("No digits were found\n");
} else if (*endptr != '\0' && *endptr != '\n') {
printf("Further characters after number: %s\n", endptr);
} else if ((errno == ERANGE && (num == LONG_MAX || num == LONG_MIN)) || (errno != 0 && num == 0)) {
perror("strtol");
} else {
session->param2 = num;
}
session->http_request.cursor = 0;
pre_sandbox->http = NULL;
pre_sandbox->state = SANDBOX_COMPLETE;
auto_buf_deinit(&session->response_body);
current_sandbox_set(NULL);
sandbox_free_linear_memory(pre_sandbox);
sandbox_free(pre_sandbox);
session->did_preprocessing = true;
const uint64_t end = __getcycles();
session->preprocessing_duration = end - start;
}
#endif

@ -40,14 +40,16 @@ declare -gr SANDBOX_ROUTE_FIELD=3
declare -gr SANDBOX_CPU_FREQ_FIELD=20
declare -gr SANDBOX_RESPONSE_CODE_FIELD=21
declare -gr SANDBOX_GUARANTEE_TYPE_FIELD=22
declare -gr SANDBOX_PAYLOAD_SIZE=23
# HTTP Session Perf Log Globals:
declare -ga HTTP_METRICS=(http_receive http_sent http_total)
declare -ga HTTP_METRICS=(http_receive http_sent http_total http_preprocess)
declare -gA HTTP_METRICS_FIELDS=(
[http_receive]=6
[http_sent]=7
[http_total]=8
[http_preprocess]=9
)
declare -gr HTTP_TENANT_NAME_FIELD=1
declare -gr HTTP_ROUTE_FIELD=2
declare -gr HTTP_CPU_FREQ_FIELD=9
declare -gr HTTP_CPU_FREQ_FIELD=10

@ -7,20 +7,11 @@ jq_admin_spec() {
jq ". + {\
\"name\": \"Admin\",\
\"port\": 55555,\
\"replenishment-period-us\": 0,\
\"max-budget-us\": 0,\
\"reservation-percentile\": 0,\
\"routes\": [\
.routes[] + {\
\"route\": \"/admin\",\
\"admissions-percentile\": 50,\
\"expected-execution-us\": 1000,\
\"relative-deadline-us\": 10000},\
\"route\": \"/admin\"},\
.routes[] + {\
\"route\": \"/terminator\",\
\"admissions-percentile\": 50,\
\"expected-execution-us\": 1000,\
\"relative-deadline-us\": 10000}\
\"route\": \"/terminator\"}\
]\
}" < "./template.json" > "./result_admin.json"
}
@ -55,6 +46,11 @@ generate_spec_json() {
local resp_content_type=${resp_content_types[$workload]}
local expected=${expected_execs[$workload]}
local deadline=${deadlines[$workload]}
local model_bias=${model_biases[$workload]}
local model_scale=${model_scales[$workload]}
local model_num_of_param=${model_num_of_params[$workload]}
local model_beta1=${model_beta1s[$workload]}
local model_beta2=${model_beta2s[$workload]}
jq_str+=".routes[] + {\
\"route\": \"/$route\",\
@ -62,6 +58,11 @@ generate_spec_json() {
\"admissions-percentile\": $ESTIMATIONS_PERCENTILE,\
\"expected-execution-us\": $expected,\
\"relative-deadline-us\": $deadline,\
\"model-bias\": $model_bias,\
\"model-scale\": $model_scale,\
\"model-num-of-param\": $model_num_of_param,\
\"model-beta1\": $model_beta1,\
\"model-beta2\": $model_beta2,\
\"http-resp-content-type\": \"$resp_content_type\"}"
if [ "$index" != $((${#t_routes[@]}-1)) ]; then

@ -22,6 +22,37 @@ if ! command -v hey > /dev/null; then
fi
fi
if ! command -v gnuplot > /dev/null; then
if [[ $(whoami) == "root" ]]; then
apt update
apt install -y gnuplot
else
sudo apt update
sudo apt install -y gnuplot
fi
fi
if ! command -v jq > /dev/null; then
if [[ $(whoami) == "root" ]]; then
apt update
apt install -y jq
else
sudo apt update
sudo apt install -y jq
fi
fi
if ! command -v htop > /dev/null; then
if [[ $(whoami) == "root" ]]; then
apt update
apt install -y htop
else
sudo apt update
sudo apt install -y htop
fi
fi
if ! command -v loadtest > /dev/null; then
if ! command -v npm > /dev/null; then
# if [[ $(whoami) == "root" ]]; then
@ -33,6 +64,7 @@ if ! command -v loadtest > /dev/null; then
# fi
# installs NVM (Node Version Manager)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
sleep 5
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
@ -63,37 +95,6 @@ if ! command -v loadtest > /dev/null; then
popd
fi
if ! command -v gnuplot > /dev/null; then
if [[ $(whoami) == "root" ]]; then
apt update
apt install -y gnuplot
else
sudo apt update
sudo apt install -y gnuplot
fi
fi
if ! command -v jq > /dev/null; then
if [[ $(whoami) == "root" ]]; then
apt update
apt install -y jq
else
sudo apt update
sudo apt install -y jq
fi
fi
if ! command -v htop > /dev/null; then
if [[ $(whoami) == "root" ]]; then
apt update
apt install -y htop
else
sudo apt update
sudo apt install -y htop
fi
fi
# For SOD:
# if ! command -v imagemagick > /dev/null; then
# if [ "$(whoami)" == "root" ]; then

@ -151,7 +151,7 @@ process_client_results_hey() {
for workload in "${workloads[@]}"; do
local t_id=${workload_tids[$workload]}
local deadline=${workload_deadlines[$workload]}
local deadline=${deadlines[$workload]}
local var=${workload_vars[$workload]}
# Some requests come back with an "Unsolicited response ..." See issue #185
@ -273,7 +273,8 @@ process_client_results_loadtest() {
# throughput=$(grep "Requests per second" "$results_directory/${workload}.dat" | tr -s ' ' | cut -d ' ' -f 14 | tail -n 1) # throughput of ALL
throughput=$(echo "$total/$duration" | bc)
goodput=$(echo "$all200/$duration" | bc)
printf "%s,%.1f\n" "$var" "$success_rate" >> "$results_directory/throughput_$t_id.csv"
# printf "%s,%.1f\n" "$var" "$success_rate" >> "$results_directory/throughput_$t_id.csv"
printf "%s,%s\n" "$throughput" "$goodput" >> "$results_directory/throughput_$t_id.csv"
# Generate Latency Data
min=$(awk '/Minimum latency/ {sum += $13; count++} END {print int(sum*1000/count)}' "$results_directory/${workload}.dat")
@ -338,7 +339,7 @@ process_server_results() {
mkdir -p "$results_directory/$workload"
local t_id=${workload_tids[$workload]}
local deadline=${workload_deadlines[$workload]}
local deadline=${deadlines[$workload]}
local var=${workload_vars[$workload]}
for metric in "${SANDBOX_METRICS[@]}"; do
@ -386,8 +387,13 @@ process_server_results() {
END{printf "'"$var"',%3.1f,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", (all200*100/NR), NR, ok, all200, total_failed, denied_any, denied_gtd, x_denied_any, x_denied_gtd, mis_dl_glob, mis_dl_local, mis_dl_wb, shed_glob, shed_local, misc, guaranteed, besteffort}
' < "$results_directory/$workload/total_sorted.csv" >> "$results_directory/success_$t_id.csv"
total=$(awk 'END {printf "%d", NR}' "$results_directory/$workload/total_sorted.csv")
ok=$(awk -F, '$2 == 200 && $1 <= '"$deadline"' {ok++} END {printf "%d", ok}' "$results_directory/$workload/total_sorted.csv")
throughput=$(echo "$total/$DURATION_sec" | bc)
goodput=$(echo "$ok/$DURATION_sec" | bc)
# Throughput is calculated on the client side, so ignore the below line
printf "%s,%d\n" "$var" "1" >> "$results_directory/throughput_$t_id.csv"
printf "%s,%s\n" "$throughput" "$goodput" >> "$results_directory/throughput_$t_id.csv"
# Generate Latency Data for csv
percentiles_table_row "$results_directory/$workload/total_sorted.csv" "$results_directory/latency_$t_id.csv" "$var"
@ -477,7 +483,7 @@ experiment_server_post() {
if [[ -f "$__run_sh__base_path/$SLEDGE_SANDBOX_PERF_LOG" ]]; then
mv "$__run_sh__base_path/$SLEDGE_SANDBOX_PERF_LOG" "$results_directory/$SERVER_LOG_FILE"
process_server_results "$results_directory" || return 1
rm "$results_directory/$SLEDGE_SANDBOX_PERF_LOG"
# rm "$results_directory/$SLEDGE_SANDBOX_PERF_LOG"
else
echo "Sandbox Perf Log was set, but $SERVER_LOG_FILE not found!"
fi
@ -487,7 +493,7 @@ experiment_server_post() {
if [[ -f "$__run_sh__base_path/$SLEDGE_HTTP_SESSION_PERF_LOG" ]]; then
mv "$__run_sh__base_path/$SLEDGE_HTTP_SESSION_PERF_LOG" "$results_directory/$SERVER_HTTP_LOG_FILE"
process_server_http_results "$results_directory" || return 1
rm "$results_directory/$SERVER_HTTP_LOG_FILE"
# rm "$results_directory/$SERVER_HTTP_LOG_FILE"
else
echo "HTTP Perf Log was set, but $SERVER_HTTP_LOG_FILE not found!"
fi

@ -12,13 +12,17 @@ declare -A wasm_paths=()
declare -A expected_execs=()
declare -A deadlines=()
declare -A resp_content_types=()
declare -A model_biases=()
declare -A model_scales=()
declare -A model_num_of_params=()
declare -A model_beta1s=()
declare -A model_beta2s=()
declare -A arg_opts_hey=()
declare -A arg_opts_lt=()
declare -A args=()
declare -A loads=()
declare -a workloads=()
declare -A workload_tids=()
declare -A workload_deadlines=()
declare -A workload_vars=()
assert_run_experiments_args() {
@ -82,6 +86,7 @@ run_init() {
reservations+=([$tenant]=$reservation)
local t_routes r_expected_execs r_deadlines r_arg_opts_hey r_arg_opts_lt r_args r_loads
local r_model_biases r_model_scales r_model_num_of_params r_model_beta1s r_model_beta2s
IFS=' ' read -r -a t_routes <<< "${ROUTES[$t_idx]}"
IFS=' ' read -r -a r_wasm_paths <<< "${WASM_PATHS[$t_idx]}"
@ -89,6 +94,12 @@ run_init() {
IFS=' ' read -r -a r_dl_to_exec_ratios <<< "${DEADLINE_TO_EXEC_RATIOs[$t_idx]}"
IFS=' ' read -r -a r_resp_content_types <<< "${RESP_CONTENT_TYPES[$t_idx]}"
IFS=' ' read -r -a r_model_biases <<< "${MODEL_BIASES[$t_idx]}"
IFS=' ' read -r -a r_model_scales <<< "${MODEL_SCALES[$t_idx]}"
IFS=' ' read -r -a r_model_num_of_params <<< "${MODEL_NUM_OF_PARAMS[$t_idx]}"
IFS=' ' read -r -a r_model_beta1s <<< "${MODEL_BETA1S[$t_idx]}"
IFS=' ' read -r -a r_model_beta2s <<< "${MODEL_BETA2S[$t_idx]}"
IFS=' ' read -r -a r_arg_opts_hey <<< "${ARG_OPTS_HEY[$t_idx]}"
IFS=' ' read -r -a r_arg_opts_lt <<< "${ARG_OPTS_LT[$t_idx]}"
IFS=' ' read -r -a r_args <<< "${ARGS[$t_idx]}"
@ -98,10 +109,14 @@ run_init() {
local route=${t_routes[$r_idx]}
local wasm_path=${r_wasm_paths[$r_idx]}
local expected=$(load_value "${r_expected_execs[$r_idx]}" "$var")
# local deadline=${r_deadlines[$r_idx]}
local dl_to_exec_ratio=${r_dl_to_exec_ratios[$r_idx]}
local deadline=$((expected*dl_to_exec_ratio/100))
local resp_content_type=${r_resp_content_types[$r_idx]}
local model_bias=${r_model_biases[$r_idx]}
local model_scale=${r_model_scales[$r_idx]}
local model_num_of_param=${r_model_num_of_params[$r_idx]}
local model_beta1=${r_model_beta1s[$r_idx]}
local model_beta2=${r_model_beta2s[$r_idx]}
local arg_opt_hey=${r_arg_opts_hey[$r_idx]}
local arg_opt_lt=${r_arg_opts_lt[$r_idx]}
local arg=$(load_value "${r_args[$r_idx]}" "$var")
@ -112,13 +127,17 @@ run_init() {
expected_execs+=([$workload]=$expected)
deadlines+=([$workload]=$deadline)
resp_content_types+=([$workload]=$resp_content_type)
model_biases+=([$workload]=$model_bias)
model_scales+=([$workload]=$model_scale)
model_num_of_params+=([$workload]=$model_num_of_param)
model_beta1s+=([$workload]=$model_beta1)
model_beta2s+=([$workload]=$model_beta2)
arg_opts_hey+=([$workload]=$arg_opt_hey)
arg_opts_lt+=([$workload]=$arg_opt_lt)
args+=([$workload]=$arg)
loads+=([$workload]=$load)
workloads+=("$workload")
workload_tids+=([$workload]=$tenant_id)
workload_deadlines+=([$workload]=$deadline)
workload_vars+=([$workload]=$var)
done
done

Loading…
Cancel
Save