From 362bf390474ae5fd4a5789db0a6a2644a8bc1c65 Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Thu, 7 Apr 2022 15:18:48 -0400 Subject: [PATCH 1/7] refactor: sandbox struct in req queue --- runtime/include/global_request_scheduler.h | 2 +- runtime/src/global_request_scheduler.c | 2 +- runtime/src/global_request_scheduler_minheap.c | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/runtime/include/global_request_scheduler.h b/runtime/include/global_request_scheduler.h index 8e363eb..437fccd 100644 --- a/runtime/include/global_request_scheduler.h +++ b/runtime/include/global_request_scheduler.h @@ -5,7 +5,7 @@ #include "sandbox_types.h" /* Returns pointer back if successful, null otherwise */ -typedef struct sandbox *(*global_request_scheduler_add_fn_t)(void *); +typedef struct sandbox *(*global_request_scheduler_add_fn_t)(struct sandbox *); typedef int (*global_request_scheduler_remove_fn_t)(struct sandbox **); typedef int (*global_request_scheduler_remove_if_earlier_fn_t)(struct sandbox **, uint64_t); typedef uint64_t (*global_request_scheduler_peek_fn_t)(void); diff --git a/runtime/src/global_request_scheduler.c b/runtime/src/global_request_scheduler.c index 459eef9..4362100 100644 --- a/runtime/src/global_request_scheduler.c +++ b/runtime/src/global_request_scheduler.c @@ -5,7 +5,7 @@ /* Default uninitialized implementations of the polymorphic interface */ noreturn static struct sandbox * -uninitialized_add(void *arg) +uninitialized_add(struct sandbox *arg) { panic("Global Request Scheduler Add was called before initialization\n"); } diff --git a/runtime/src/global_request_scheduler_minheap.c b/runtime/src/global_request_scheduler_minheap.c index 3d8facf..510cb15 100644 --- a/runtime/src/global_request_scheduler_minheap.c +++ b/runtime/src/global_request_scheduler_minheap.c @@ -15,16 +15,16 @@ static struct priority_queue *global_request_scheduler_minheap; * @returns pointer to request if added. Panics runtime otherwise */ static struct sandbox * -global_request_scheduler_minheap_add(void *sandbox_raw) +global_request_scheduler_minheap_add(struct sandbox *sandbox) { - assert(sandbox_raw); + assert(sandbox); assert(global_request_scheduler_minheap); 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_raw); + int return_code = priority_queue_enqueue(global_request_scheduler_minheap, sandbox); /* TODO: Propagate -1 to caller. Issue #91 */ if (return_code == -ENOSPC) panic("Request Queue is full\n"); - return (struct sandbox *)sandbox_raw; + return sandbox; } /** From 823c46f6f8ffa6f286daf9526dcf5c0eb53b5cd5 Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Thu, 7 Apr 2022 15:32:38 -0400 Subject: [PATCH 2/7] feat: return 429 if request queue full --- runtime/src/global_request_scheduler.c | 1 + runtime/src/global_request_scheduler_deque.c | 2 +- runtime/src/global_request_scheduler_minheap.c | 6 +++--- runtime/src/listener_thread.c | 10 ++++++++-- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/runtime/src/global_request_scheduler.c b/runtime/src/global_request_scheduler.c index 4362100..05ec3dd 100644 --- a/runtime/src/global_request_scheduler.c +++ b/runtime/src/global_request_scheduler.c @@ -43,6 +43,7 @@ global_request_scheduler_initialize(struct global_request_scheduler_config *conf /** * Adds a sandbox to the request scheduler * @param sandbox + * @returns pointer to sandbox if added. NULL otherwise */ struct sandbox * global_request_scheduler_add(struct sandbox *sandbox) diff --git a/runtime/src/global_request_scheduler_deque.c b/runtime/src/global_request_scheduler_deque.c index 628f57f..af151b4 100644 --- a/runtime/src/global_request_scheduler_deque.c +++ b/runtime/src/global_request_scheduler_deque.c @@ -12,7 +12,7 @@ static pthread_mutex_t global_request_scheduler_deque_mutex = PTHREAD_MUTEX_INIT /** * Pushes a sandbox to the global deque * @param sandbox_raw - * @returns pointer to request if added. NULL otherwise + * @returns pointer to sandbox if added. NULL otherwise */ static struct sandbox * global_request_scheduler_deque_add(struct sandbox *sandbox) diff --git a/runtime/src/global_request_scheduler_minheap.c b/runtime/src/global_request_scheduler_minheap.c index 510cb15..cee34f9 100644 --- a/runtime/src/global_request_scheduler_minheap.c +++ b/runtime/src/global_request_scheduler_minheap.c @@ -12,7 +12,7 @@ static struct priority_queue *global_request_scheduler_minheap; /** * Pushes a sandbox to the global deque * @param sandbox - * @returns pointer to request if added. Panics runtime otherwise + * @returns pointer to sandbox if added. NULL otherwise */ static struct sandbox * global_request_scheduler_minheap_add(struct sandbox *sandbox) @@ -22,8 +22,8 @@ global_request_scheduler_minheap_add(struct sandbox *sandbox) 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); - /* TODO: Propagate -1 to caller. Issue #91 */ - if (return_code == -ENOSPC) panic("Request Queue is full\n"); + + if (return_code != 0) return NULL; return sandbox; } diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 758c794..1a9d3ca 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -189,8 +189,14 @@ listener_thread_main(void *dummy) &sandbox->client_address); } - /* Add to the Global Sandbox Request Scheduler */ - global_request_scheduler_add(sandbox); + /* If the global request scheduler is full, return a 429 to the client */ + sandbox = global_request_scheduler_add(sandbox); + if (unlikely(sandbox == NULL)) { + client_socket_send_oneshot(sandbox->client_socket_descriptor, + http_header_build(429), http_header_len(429)); + client_socket_close(sandbox->client_socket_descriptor, + &sandbox->client_address); + } } /* while true */ } /* for loop */ From 69bdf5b49b68ef5ce8b62992964dee8a0495362b Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Thu, 7 Apr 2022 16:32:55 -0400 Subject: [PATCH 3/7] feat: grow local runqueue if full --- runtime/src/local_runqueue_minheap.c | 29 ++++++++++++++++++++++++++-- tests/fibonacci/bimodal/Makefile | 3 +++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/runtime/src/local_runqueue_minheap.c b/runtime/src/local_runqueue_minheap.c index ad3803f..8f3b7b9 100644 --- a/runtime/src/local_runqueue_minheap.c +++ b/runtime/src/local_runqueue_minheap.c @@ -25,6 +25,28 @@ local_runqueue_minheap_is_empty() return priority_queue_length_nolock(local_runqueue_minheap) == 0; } +/** + * Doubles capacity of local runqueue + */ +void +local_runqueue_minheap_grow(void) +{ + assert(local_runqueue_minheap != NULL); + + /* capacity is padded by 1 because idx 0 is padding */ + if (unlikely(local_runqueue_minheap->capacity == 1)) { + debuglog("Growing to 2\n"); + local_runqueue_minheap->capacity++; + } else { + local_runqueue_minheap->capacity = (local_runqueue_minheap->capacity - 1) * 2 + 1; + debuglog("Growing to %zu\n", local_runqueue_minheap->capacity); + } + + local_runqueue_minheap = (struct priority_queue *) + realloc(local_runqueue_minheap, + sizeof(struct priority_queue) + sizeof(void *) * (local_runqueue_minheap->capacity)); +} + /** * Adds a sandbox to the run queue * @param sandbox @@ -34,8 +56,11 @@ void local_runqueue_minheap_add(struct sandbox *sandbox) { int return_code = priority_queue_enqueue_nolock(local_runqueue_minheap, sandbox); - /* TODO: propagate RC to caller. Issue #92 */ - if (return_code == -ENOSPC) panic("Thread Runqueue is full!\n"); + if (unlikely(return_code == -ENOSPC)) { + local_runqueue_minheap_grow(); + return_code = priority_queue_enqueue_nolock(local_runqueue_minheap, sandbox); + if (unlikely(return_code == -ENOSPC)) panic("Thread Runqueue is full!\n"); + } } /** diff --git a/tests/fibonacci/bimodal/Makefile b/tests/fibonacci/bimodal/Makefile index 70b339f..fffbdd7 100644 --- a/tests/fibonacci/bimodal/Makefile +++ b/tests/fibonacci/bimodal/Makefile @@ -45,3 +45,6 @@ client-preempt: client-fib10-multi: hey -z ${DURATION_SEC}s -cpus 4 -c 100 -t 0 -o csv -m GET -d "10\n" "http://${HOSTNAME}:10010" + +client-fib40-multi: + hey -z ${DURATION_SEC}s -cpus 4 -c 100 -t 0 -o csv -m GET -d "40\n" "http://${HOSTNAME}:10040" From 08a0f03cd5470d365c5accb53caa18fd8d975371 Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Thu, 7 Apr 2022 16:52:37 -0400 Subject: [PATCH 4/7] refactor: change PQ capacity to exclude 0th elem --- runtime/include/priority_queue.h | 13 +++++-------- runtime/src/local_runqueue_minheap.c | 20 ++++++++++++-------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/runtime/include/priority_queue.h b/runtime/include/priority_queue.h index 0ca9e3d..3833f46 100644 --- a/runtime/include/priority_queue.h +++ b/runtime/include/priority_queue.h @@ -64,8 +64,8 @@ priority_queue_append(struct priority_queue *priority_queue, void *new_item) int rc; - if (unlikely(priority_queue->size + 1 > priority_queue->capacity)) panic("PQ overflow"); - if (unlikely(priority_queue->size + 1 == priority_queue->capacity)) goto err_enospc; + if (unlikely(priority_queue->size > priority_queue->capacity)) panic("PQ overflow"); + if (unlikely(priority_queue->size == priority_queue->capacity)) goto err_enospc; priority_queue->items[++priority_queue->size] = new_item; rc = 0; @@ -271,16 +271,13 @@ priority_queue_initialize(size_t capacity, bool use_lock, priority_queue_get_pri assert(get_priority_fn != NULL); /* Add one to capacity because this data structure ignores the element at 0 */ - size_t one_based_capacity = capacity + 1; - - struct priority_queue *priority_queue = (struct priority_queue *) - calloc(1, sizeof(struct priority_queue) + sizeof(void *) * one_based_capacity); - + struct priority_queue *priority_queue = (struct priority_queue *)calloc(1, sizeof(struct priority_queue) + + sizeof(void *) * (capacity + 1)); /* We're assuming a min-heap implementation, so set to larget possible value */ priority_queue_update_highest_priority(priority_queue, ULONG_MAX); priority_queue->size = 0; - priority_queue->capacity = one_based_capacity; // Add one because we skip element 0 + priority_queue->capacity = capacity; priority_queue->get_priority_fn = get_priority_fn; priority_queue->use_lock = use_lock; diff --git a/runtime/src/local_runqueue_minheap.c b/runtime/src/local_runqueue_minheap.c index 8f3b7b9..596303a 100644 --- a/runtime/src/local_runqueue_minheap.c +++ b/runtime/src/local_runqueue_minheap.c @@ -13,6 +13,8 @@ #include "sandbox_functions.h" #include "runtime.h" +#define INITIAL_LOCAL_RUNQUEUE_MINHEAP_CAPACITY 256 + thread_local static struct priority_queue *local_runqueue_minheap; /** @@ -33,18 +35,19 @@ local_runqueue_minheap_grow(void) { assert(local_runqueue_minheap != NULL); - /* capacity is padded by 1 because idx 0 is padding */ - if (unlikely(local_runqueue_minheap->capacity == 1)) { - debuglog("Growing to 2\n"); + if (unlikely(local_runqueue_minheap->capacity == 0)) { local_runqueue_minheap->capacity++; + debuglog("Growing to 1\n"); } else { - local_runqueue_minheap->capacity = (local_runqueue_minheap->capacity - 1) * 2 + 1; + local_runqueue_minheap->capacity *= 2; debuglog("Growing to %zu\n", local_runqueue_minheap->capacity); } - local_runqueue_minheap = (struct priority_queue *) - realloc(local_runqueue_minheap, - sizeof(struct priority_queue) + sizeof(void *) * (local_runqueue_minheap->capacity)); + /* capacity is padded by 1 because idx 0 is unused */ + local_runqueue_minheap = (struct priority_queue *)realloc(local_runqueue_minheap, + sizeof(struct priority_queue) + + sizeof(void *) * local_runqueue_minheap->capacity + + 1); } /** @@ -103,7 +106,8 @@ void local_runqueue_minheap_initialize() { /* Initialize local state */ - local_runqueue_minheap = priority_queue_initialize(256, false, sandbox_get_priority); + local_runqueue_minheap = priority_queue_initialize(INITIAL_LOCAL_RUNQUEUE_MINHEAP_CAPACITY, false, + sandbox_get_priority); /* Register Function Pointers for Abstract Scheduling API */ struct local_runqueue_config config = { .add_fn = local_runqueue_minheap_add, From 8a170e1a6446c444c84baa3ed97e63b802f05f81 Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Thu, 7 Apr 2022 17:04:31 -0400 Subject: [PATCH 5/7] refactor: Move grow logic into PQ API --- runtime/include/priority_queue.h | 23 +++++++++++++++++++++++ runtime/src/local_runqueue_minheap.c | 27 ++------------------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/runtime/include/priority_queue.h b/runtime/include/priority_queue.h index 3833f46..79aa992 100644 --- a/runtime/include/priority_queue.h +++ b/runtime/include/priority_queue.h @@ -286,6 +286,29 @@ priority_queue_initialize(size_t capacity, bool use_lock, priority_queue_get_pri return priority_queue; } +/** + * Double capacity of priority queue + * @param priority_queue to resize + * @returns pointer to PR. This may have been moved by realloc! + */ +static inline struct priority_queue * +priority_queue_grow(struct priority_queue *priority_queue) +{ + assert(priority_queue != NULL); + + if (unlikely(priority_queue->capacity == 0)) { + priority_queue->capacity++; + debuglog("Growing to 1\n"); + } else { + priority_queue->capacity *= 2; + debuglog("Growing to %zu\n", priority_queue->capacity); + } + + /* capacity is padded by 1 because idx 0 is unused */ + return (struct priority_queue *)realloc(priority_queue, sizeof(struct priority_queue) + + sizeof(void *) * (priority_queue->capacity + 1)); +} + /** * Free the Priority Queue Data structure * @param priority_queue the priority_queue to initialize diff --git a/runtime/src/local_runqueue_minheap.c b/runtime/src/local_runqueue_minheap.c index 596303a..6db81f7 100644 --- a/runtime/src/local_runqueue_minheap.c +++ b/runtime/src/local_runqueue_minheap.c @@ -27,29 +27,6 @@ local_runqueue_minheap_is_empty() return priority_queue_length_nolock(local_runqueue_minheap) == 0; } -/** - * Doubles capacity of local runqueue - */ -void -local_runqueue_minheap_grow(void) -{ - assert(local_runqueue_minheap != NULL); - - if (unlikely(local_runqueue_minheap->capacity == 0)) { - local_runqueue_minheap->capacity++; - debuglog("Growing to 1\n"); - } else { - local_runqueue_minheap->capacity *= 2; - debuglog("Growing to %zu\n", local_runqueue_minheap->capacity); - } - - /* capacity is padded by 1 because idx 0 is unused */ - local_runqueue_minheap = (struct priority_queue *)realloc(local_runqueue_minheap, - sizeof(struct priority_queue) - + sizeof(void *) * local_runqueue_minheap->capacity - + 1); -} - /** * Adds a sandbox to the run queue * @param sandbox @@ -60,8 +37,8 @@ local_runqueue_minheap_add(struct sandbox *sandbox) { int return_code = priority_queue_enqueue_nolock(local_runqueue_minheap, sandbox); if (unlikely(return_code == -ENOSPC)) { - local_runqueue_minheap_grow(); - return_code = priority_queue_enqueue_nolock(local_runqueue_minheap, sandbox); + local_runqueue_minheap = priority_queue_grow(local_runqueue_minheap); + return_code = priority_queue_enqueue_nolock(local_runqueue_minheap, sandbox); if (unlikely(return_code == -ENOSPC)) panic("Thread Runqueue is full!\n"); } } From 3b929638685f938f636995a9a06202126ca27b2d Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Thu, 7 Apr 2022 17:25:27 -0400 Subject: [PATCH 6/7] refactor: priority_queue_grow_nolock --- runtime/include/priority_queue.h | 5 ++++- runtime/src/local_runqueue_minheap.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/runtime/include/priority_queue.h b/runtime/include/priority_queue.h index 79aa992..01d3d17 100644 --- a/runtime/include/priority_queue.h +++ b/runtime/include/priority_queue.h @@ -288,11 +288,14 @@ priority_queue_initialize(size_t capacity, bool use_lock, priority_queue_get_pri /** * Double capacity of priority queue + * Note: currently there is no equivalent call for PQs that are not thread-local and need to be locked because it is + * unclear if the fact that the lock is a member in the struct that might be moved by realloc breaks the guarantees of + * the lock. * @param priority_queue to resize * @returns pointer to PR. This may have been moved by realloc! */ static inline struct priority_queue * -priority_queue_grow(struct priority_queue *priority_queue) +priority_queue_grow_nolock(struct priority_queue *priority_queue) { assert(priority_queue != NULL); diff --git a/runtime/src/local_runqueue_minheap.c b/runtime/src/local_runqueue_minheap.c index 6db81f7..b75bbc9 100644 --- a/runtime/src/local_runqueue_minheap.c +++ b/runtime/src/local_runqueue_minheap.c @@ -37,7 +37,7 @@ local_runqueue_minheap_add(struct sandbox *sandbox) { int return_code = priority_queue_enqueue_nolock(local_runqueue_minheap, sandbox); if (unlikely(return_code == -ENOSPC)) { - local_runqueue_minheap = priority_queue_grow(local_runqueue_minheap); + local_runqueue_minheap = priority_queue_grow_nolock(local_runqueue_minheap); return_code = priority_queue_enqueue_nolock(local_runqueue_minheap, sandbox); if (unlikely(return_code == -ENOSPC)) panic("Thread Runqueue is full!\n"); } From 3aaa7737df6fa466849bf39a02e606f8bce37f66 Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Tue, 12 Apr 2022 15:11:16 -0400 Subject: [PATCH 7/7] fix: handle NULL from realloc --- runtime/include/priority_queue.h | 2 +- runtime/src/local_runqueue_minheap.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/runtime/include/priority_queue.h b/runtime/include/priority_queue.h index 01d3d17..ae92366 100644 --- a/runtime/include/priority_queue.h +++ b/runtime/include/priority_queue.h @@ -292,7 +292,7 @@ priority_queue_initialize(size_t capacity, bool use_lock, priority_queue_get_pri * unclear if the fact that the lock is a member in the struct that might be moved by realloc breaks the guarantees of * the lock. * @param priority_queue to resize - * @returns pointer to PR. This may have been moved by realloc! + * @returns pointer to PR or NULL if realloc fails. This may have been moved by realloc! */ static inline struct priority_queue * priority_queue_grow_nolock(struct priority_queue *priority_queue) diff --git a/runtime/src/local_runqueue_minheap.c b/runtime/src/local_runqueue_minheap.c index b75bbc9..8ba3c29 100644 --- a/runtime/src/local_runqueue_minheap.c +++ b/runtime/src/local_runqueue_minheap.c @@ -37,7 +37,9 @@ local_runqueue_minheap_add(struct sandbox *sandbox) { int return_code = priority_queue_enqueue_nolock(local_runqueue_minheap, sandbox); if (unlikely(return_code == -ENOSPC)) { - local_runqueue_minheap = priority_queue_grow_nolock(local_runqueue_minheap); + 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"); }