Commit c6adf304 authored by Maciej Szwed's avatar Maciej Szwed Committed by Tomasz Zawadzki
Browse files

event: governor implementation

parent 2cffc800
Loading
Loading
Loading
Loading
+89 −3
Original line number Diff line number Diff line
@@ -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 {
+93 −3
Original line number Diff line number Diff line
@@ -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)