event: governor implementation

Signed-off-by: Maciej Szwed <maciej.szwed@intel.com>
Change-Id: I9aaa84261144145933d227976a5f89dc89732267
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/4028
Reviewed-by: Aleksey Marchuk <alexeymar@mellanox.com>
Reviewed-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Tested-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com>
This commit is contained in:
Maciej Szwed 2020-09-02 10:00:12 +02:00 committed by Tomasz Zawadzki
parent 2cffc80079
commit c6adf304bd
2 changed files with 182 additions and 6 deletions

View File

@ -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 {

View File

@ -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)