Commit 127fc0d0 authored by Tomasz Zawadzki's avatar Tomasz Zawadzki Committed by Jim Harris
Browse files

scheduler_dynamic: consider any core for the thread



Previously core load was only considered for main lcore.
Other cores were used based on cpumask only.

Once an active thread was placed on core it remained there
until idle. If _get_next_target_core() looped around,
the core might receive another active thread.

This patch makes the core load matter for placement of any thread.
As of this patch if no core can fit a thread it will remain there.
Later in the series least busy core will be used to balance
threads when every core is already busy.

Modified the functional test that depended on always selecting
consecutive core, even if 'current' one fit the bill.
Later in the series the round robin logic for core selection
is removed all together.

Fixed typo in test while here.

Note: _can_core_fit_thread() intentionally does not check
core->interrupt_mode and uses tsc. That flag is only updated
at the end of balancing right now. Meanwhile tsc is updated
one first thread moved to the core, so it is no longer
considered in interrupt mode.

Signed-off-by: default avatarTomasz Zawadzki <tomasz.zawadzki@intel.com>
Change-Id: I95f58c94e3f5ae8a468723d1dd6e53b0e417dcc3
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/8069


Reviewed-by: default avatarMaciej Szwed <maciej.szwed@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
parent 2d79bf58
Loading
Loading
Loading
Loading
+31 −4
Original line number Diff line number Diff line
@@ -126,14 +126,41 @@ _move_thread(struct spdk_lw_thread *lw_thread, uint32_t dst_core)
	lw_thread->lcore = dst_core;
}

static bool
_can_core_fit_thread(struct spdk_lw_thread *lw_thread, uint32_t dst_core)
{
	struct core_stats *dst = &g_cores[dst_core];

	/* Thread can always fit on the core it's currently on. */
	if (lw_thread->lcore == dst_core) {
		return true;
	}

	/* Reactors in interrupt mode do not update stats,
	 * a thread can always fit into reactor in interrupt mode. */
	if (dst->busy + dst->idle == 0) {
		return true;
	}

	/* Core has no threads. */
	if (dst->thread_count == 0) {
		return true;
	}

	if (lw_thread->current_stats.busy_tsc <= dst->idle) {
		return true;
	}
	return false;
}

static uint32_t
_find_optimal_core(struct spdk_lw_thread *lw_thread)
{
	uint32_t i;
	uint32_t target_lcore;
	uint32_t current_lcore = lw_thread->lcore;
	struct spdk_thread *thread = spdk_thread_get_from_ctx(lw_thread);
	struct spdk_cpuset *cpumask = spdk_thread_get_cpumask(thread);
	uint64_t thread_busy = lw_thread->current_stats.busy_tsc;

	/* Find a core that can fit the thread. */
	for (i = 0; i < spdk_env_get_core_count(); i++) {
@@ -144,8 +171,8 @@ _find_optimal_core(struct spdk_lw_thread *lw_thread)
			continue;
		}

		/* Do not use main core if it is too busy for new thread. */
		if (target_lcore == g_main_lcore && thread_busy > g_cores[g_main_lcore].idle) {
		/* Skip cores that cannot fit the thread and current one. */
		if (!_can_core_fit_thread(lw_thread, target_lcore) || target_lcore == current_lcore) {
			continue;
		}

@@ -153,7 +180,7 @@ _find_optimal_core(struct spdk_lw_thread *lw_thread)
	}

	/* If no better core is found, remain on the same one. */
	return lw_thread->lcore;
	return current_lcore;
}

static int
+3 −4
Original line number Diff line number Diff line
@@ -96,7 +96,7 @@ balanced() {

	thread0_name=thread0
	thread0=$(create_thread -n "$thread0_name" -m "$(mask_cpus "${selected_cpus[@]}")" -a 0)
	for cpu in "${selected_cpus[@]}"; do
	for cpu in "${selected_cpus[@]::${#selected_cpus[@]}-1}"; do
		extra_threads+=("$(create_thread -n "thread_cpu_$cpu" -m "$(mask_cpus "$cpu")" -a 100)")
	done

@@ -124,13 +124,12 @@ balanced() {

	[[ -n $(jq -r "select(.lcore == $spdk_main_core) | .lw_threads[] | select(.id == $thread0)") ]] <<< "$reactor_framework"

	# thread0 is active, wait for scheduler to run (2x) and check if it is not on main core, nor the core from 2)
	# thread0 is active, wait for scheduler to run (2x) and check if it is not on main core
	active_thread "$thread0" 100
	sleep $((2 * sched_period))
	reactor_framework=$(rpc_cmd framework_get_reactors | jq -r '.reactors[]')

	[[ -z $(jq -r "select(.lcore == $spdk_main_core) | .lw_threads[] | select(.id == $thread0)") ]] <<< "$reactor_framewrk"
	[[ -z $(jq -r "select(.lcore == $active_cpu) | .lw_threads[] | select(.id == $thread0)") ]] <<< "$reactor_framewrk"
	[[ -z $(jq -r "select(.lcore == $spdk_main_core) | .lw_threads[] | select(.id == $thread0)") ]] <<< "$reactor_framework"

	destroy_thread "$thread0"
	for thread in "${extra_threads[@]}"; do