From c6adf304bde0caea94cd75a8469596bf47e82d21 Mon Sep 17 00:00:00 2001 From: Maciej Szwed Date: Wed, 2 Sep 2020 10:00:12 +0200 Subject: [PATCH] event: governor implementation Signed-off-by: Maciej Szwed Change-Id: I9aaa84261144145933d227976a5f89dc89732267 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/4028 Reviewed-by: Aleksey Marchuk Reviewed-by: Tomasz Zawadzki Reviewed-by: Jim Harris Tested-by: Tomasz Zawadzki --- include/spdk_internal/event.h | 92 +++++++++++++++++++++++++++++++-- lib/event/reactor.c | 96 +++++++++++++++++++++++++++++++++-- 2 files changed, 182 insertions(+), 6 deletions(-) diff --git a/include/spdk_internal/event.h b/include/spdk_internal/event.h index 1f32db439..474e0ccd3 100644 --- a/include/spdk_internal/event.h +++ b/include/spdk_internal/event.h @@ -175,6 +175,91 @@ void spdk_subsystem_config_json(struct spdk_json_write_ctx *w, struct spdk_subsy void spdk_rpc_initialize(const char *listen_addr); void spdk_rpc_finish(void); +struct spdk_governor_capabilities { + bool freq_change; + bool freq_getset; + bool freq_up; + bool freq_down; + bool freq_max; + bool freq_min; + bool turbo_set; + bool turbo_available; + bool priority; +}; + +/** Cores governor */ +struct spdk_governor { + char *name; + + /* freqs - the buffer array to save the frequencies; num - the number of frequencies to get; return - the number of available frequencies */ + uint32_t (*get_core_freqs)(uint32_t lcore_id, uint32_t *freqs, uint32_t num); + + /* return - current frequency */ + uint32_t (*get_core_curr_freq)(uint32_t lcore_id); + + /** + * freq_index - index of available frequencies returned from get_core_freqs call + * + * return + * - 1 on success with frequency changed. + * - 0 on success without frequency changed. + * - Negative on error. + */ + int (*set_core_freq)(uint32_t lcore_id, uint32_t freq_index); + int (*core_freq_up)(uint32_t lcore_id); + int (*core_freq_down)(uint32_t lcore_id); + int (*set_core_freq_max)(uint32_t lcore_id); + int (*set_core_freq_min)(uint32_t lcore_id); + + /** + * return + * - 1 Turbo Boost is enabled for this lcore. + * - 0 Turbo Boost is disabled for this lcore. + * - Negative on error. + */ + int (*get_core_turbo_status)(uint32_t lcore_id); + + /* return - 0 on success; negative on error */ + int (*enable_core_turbo)(uint32_t lcore_id); + int (*disable_core_turbo)(uint32_t lcore_id); + int (*get_core_capabilities)(uint32_t lcore_id, struct spdk_governor_capabilities *capabilities); + int (*init_core)(uint32_t lcore_id); + int (*deinit_core)(uint32_t lcore_id); + int (*init)(void); + int (*deinit)(void); + + TAILQ_ENTRY(spdk_governor) link; +}; + +/** + * Add the given governor to the list of registered governors. + * This function should be invoked by referencing the macro + * SPDK_GOVERNOR_REGISTER in the governor c file. + * + * \param governor Governor to be added. + * + * \return 0 on success or non-zero on failure. + */ +void _spdk_governor_list_add(struct spdk_governor *governor); + +/** + * Change current governor. + * + * \param name Name of the governor to be used. + * + * \return 0 on success or non-zero on failure. + */ +int _spdk_governor_set(char *name); + +/** + * Macro used to register new cores governor. + */ +#define SPDK_GOVERNOR_REGISTER(governor) \ + static void __attribute__((constructor)) _spdk_governor_register_##name(void) \ + { \ + _spdk_governor_list_add(governor); \ + } \ + /** * A list of cores and threads which is used for scheduling. */ @@ -190,19 +275,20 @@ struct spdk_scheduler_core_info { * Scheduler balance function type. * Accepts array of core_info which is of size 'count' and returns updated array. */ -typedef void (*spdk_scheduler_balance_fn)(struct spdk_scheduler_core_info *core_info, int count); +typedef void (*spdk_scheduler_balance_fn)(struct spdk_scheduler_core_info *core_info, int count, + struct spdk_governor *governor); /** * Scheduler init function type. * Called on scheduler module initialization. */ -typedef int (*spdk_scheduler_init_fn)(void); +typedef int (*spdk_scheduler_init_fn)(struct spdk_governor *governor); /** * Scheduler deinitialization function type. * Called on reactor fini. */ -typedef int (*spdk_scheduler_deinit_fn)(void); +typedef int (*spdk_scheduler_deinit_fn)(struct spdk_governor *governor); /** Thread scheduler */ struct spdk_scheduler { diff --git a/lib/event/reactor.c b/lib/event/reactor.c index 813df6066..07c50218d 100644 --- a/lib/event/reactor.c +++ b/lib/event/reactor.c @@ -70,6 +70,17 @@ static struct spdk_reactor *g_scheduling_reactor; static uint32_t g_scheduler_period; static struct spdk_scheduler_core_info *g_core_infos = NULL; +TAILQ_HEAD(, spdk_governor) g_governor_list + = TAILQ_HEAD_INITIALIZER(g_governor_list); + +static int _governor_get_capabilities(uint32_t lcore_id, + struct spdk_governor_capabilities *capabilities); + +static struct spdk_governor g_governor = { + .name = "default", + .get_core_capabilities = _governor_get_capabilities, +}; + static int reactor_interrupt_init(struct spdk_reactor *reactor); static void reactor_interrupt_fini(struct spdk_reactor *reactor); @@ -98,8 +109,12 @@ _spdk_scheduler_set(char *name) return -ENOENT; } + if (g_scheduler != NULL && g_scheduler->deinit != NULL) { + g_scheduler->deinit(&g_governor); + } + if (scheduler->init != NULL) { - scheduler->init(); + scheduler->init(&g_governor); } g_scheduler = scheduler; @@ -232,7 +247,7 @@ spdk_reactors_fini(void) } if (g_scheduler->deinit != NULL) { - g_scheduler->deinit(); + g_scheduler->deinit(&g_governor); } spdk_thread_lib_fini(); @@ -477,7 +492,7 @@ _reactors_scheduler_fini(void *arg1, void *arg2) if (g_reactor_state == SPDK_REACTOR_STATE_RUNNING) { last_core = spdk_env_get_last_core(); - g_scheduler->balance(g_core_infos, last_core + 1); + g_scheduler->balance(g_core_infos, last_core + 1, &g_governor); /* Reschedule based on the balancing output */ _threads_reschedule(g_core_infos); @@ -1115,4 +1130,79 @@ _spdk_lw_thread_get_current_stats(struct spdk_lw_thread *thread, struct spdk_thr *stats = thread->current_stats; } +static int +_governor_get_capabilities(uint32_t lcore_id, struct spdk_governor_capabilities *capabilities) +{ + capabilities->freq_change = false; + capabilities->freq_getset = false; + capabilities->freq_up = false; + capabilities->freq_down = false; + capabilities->freq_max = false; + capabilities->freq_min = false; + capabilities->turbo_set = false; + capabilities->priority = false; + capabilities->turbo_available = false; + + return 0; +} + +static struct spdk_governor * +_governor_find(char *name) +{ + struct spdk_governor *governor, *tmp; + + TAILQ_FOREACH_SAFE(governor, &g_governor_list, link, tmp) { + if (strcmp(name, governor->name) == 0) { + return governor; + } + } + + return NULL; +} + +int +_spdk_governor_set(char *name) +{ + struct spdk_governor *governor; + uint32_t i; + int rc; + + governor = _governor_find(name); + if (governor == NULL) { + return -EINVAL; + } + + g_governor = *governor; + + if (g_governor.init) { + rc = g_governor.init(); + if (rc != 0) { + return rc; + } + } + + SPDK_ENV_FOREACH_CORE(i) { + if (g_governor.init_core) { + rc = g_governor.init_core(i); + if (rc != 0) { + return rc; + } + } + } + + return 0; +} + +void +_spdk_governor_list_add(struct spdk_governor *governor) +{ + if (_governor_find(governor->name)) { + SPDK_ERRLOG("governor named '%s' already registered.\n", governor->name); + assert(false); + return; + } + + TAILQ_INSERT_TAIL(&g_governor_list, governor, link); +} + SPDK_LOG_REGISTER_COMPONENT(reactor)