diff --git a/include/spdk_internal/event.h b/include/spdk_internal/event.h index 37065a59c..d54f70cbf 100644 --- a/include/spdk_internal/event.h +++ b/include/spdk_internal/event.h @@ -62,8 +62,11 @@ enum spdk_reactor_state { struct spdk_lw_thread { TAILQ_ENTRY(spdk_lw_thread) link; - bool resched; uint64_t tsc_start; + uint32_t lcore; + uint32_t new_lcore; + bool resched; + struct spdk_thread_stats current_stats; }; struct spdk_reactor { @@ -76,7 +79,8 @@ struct spdk_reactor { struct { uint32_t is_valid : 1; - uint32_t reserved : 31; + uint32_t is_scheduling : 1; + uint32_t reserved : 30; } flags; uint64_t tsc_last; @@ -171,6 +175,79 @@ 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); +/** + * A list of cores and threads which is used for scheduling. + */ +struct spdk_scheduler_core_info { + uint64_t core_idle_tsc; + uint64_t core_busy_tsc; + uint32_t lcore; + uint32_t threads_count; + struct spdk_lw_thread **threads; +}; + +/** + * 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); + +/** + * Scheduler init function type. + * Called on scheduler module initialization. + */ +typedef int (*spdk_scheduler_init_fn)(void); + +/** + * Scheduler deinitialization function type. + * Called on reactor fini. + */ +typedef int (*spdk_scheduler_deinit_fn)(void); + +/** Thread scheduler */ +struct spdk_scheduler { + char *name; + spdk_scheduler_init_fn init; + spdk_scheduler_deinit_fn deinit; + spdk_scheduler_balance_fn balance; + TAILQ_ENTRY(spdk_scheduler) link; +}; + +/** + * Add the given scheduler to the list of registered schedulers. + * This function should be invoked by referencing the macro + * SPDK_SCHEDULER_REGISTER in the scheduler c file. + * + * \param scheduler Scheduler to be added. + */ +void _spdk_scheduler_list_add(struct spdk_scheduler *scheduler); + +/** + * Change current scheduler. + * + * \param name Name of the scheduler to be used. + * + * \return 0 on success or non-zero on failure. + */ +int _spdk_scheduler_set(char *name); + +/** + * Change current scheduling period. + * + * \param period New period (ticks). + * Use spdk_get_ticks_hz() to translate seconds to ticks. + */ +void _spdk_scheduler_period_set(uint32_t period); + +/* + * Macro used to register new reactor balancer. + */ +#define SPDK_SCHEDULER_REGISTER(scheduler) \ +static void __attribute__((constructor)) _spdk_scheduler_register_##name(void) \ +{ \ + spdk_scheduler_list_add(scheduler); \ +} \ + /** * \brief Register a new subsystem */ diff --git a/lib/event/reactor.c b/lib/event/reactor.c index 8f75fc65d..9227c7d21 100644 --- a/lib/event/reactor.c +++ b/lib/event/reactor.c @@ -62,9 +62,61 @@ static bool g_framework_context_switch_monitor_enabled = true; static struct spdk_mempool *g_spdk_event_mempool = NULL; +TAILQ_HEAD(, spdk_scheduler) g_scheduler_list + = TAILQ_HEAD_INITIALIZER(g_scheduler_list); + +static struct spdk_scheduler *g_scheduler; +static uint32_t g_scheduler_period; + static int reactor_interrupt_init(struct spdk_reactor *reactor); static void reactor_interrupt_fini(struct spdk_reactor *reactor); +static struct spdk_scheduler * +_scheduler_find(char *name) +{ + struct spdk_scheduler *tmp; + + TAILQ_FOREACH(tmp, &g_scheduler_list, link) { + if (strcmp(name, tmp->name) == 0) { + return tmp; + } + } + + return NULL; +} + +int +_spdk_scheduler_set(char *name) +{ + struct spdk_scheduler *scheduler; + + scheduler = _scheduler_find(name); + if (scheduler == NULL) { + return -ENOENT; + } + + g_scheduler = scheduler; + return 0; +} + +void +_spdk_scheduler_period_set(uint32_t period) +{ + g_scheduler_period = period; +} + +void +_spdk_scheduler_list_add(struct spdk_scheduler *scheduler) +{ + if (_scheduler_find(scheduler->name)) { + SPDK_ERRLOG("scheduler named '%s' already registered.\n", scheduler->name); + assert(false); + return; + } + + TAILQ_INSERT_TAIL(&g_scheduler_list, scheduler, link); +} + static void reactor_construct(struct spdk_reactor *reactor, uint32_t lcore) { @@ -689,6 +741,7 @@ _reactor_request_thread_reschedule(struct spdk_thread *thread) assert(lw_thread != NULL); lw_thread->resched = true; + lw_thread->lcore = SPDK_ENV_LCORE_ID_ANY; current_core = spdk_env_get_current_core(); reactor = spdk_reactor_get(current_core);