e52df268d3
Signed-off-by: Michal Berger <michalx.berger@intel.com> Signed-off-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com> Change-Id: I89e31aceb7037c55801f4b7cbd4126bce38ae174 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/7566 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com> Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com>
241 lines
8.1 KiB
Bash
Executable File
241 lines
8.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
testdir=$(readlink -f "$(dirname "$0")")
|
|
rootdir=$(readlink -f "$testdir/../../")
|
|
|
|
source "$rootdir/test/common/autotest_common.sh"
|
|
source "$testdir/common.sh"
|
|
|
|
trap 'killprocess "$spdk_pid"' EXIT
|
|
|
|
fold_list_onto_array cpus $(parse_cpu_list <(echo "$spdk_cpus_csv"))
|
|
# Normalize the indexes
|
|
cpus=("${cpus[@]}")
|
|
|
|
busy() {
|
|
local selected_cpus cpu
|
|
local reactor_framework
|
|
local threads thread
|
|
|
|
# Create two busy threads with two cpus (not including main cpu) and check if either of
|
|
# them is moved to either of the selected cpus. Expected load is ~100% on each thread and
|
|
# each thread should remain on its designated cpu.
|
|
|
|
fold_list_onto_array selected_cpus "${cpus[@]:1:2}"
|
|
|
|
thread0=$(create_thread -n "thread0" -m "$(mask_cpus "${selected_cpus[@]}")" -a 100)
|
|
thread1=$(create_thread -n "thread1" -m "$(mask_cpus "${selected_cpus[@]}")" -a 100)
|
|
|
|
local samples=0
|
|
|
|
xtrace_disable
|
|
while ((samples++ < 5)); do
|
|
sleep 0.5s
|
|
|
|
all_set=0
|
|
reactor_framework=$(rpc_cmd framework_get_reactors | jq -r '.reactors[]')
|
|
|
|
printf '*Sample %u\n' "$samples"
|
|
for cpu in "${selected_cpus[@]}"; do
|
|
threads=($(jq -r "select(.lcore == $cpu) | .lw_threads[].id" <<< "$reactor_framework"))
|
|
|
|
if ((${#threads[@]} == 0)); then
|
|
printf ' No threads found on cpu%u\n' "$cpu"
|
|
continue
|
|
fi
|
|
|
|
get_thread_stats
|
|
|
|
for thread in "${threads[@]}"; do
|
|
if ((thread != thread0 && thread != thread1)); then
|
|
printf ' Unexpected thread %u (%s) on cpu%u\n' \
|
|
"$thread" "${thread_map[thread]}" "$cpu"
|
|
continue 3
|
|
fi
|
|
load=$((busy[thread] * 100 / (busy[thread] + idle[thread])))
|
|
if ((load < 95)); then
|
|
printf ' Unexpected load on thread %u (%s): %u%% (< 95%%)\n' \
|
|
"$thread" "${thread_map[thread]}" "$load"
|
|
continue 3
|
|
fi
|
|
printf ' Thread %u (%s) on cpu%u; load: %u%%\n' \
|
|
"$thread" "${thread_map[thread]}" "$cpu" "$load"
|
|
eval "${thread_map[thread]}_cpus[$cpu]=$cpu"
|
|
done
|
|
done
|
|
|
|
all_set=1
|
|
done
|
|
|
|
destroy_thread "$thread0"
|
|
destroy_thread "$thread1"
|
|
|
|
# The final expectation is that when target threads are ~100% busy, they will stay on their
|
|
# designated cpus. FIXME: Does it make sense? if given cpu is not getting a break due to a
|
|
# thread not becoming idle even for a tick, scheduler should not put any other threads on
|
|
# that cpu nor move its assigned thread to any other cpu.
|
|
printf 'Thread %u (%s) cpus: %s\n' "$thread0" "${thread_map[thread0]}" "${thread0_cpus[*]:-none}"
|
|
printf 'Thread %u (%s) cpus: %s\n' "$thread1" "${thread_map[thread1]}" "${thread1_cpus[*]:-none}"
|
|
[[ ${thread0_cpus[*]} != "${thread1_cpus[*]}" ]]
|
|
((${#thread0_cpus[@]} == 1 && ${#thread1_cpus[@]} == 1 && all_set == 1))
|
|
|
|
xtrace_restore
|
|
}
|
|
|
|
balanced() {
|
|
|
|
local thread cpu
|
|
local extra_threads
|
|
local sched_period=1 # default, 1s
|
|
local active_cpu
|
|
|
|
# Exclude main cpu
|
|
fold_list_onto_array selected_cpus "${cpus[@]:1}"
|
|
|
|
thread0=$(create_thread -n "thread0" -m "$(mask_cpus "${selected_cpus[@]}")" -a 0)
|
|
for cpu in "${selected_cpus[@]::${#selected_cpus[@]}-1}"; do
|
|
extra_threads+=("$(create_thread -n "thread_cpu_$cpu" -m "$(mask_cpus "$cpu")" -a 100)")
|
|
done
|
|
|
|
# thread0 is idle, wait for scheduler to run (2x scheduling period) and check if it is on main core
|
|
sleep $((2 * sched_period))
|
|
reactor_framework=$(rpc_cmd framework_get_reactors | jq -r '.reactors[]')
|
|
[[ -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
|
|
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_framework"
|
|
# Get the cpu thread was scheduled onto
|
|
for cpu in "${selected_cpus[@]}"; do
|
|
[[ -n $(jq -r "select(.lcore == $cpu) | .lw_threads[] | select(.id == $thread0)") ]] <<< "$reactor_framework" && active_cpu=$cpu
|
|
done
|
|
[[ -n ${selected_cpus[active_cpu]} ]]
|
|
|
|
# thread0 is idle, wait for scheduler to run (2x) and check if it is on main core
|
|
active_thread "$thread0" 0
|
|
sleep $((2 * sched_period))
|
|
reactor_framework=$(rpc_cmd framework_get_reactors | jq -r '.reactors[]')
|
|
|
|
[[ -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
|
|
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_framework"
|
|
|
|
destroy_thread "$thread0"
|
|
for thread in "${extra_threads[@]}"; do
|
|
destroy_thread "$thread"
|
|
done
|
|
}
|
|
|
|
core_load() {
|
|
local sched_period=1 # default, 1s
|
|
local thread
|
|
local on_main_core=0 on_next_core=0
|
|
|
|
# Re-exec the scheduler app to make sure rr balancer won't affect threads without
|
|
# configured cpumask from the previous test suites.
|
|
|
|
exec_under_dynamic_scheduler "$scheduler" -m "$spdk_cpusmask" --main-core "$spdk_main_core"
|
|
|
|
# Create thread0 with 90% activity no cpumask, expecting it to remain on main cpu
|
|
thread0=$(create_thread -n "thread0" -a 90)
|
|
|
|
sleep $((2 * sched_period))
|
|
update_thread_cpus_map
|
|
|
|
((thread_cpus[thread0] == spdk_main_core))
|
|
|
|
# Create thread1 with 90% activity. Expecting one of the threads to be moved to next
|
|
# cpu and the other remain on main cpu. Verifying that threads are spread out when core
|
|
# load is over 95% limit.
|
|
thread1=$(create_thread -n "thread1" -a 90)
|
|
|
|
# Three iterations are needed, as both active threads first are moved out of main core.
|
|
# During next scheduling period one of them is moved back to the main core.
|
|
sleep $((3 * sched_period))
|
|
update_thread_cpus_map
|
|
|
|
((thread_cpus[thread0] == spdk_main_core || thread_cpus[thread1] == spdk_main_core))
|
|
((thread_cpus[thread0] != thread_cpus[thread1]))
|
|
|
|
# Create thread2 with 10% activity. Expecting the idle thread2 to be placed on main cpu and two
|
|
# other active threads on next cpus. Verifying the condition where core load over 95% moves threads
|
|
# away from main cpu.
|
|
thread2=$(create_thread -n "thread2" -a 10)
|
|
|
|
sleep $((2 * sched_period))
|
|
update_thread_cpus_map
|
|
|
|
((thread_cpus[thread2] == spdk_main_core))
|
|
((thread_cpus[thread1] != spdk_main_core))
|
|
((thread_cpus[thread0] != spdk_main_core))
|
|
((thread_cpus[thread0] != thread_cpus[thread1]))
|
|
|
|
# Change all threads activity to 10%. Expecting all threads to be placed on main cpu.
|
|
# Verifying the condition where core load less than 95% is grouping multiple threads.
|
|
active_thread "$thread0" 10
|
|
active_thread "$thread1" 10
|
|
active_thread "$thread2" 10
|
|
|
|
sleep $((2 * sched_period))
|
|
update_thread_cpus_map
|
|
|
|
for thread in \
|
|
"$thread0" \
|
|
"$thread1" \
|
|
"$thread2"; do
|
|
((thread_cpus[thread] == spdk_main_core))
|
|
done
|
|
|
|
# Create thread3, thread4 and thread 5 with 25% activity. Expecting one of the threads on next cpu
|
|
# and rest on main cpu. Total load on main cpu will be (10*3+25*2) 80%, and next cpu 25%.
|
|
thread3=$(create_thread -n "thread3" -a 25)
|
|
thread4=$(create_thread -n "thread4" -a 25)
|
|
thread5=$(create_thread -n "thread5" -a 25)
|
|
|
|
# Three iterations are needed, as all threads look active on first iteration since they are on the main core.
|
|
# Second iteraion will have them spread out over cores and only third will collapse to the expected scenario.
|
|
sleep $((3 * sched_period))
|
|
update_thread_cpus_map
|
|
|
|
# Verify that load is not exceeding 80% on each of the cpus except the main and next cpu
|
|
get_cpu_time 5 user "${cpus[@]:2}"
|
|
|
|
for cpu in "${!avg_cpu_time[@]}"; do
|
|
printf '* cpu%u avg load: %u%% (%s)\n' \
|
|
"$cpu" "${avg_cpu_time[cpu]}" "${cpu_times[cpu]}"
|
|
((avg_cpu_time[cpu] <= 80))
|
|
done
|
|
|
|
for thread in \
|
|
"$thread0" \
|
|
"$thread1" \
|
|
"$thread2" \
|
|
"$thread3" \
|
|
"$thread4" \
|
|
"$thread5"; do
|
|
if ((thread_cpus[thread] == spdk_main_core)); then
|
|
((++on_main_core))
|
|
else
|
|
((++on_next_core))
|
|
fi
|
|
|
|
destroy_thread "$thread"
|
|
done
|
|
|
|
((on_main_core == 5 && on_next_core == 1))
|
|
}
|
|
|
|
exec_under_dynamic_scheduler "$scheduler" -m "$spdk_cpusmask" --main-core "$spdk_main_core"
|
|
|
|
run_test "busy" busy
|
|
run_test "balanced" balanced
|
|
run_test "core_load" core_load
|