From f43ac71d26ad95a79e82bc7a345d5f014affbffa Mon Sep 17 00:00:00 2001 From: Andrey Borodin Date: Sun, 1 Dec 2019 22:27:03 +0500 Subject: [PATCH] Optimize clocks --- test/machinarium/test_sleep.c | 30 ++++++++ test/odyssey_test.c | 2 + third_party/machinarium/sources/clock.c | 97 ++++++++++++++++--------- 3 files changed, 95 insertions(+), 34 deletions(-) diff --git a/test/machinarium/test_sleep.c b/test/machinarium/test_sleep.c index 01ddb3243..fb1d615ed 100644 --- a/test/machinarium/test_sleep.c +++ b/test/machinarium/test_sleep.c @@ -25,3 +25,33 @@ machinarium_test_sleep(void) machinarium_free(); } + +static void +coroutine_random_sleep(void *arg) +{ + (void)arg; + long int duration = machine_lrand48(); + machine_sleep(duration & 0xFF); + machine_stop(); +} + +void +machinarium_test_sleep_random(void) +{ + machinarium_init(); + + int n = 100; + int id[n]; + for (int i = 0 ; i < n; i++) { + id[i] = machine_create("test", coroutine_random_sleep, NULL); + test(id[i] != -1); + } + + for (int i = 0 ; i < n; i++) { + int rc; + rc = machine_wait(id[i]); + test(rc != -1); + } + + machinarium_free(); +} diff --git a/test/odyssey_test.c b/test/odyssey_test.c index cf50f009d..d5ca2eed8 100644 --- a/test/odyssey_test.c +++ b/test/odyssey_test.c @@ -21,6 +21,7 @@ extern void machinarium_test_create1(void); extern void machinarium_test_config(void); extern void machinarium_test_context_switch(void); extern void machinarium_test_sleep(void); +extern void machinarium_test_sleep_random(void); extern void machinarium_test_sleep_yield(void); extern void machinarium_test_sleep_cancel0(void); extern void machinarium_test_join(void); @@ -84,6 +85,7 @@ int main(int argc, char *argv[]) odyssey_test(machinarium_test_config); odyssey_test(machinarium_test_context_switch); odyssey_test(machinarium_test_sleep); + odyssey_test(machinarium_test_sleep_random); odyssey_test(machinarium_test_sleep_yield); odyssey_test(machinarium_test_sleep_cancel0); odyssey_test(machinarium_test_join); diff --git a/third_party/machinarium/sources/clock.c b/third_party/machinarium/sources/clock.c index 9aae34a72..5b3957362 100644 --- a/third_party/machinarium/sources/clock.c +++ b/third_party/machinarium/sources/clock.c @@ -9,14 +9,15 @@ #include static int -mm_clock_cmp(const void *a_ptr, const void *b_ptr) +mm_clock_cmp(mm_timer_t *a, mm_timer_t *b) { - mm_timer_t *a = *(mm_timer_t**)a_ptr; - mm_timer_t *b = *(mm_timer_t**)b_ptr; if (a->timeout == b->timeout) { + if (a->seq == b->seq) { + assert(a == b); + return 0; + } return (a->seq > b->seq) ? 1 : -1; - } else - if (a->timeout > b->timeout) { + } else if (a->timeout > b->timeout) { return 1; } return -1; @@ -39,45 +40,81 @@ void mm_clock_free(mm_clock_t *clock) mm_buf_free(&clock->timers); } +// Binary search routine for timer in sorted array. +// We expect that there is at most only one occurrence of timer in list. +// If there is not timer in list, we must return first index greater than timer. +static int mm_clock_get_insert_position(mm_timer_t **list, int count, mm_timer_t *timer) +{ + int low = 0, high = count; + while (low < high) + { + int med = low + (high - low) / 2; + int cmp = mm_clock_cmp(timer, list[med]); + if (cmp == 0) + return med; + if (cmp > 0) { + low = med + 1; + } else { + high = med; + } + } + return low; +} + +static int mm_clock_list_is_sorted(mm_timer_t **list, int count) +{ + for (int i = 1; i < count; i++) { + if (mm_clock_cmp(list[i-1], list[i]) >= 0) { + return 0; + } + } + return 1; +} + int mm_clock_timer_add(mm_clock_t *clock, mm_timer_t *timer) { - int count = clock->timers_count + 1; + int count = clock->timers_count; int rc; - rc = mm_buf_ensure(&clock->timers, count * sizeof(mm_timer_t*)); + rc = mm_buf_ensure(&clock->timers, sizeof(mm_timer_t*)); if (rc == -1) return -1; mm_timer_t **list; list = (mm_timer_t**)clock->timers.start; - list[count - 1] = timer; mm_buf_advance(&clock->timers, sizeof(mm_timer_t*)); timer->seq = clock->timers_seq++; timer->timeout = clock->time_ms + timer->interval; timer->active = 1; timer->clock = clock; - qsort(list, count, sizeof(mm_timer_t*), - mm_clock_cmp); - clock->timers_count = count; + int insert_position = mm_clock_get_insert_position(list, count, timer); + // We are last, or insert position is after us + assert((insert_position == count) || mm_clock_cmp(list[insert_position], timer) > 0); + memmove(list + insert_position + 1, list + insert_position, sizeof(mm_timer_t*) * (count - insert_position)); + list[insert_position] = timer; + clock->timers_count = count + 1; + assert(mm_clock_list_is_sorted(list, clock->timers_count)); return 0; } int mm_clock_timer_del(mm_clock_t *clock, mm_timer_t *timer) { - if (! timer->active) + if (!timer->active) return -1; assert(clock->timers_count >= 1); mm_timer_t **list; list = (mm_timer_t**)clock->timers.start; - int i = 0; - int j = 0; + int i = mm_clock_get_insert_position(list, clock->timers_count, timer); + // We should find timer + assert(list[i] == timer); for (; i < clock->timers_count; i++) { - if (list[i] == timer) + if (list[i] != timer) continue; - list[j] = list[i]; - j++; + memmove(list + i, list + i + 1, sizeof(mm_timer_t*) * (clock->timers_count - i - 1)); + clock->timers.pos -= sizeof(mm_timer_t*); + clock->timers_count -= 1; + break; } + assert(mm_clock_list_is_sorted(list, clock->timers_count)); timer->active = 0; - clock->timers.pos -= sizeof(mm_timer_t*); - clock->timers_count -= 1; return 0; } @@ -86,8 +123,8 @@ mm_clock_timer_min(mm_clock_t *clock) { if (clock->timers_count == 0) return NULL; - mm_timer_t **list; - list = (mm_timer_t**)clock->timers.start; + mm_timer_t**list; + list = (mm_timer_t**) clock->timers.start; return list[0]; } @@ -95,21 +132,19 @@ int mm_clock_step(mm_clock_t *clock) { if (clock->timers_count == 0) return 0; - mm_timer_t **list; - list = (mm_timer_t**)clock->timers.start; + mm_timer_t**list; + list = (mm_timer_t**) clock->timers.start; int timers_hit = 0; int i = 0; - int j = 0; for (; i < clock->timers_count; i++) { - mm_timer_t *timer = list[i]; + mm_timer_t*timer = list[i]; if (timer->timeout > clock->time_ms) break; timer->callback(timer); timer->active = 0; timers_hit++; - list[i] = NULL; } - if (! timers_hit) + if (!timers_hit) return 0; int timers_left = clock->timers_count - timers_hit; if (timers_left == 0) { @@ -117,13 +152,7 @@ int mm_clock_step(mm_clock_t *clock) clock->timers_count = 0; return timers_hit; } - i = 0; - for (; i < clock->timers_count; i++) { - if (list[i] == NULL) - continue; - list[j] = list[i]; - j++; - } + memmove(list, list + timers_hit, sizeof(mm_timer_t*) * timers_left); clock->timers.pos -= sizeof(mm_timer_t*) * timers_hit; clock->timers_count -= timers_hit; return timers_hit;