From 587e2ab3548b973e1560ea3fa5dc66249ffff3ed Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Tue, 11 Aug 2020 21:04:44 -0400 Subject: [PATCH] feat: Only dequeue request if actually earlier --- runtime/include/global_request_scheduler.h | 11 ++++++--- runtime/include/priority_queue.h | 9 ++++---- runtime/src/global_request_scheduler.c | 14 +++++++++++ runtime/src/global_request_scheduler_deque.c | 15 ++++++++++-- .../src/global_request_scheduler_minheap.c | 23 ++++++++++++++++--- runtime/src/local_runqueue_minheap.c | 11 +++++++-- runtime/src/priority_queue.c | 15 +++++++++++- 7 files changed, 83 insertions(+), 15 deletions(-) diff --git a/runtime/include/global_request_scheduler.h b/runtime/include/global_request_scheduler.h index a7cc14e..b3ec0c7 100644 --- a/runtime/include/global_request_scheduler.h +++ b/runtime/include/global_request_scheduler.h @@ -1,20 +1,25 @@ #pragma once +#include + #include "sandbox_request.h" /* Returns pointer back if successful, null otherwise */ typedef struct sandbox_request *(*global_request_scheduler_add_fn_t)(void *); typedef int (*global_request_scheduler_remove_fn_t)(struct sandbox_request **); +typedef int (*global_request_scheduler_remove_if_earlier_fn_t)(struct sandbox_request **, uint64_t); typedef uint64_t (*global_request_scheduler_peek_fn_t)(void); struct global_request_scheduler_config { - global_request_scheduler_add_fn_t add_fn; - global_request_scheduler_remove_fn_t remove_fn; - global_request_scheduler_peek_fn_t peek_fn; + global_request_scheduler_add_fn_t add_fn; + global_request_scheduler_remove_fn_t remove_fn; + global_request_scheduler_remove_if_earlier_fn_t remove_if_earlier_fn; + global_request_scheduler_peek_fn_t peek_fn; }; void global_request_scheduler_initialize(struct global_request_scheduler_config *config); struct sandbox_request *global_request_scheduler_add(struct sandbox_request *); int global_request_scheduler_remove(struct sandbox_request **); +int global_request_scheduler_remove_if_earlier(struct sandbox_request **, uint64_t targed_deadline); uint64_t global_request_scheduler_peek(); diff --git a/runtime/include/priority_queue.h b/runtime/include/priority_queue.h index bfcd24c..f0b1791 100644 --- a/runtime/include/priority_queue.h +++ b/runtime/include/priority_queue.h @@ -37,10 +37,11 @@ priority_queue_is_empty(struct priority_queue *self) return self->highest_priority == ULONG_MAX; } -void priority_queue_initialize(struct priority_queue *self, priority_queue_get_priority_fn_t get_priority_fn); -int priority_queue_enqueue(struct priority_queue *self, void *value); -int priority_queue_dequeue(struct priority_queue *self, void **dequeued_element); -int priority_queue_length(struct priority_queue *self); +void priority_queue_initialize(struct priority_queue *self, priority_queue_get_priority_fn_t get_priority_fn); +int priority_queue_enqueue(struct priority_queue *self, void *value); +int priority_queue_dequeue(struct priority_queue *self, void **dequeued_element); +int priority_queue_dequeue_if_earlier(struct priority_queue *self, void **dequeued_element, uint64_t target_deadline); +int priority_queue_length(struct priority_queue *self); uint64_t priority_queue_peek(struct priority_queue *self); int priority_queue_delete(struct priority_queue *self, void *value); int priority_queue_top(struct priority_queue *self, void **dequeued_element); diff --git a/runtime/src/global_request_scheduler.c b/runtime/src/global_request_scheduler.c index b0b95e9..e5eeac4 100644 --- a/runtime/src/global_request_scheduler.c +++ b/runtime/src/global_request_scheduler.c @@ -61,6 +61,20 @@ global_request_scheduler_remove(struct sandbox_request **removed_sandbox) return global_request_scheduler.remove_fn(removed_sandbox); } +/** + * Removes a sandbox request according to the scheduling policy of the variant + * @param removed_sandbox where to write the adddress of the removed sandbox + * @param target_deadline the deadline that must be validated before dequeuing + * @returns 0 if successfully returned a sandbox request, -ENOENT if empty or if no element meets target_deadline, + * -EAGAIN if atomic operation unsuccessful + */ +int +global_request_scheduler_remove_if_earlier(struct sandbox_request **removed_sandbox, uint64_t target_deadline) +{ + assert(removed_sandbox != NULL); + return global_request_scheduler.remove_if_earlier_fn(removed_sandbox, target_deadline); +} + /** * Peeks at the priority of the highest priority sandbox request * @returns highest priority diff --git a/runtime/src/global_request_scheduler_deque.c b/runtime/src/global_request_scheduler_deque.c index ec718fc..c2edaaf 100644 --- a/runtime/src/global_request_scheduler_deque.c +++ b/runtime/src/global_request_scheduler_deque.c @@ -36,6 +36,14 @@ global_request_scheduler_deque_remove(struct sandbox_request **removed_sandbox_r return deque_steal_sandbox(global_request_scheduler_deque, removed_sandbox_request); } +static int +global_request_scheduler_deque_remove_if_earlier(struct sandbox_request **removed_sandbox_request, + uint64_t target_deadline) +{ + panic("Deque variant does not support this call\n"); + return -1; +} + void global_request_scheduler_deque_initialize() { @@ -46,8 +54,11 @@ global_request_scheduler_deque_initialize() deque_init_sandbox(global_request_scheduler_deque, RUNTIME_MAX_SANDBOX_REQUEST_COUNT); /* Register Function Pointers for Abstract Scheduling API */ - struct global_request_scheduler_config config = { .add_fn = global_request_scheduler_deque_add, - .remove_fn = global_request_scheduler_deque_remove }; + struct global_request_scheduler_config config = { + .add_fn = global_request_scheduler_deque_add, + .remove_fn = global_request_scheduler_deque_remove, + .remove_if_earlier_fn = global_request_scheduler_deque_remove_if_earlier + }; global_request_scheduler_initialize(&config); } diff --git a/runtime/src/global_request_scheduler_minheap.c b/runtime/src/global_request_scheduler_minheap.c index 5ea5d75..6be64e9 100644 --- a/runtime/src/global_request_scheduler_minheap.c +++ b/runtime/src/global_request_scheduler_minheap.c @@ -37,6 +37,20 @@ global_request_scheduler_minheap_remove(struct sandbox_request **removed_sandbox return priority_queue_dequeue(&global_request_scheduler_minheap, (void **)removed_sandbox_request); } +/** + * @param removed_sandbox_request pointer to set to removed sandbox request + * @param target_deadline the deadline that the request must be earlier than to dequeue + * @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_request **removed_sandbox_request, + uint64_t target_deadline) +{ + assert(!software_interrupt_is_enabled()); + return priority_queue_dequeue_if_earlier(&global_request_scheduler_minheap, (void **)removed_sandbox_request, + target_deadline); +} + /** * Peek at the priority of the highest priority task without having to take the lock * Because this is a min-heap PQ, the highest priority is the lowest 64-bit integer @@ -65,9 +79,12 @@ global_request_scheduler_minheap_initialize() { priority_queue_initialize(&global_request_scheduler_minheap, sandbox_request_get_priority_fn); - struct global_request_scheduler_config config = { .add_fn = global_request_scheduler_minheap_add, - .remove_fn = global_request_scheduler_minheap_remove, - .peek_fn = global_request_scheduler_minheap_peek }; + struct global_request_scheduler_config config = { + .add_fn = global_request_scheduler_minheap_add, + .remove_fn = global_request_scheduler_minheap_remove, + .remove_if_earlier_fn = global_request_scheduler_minheap_remove_if_earlier, + .peek_fn = global_request_scheduler_minheap_peek + }; global_request_scheduler_initialize(&config); } diff --git a/runtime/src/local_runqueue_minheap.c b/runtime/src/local_runqueue_minheap.c index 364bf11..057da30 100644 --- a/runtime/src/local_runqueue_minheap.c +++ b/runtime/src/local_runqueue_minheap.c @@ -142,10 +142,17 @@ local_runqueue_minheap_preempt(ucontext_t *user_context) current_sandbox->request_arrival_timestamp, local_deadline, global_deadline); #endif - int return_code = global_request_scheduler_remove(&sandbox_request); + int return_code = global_request_scheduler_remove_if_earlier(&sandbox_request, local_deadline); /* If we were unable to get a sandbox_request, exit */ - if (return_code != 0) goto done; + if (return_code != 0) { +#ifdef LOG_PREEMPTION + debuglog("Preemption aborted. Another thread took the request\n"); +#endif + goto done; + } + + assert(sandbox_request->absolute_deadline < local_deadline); #ifdef LOG_PREEMPTION debuglog("Preempted %lu for %lu\n", local_deadline, sandbox_request->absolute_deadline); diff --git a/runtime/src/priority_queue.c b/runtime/src/priority_queue.c index 96d1269..8d03255 100644 --- a/runtime/src/priority_queue.c +++ b/runtime/src/priority_queue.c @@ -244,6 +244,18 @@ priority_queue_delete(struct priority_queue *self, void *value) */ int priority_queue_dequeue(struct priority_queue *self, void **dequeued_element) +{ + return priority_queue_dequeue_if_earlier(self, dequeued_element, UINT64_MAX); +} + +/** + * @param self - the priority queue we want to add to + * @param dequeued_element a pointer to set to the dequeued element + * @param target_deadline the deadline that the request must be earlier than in order to dequeue + * @returns RC 0 if successfully set dequeued_element, -ENOENT if empty or if none meet target_deadline + */ +int +priority_queue_dequeue_if_earlier(struct priority_queue *self, void **dequeued_element, uint64_t target_deadline) { assert(self != NULL); assert(dequeued_element != NULL); @@ -253,7 +265,8 @@ priority_queue_dequeue(struct priority_queue *self, void **dequeued_element) LOCK_LOCK(&self->lock); - if (priority_queue_is_empty_locked(self)) goto err_enoent; + /* If the dequeue is not higher priority (earlier timestamp) than targed_deadline, return immediately */ + if (priority_queue_is_empty_locked(self) || self->highest_priority >= target_deadline) goto err_enoent; *dequeued_element = self->items[1]; self->items[1] = self->items[--self->first_free];