diff --git a/runtime/include/module.h b/runtime/include/module.h index a2dae85..2a13483 100644 --- a/runtime/include/module.h +++ b/runtime/include/module.h @@ -5,6 +5,7 @@ #include "http.h" #include "panic.h" +#include "perf_window.h" #include "software_interrupt.h" #include "types.h" @@ -37,6 +38,7 @@ struct module { struct indirect_table_entry indirect_table[INDIRECT_TABLE_SIZE]; struct sockaddr_in socket_address; int socket_descriptor; + struct perf_window perf_window; int port; /* diff --git a/runtime/include/perf_window.h b/runtime/include/perf_window.h new file mode 100644 index 0000000..b155774 --- /dev/null +++ b/runtime/include/perf_window.h @@ -0,0 +1,96 @@ +#pragma once + +#include +#include + +#define PERF_WINDOW_BUFFER_SIZE 10 + +struct perf_window { + uint64_t buffer[PERF_WINDOW_BUFFER_SIZE]; + uint64_t count; + ck_spinlock_fas_t lock; + double mean; +}; + +/** + * Iterates through the values in the buffer and updates the mean + * Not intended to be called directly! + * @param self + */ +static inline void +perf_window_update_mean(struct perf_window *self) +{ + assert(self != NULL); + assert(ck_spinlock_fas_locked(&self->lock)); + + uint64_t limit = self->count; + if (limit > PERF_WINDOW_BUFFER_SIZE) { limit = PERF_WINDOW_BUFFER_SIZE; } + + uint64_t sum = 0; + for (uint64_t i = 0; i < limit; i++) sum += self->buffer[i]; + + self->mean = (double)(sum) / limit; +}; + +/** + * Iterates through the values in the buffer and updates the mean + * Not intended to be called directly! + * @param self + */ +static inline void +perf_window_initialize(struct perf_window *self) +{ + assert(self != NULL); + + ck_spinlock_fas_init(&self->lock); + self->count = 0; + self->mean = 0; + memset(&self->buffer, 0, sizeof(uint64_t) * PERF_WINDOW_BUFFER_SIZE); +} + +/** + * Iterates through the values in the buffer and updates the mean + * Not intended to be called directly! + * @param self + * @param value + */ +static inline void +perf_window_add(struct perf_window *self, uint64_t value) +{ + assert(self != NULL); + + + /* A successful invocation should run for a non-zero amount of time */ + assert(value > 0); + + ck_spinlock_fas_lock(&self->lock); + self->buffer[self->count++ % PERF_WINDOW_BUFFER_SIZE] = value; + perf_window_update_mean(self); + ck_spinlock_fas_unlock(&self->lock); +} + +/** + * Returns mean perf value across all executions + * @returns mean or -1 if buffer is empty + */ +static inline double +perf_window_get_mean(struct perf_window *self) +{ + assert(self != NULL); + + if (self->count == 0) return -1; + + return self->mean; +} + +/** + * Returns the total count of executions + * @returns total count + */ +static inline uint64_t +perf_window_get_count(struct perf_window *self) +{ + assert(self != NULL); + + return self->count; +} diff --git a/runtime/src/module.c b/runtime/src/module.c index 41505ff..adc0a44 100644 --- a/runtime/src/module.c +++ b/runtime/src/module.c @@ -201,6 +201,9 @@ module_new(char *name, char *path, int32_t argument_count, uint32_t stack_size, /* Add the module to the in-memory module DB */ module_database_add(module); + /* Initialize Perf Window */ + perf_window_initialize(&module->perf_window); + /* Start listening for requests */ module_listen(module);