1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
|
#!/usr/bin/env bats
# Exec CPU affinity tests. For more details, see:
# - https://github.com/opencontainers/runtime-spec/pull/1253
load helpers
INITIAL_CPU_MASK="$(grep -F Cpus_allowed_list: /proc/self/status | awk '{ print $2 }')"
function setup() {
requires smp cgroups_cpuset
setup_busybox
echo "Initial CPU mask: $INITIAL_CPU_MASK" >&2
echo "---" >&2
}
function teardown() {
teardown_bundle
}
function first_cpu() {
sed 's/[-,].*//g' </sys/devices/system/cpu/online
}
# Convert list of cpus ("0,1" or "0-1") to mask as printed by nsexec.
# NOTE the range conversion is not proper, merely sufficient for tests here.
function cpus_to_mask() {
local cpus=$* mask=0
cpus=${cpus//,/-} # 1. "," --> "-".
cpus=${cpus//-/ } # 2. "-" --> " ".
for c in $cpus; do
mask=$((mask | 1 << c))
done
printf "0x%x" $mask
}
@test "runc exec [CPU affinity, only initial set from process.json]" {
first="$(first_cpu)"
second=$((first + 1)) # Hacky; might not work in all environments.
runc run -d --console-socket "$CONSOLE_SOCKET" ct1
[ "$status" -eq 0 ]
for cpus in "$second" "$first-$second" "$first,$second" "$first"; do
proc='
{
"terminal": false,
"execCPUAffinity": {
"initial": "'$cpus'"
},
"args": [ "/bin/true" ],
"cwd": "/"
}'
mask=$(cpus_to_mask "$cpus")
echo "CPUS: $cpus, mask: $mask"
runc --debug exec --process <(echo "$proc") ct1
[[ "$output" == *"nsexec"*": affinity: $mask"* ]]
done
}
@test "runc exec [CPU affinity, initial and final set from process.json]" {
first="$(first_cpu)"
second=$((first + 1)) # Hacky; might not work in all environments.
runc run -d --console-socket "$CONSOLE_SOCKET" ct1
[ "$status" -eq 0 ]
for cpus in "$second" "$first-$second" "$first,$second" "$first"; do
proc='
{
"terminal": false,
"execCPUAffinity": {
"initial": "'$cpus'",
"final": "'$cpus'"
},
"args": [ "/bin/grep", "-F", "Cpus_allowed_list:", "/proc/self/status" ],
"cwd": "/"
}'
mask=$(cpus_to_mask "$cpus")
exp=${cpus//,/-} # "," --> "-".
echo "CPUS: $cpus, mask: $mask, final: $exp"
runc --debug exec --process <(echo "$proc") ct1
[[ "$output" == *"nsexec"*": affinity: $mask"* ]]
[[ "$output" == *"Cpus_allowed_list: $exp"* ]] # Mind the literal tab.
done
}
@test "runc exec [CPU affinity, initial and final set from config.json]" {
initial="$(first_cpu)"
final=$((initial + 1)) # Hacky; might not work in all environments.
update_config " .process.execCPUAffinity.initial = \"$initial\"
| .process.execCPUAffinity.final = \"$final\""
runc run -d --console-socket "$CONSOLE_SOCKET" ct1
[ "$status" -eq 0 ]
runc --debug exec ct1 grep "Cpus_allowed_list:" /proc/self/status
[ "$status" -eq 0 ]
mask=$(cpus_to_mask "$initial")
[[ "$output" == *"nsexec"*": affinity: $mask"* ]]
[[ "$output" == *"Cpus_allowed_list: $final"* ]] # Mind the literal tab.
}
@test "runc run [CPU affinity should reset]" {
# We need to use RUNC_CMDLINE since taskset requires a proper binary, not a
# bash function (which is what runc and __runc are).
setup_runc_cmdline
first="$(first_cpu)"
# Running without cpuset should result in an affinity for all CPUs.
update_config '.process.args = [ "/bin/grep", "-F", "Cpus_allowed_list:", "/proc/self/status" ]'
update_config 'del(.linux.resources.cpu)'
sane_run taskset -c "$first" "${RUNC_CMDLINE[@]}" run ctr
[ "$status" -eq 0 ]
[[ "$output" != $'Cpus_allowed_list:\t'"$first" ]]
[[ "$output" == $'Cpus_allowed_list:\t'"$INITIAL_CPU_MASK" ]]
}
@test "runc run [CPU affinity should reset to cgroup cpuset]" {
[ $EUID -ne 0 ] && requires rootless_cgroup
set_cgroups_path
# We need to use RUNC_CMDLINE since taskset requires a proper binary, not a
# bash function (which is what runc and __runc are).
setup_runc_cmdline
first="$(first_cpu)"
second="$((first + 1))" # Hacky; might not work in all environments.
# Running with a cpuset should result in an affinity that matches.
update_config '.process.args = [ "/bin/grep", "-F", "Cpus_allowed_list:", "/proc/self/status" ]'
update_config '.linux.resources.cpu = {"mems": "0", "cpus": "'"$first-$second"'"}'
sane_run taskset -c "$first" "${RUNC_CMDLINE[@]}" run ctr
[ "$status" -eq 0 ]
[[ "$output" != $'Cpus_allowed_list:\t'"$first" ]]
# XXX: For some reason, systemd-cgroup leads to us using the all-set
# cpumask rather than the cpuset we configured?
[ -v RUNC_USE_SYSTEMD ] || [[ "$output" == $'Cpus_allowed_list:\t'"$first-$second" ]]
# Ditto for a cpuset that has no overlap with the original cpumask.
update_config '.linux.resources.cpu = {"mems": "0", "cpus": "'"$second"'"}'
sane_run taskset -c "$first" "${RUNC_CMDLINE[@]}" run ctr
[ "$status" -eq 0 ]
[[ "$output" != $'Cpus_allowed_list:\t'"$first" ]]
# XXX: For some reason, systemd-cgroup leads to us using the all-set
# cpumask rather than the cpuset we configured?
[ -v RUNC_USE_SYSTEMD ] || [[ "$output" == $'Cpus_allowed_list:\t'"$second" ]]
}
@test "runc exec [default CPU affinity should reset]" {
# We need to use RUNC_CMDLINE since taskset requires a proper binary, not a
# bash function (which is what runc and __runc are).
setup_runc_cmdline
first="$(first_cpu)"
# Running without cpuset should result in an affinity for all CPUs.
update_config '.process.args = [ "/bin/sleep", "infinity" ]'
update_config 'del(.linux.resources.cpu)'
sane_run taskset -c "$first" "${RUNC_CMDLINE[@]}" run -d --console-socket "$CONSOLE_SOCKET" ctr3
[ "$status" -eq 0 ]
sane_run taskset -c "$first" "${RUNC_CMDLINE[@]}" exec ctr3 grep -F Cpus_allowed_list: /proc/self/status
[ "$status" -eq 0 ]
[[ "$output" != $'Cpus_allowed_list:\t'"$first" ]]
[[ "$output" == $'Cpus_allowed_list:\t'"$INITIAL_CPU_MASK" ]]
}
@test "runc exec [default CPU affinity should reset to cgroup cpuset]" {
[ $EUID -ne 0 ] && requires rootless_cgroup
set_cgroups_path
# We need to use RUNC_CMDLINE since taskset requires a proper binary, not a
# bash function (which is what runc and __runc are).
setup_runc_cmdline
first="$(first_cpu)"
second="$((first + 1))" # Hacky; might not work in all environments.
# Running with a cpuset should result in an affinity that matches.
update_config '.process.args = [ "/bin/sleep", "infinity" ]'
update_config '.linux.resources.cpu = {"mems": "0", "cpus": "'"$first-$second"'"}'
sane_run taskset -c "$first" "${RUNC_CMDLINE[@]}" run -d --console-socket "$CONSOLE_SOCKET" ctr
[ "$status" -eq 0 ]
sane_run taskset -c "$first" "${RUNC_CMDLINE[@]}" exec ctr grep -F Cpus_allowed_list: /proc/self/status
[ "$status" -eq 0 ]
[[ "$output" != $'Cpus_allowed_list:\t'"$first" ]]
# XXX: For some reason, systemd-cgroup leads to us using the all-set
# cpumask rather than the cpuset we configured?
[ -v RUNC_USE_SYSTEMD ] || [[ "$output" == $'Cpus_allowed_list:\t'"$first-$second" ]]
# Stop the container so we can reconfigure it.
runc delete -f ctr
[ "$status" -eq 0 ]
# Ditto for a cpuset that has no overlap with the original cpumask.
update_config '.linux.resources.cpu = {"mems": "0", "cpus": "'"$second"'"}'
sane_run taskset -c "$first" "${RUNC_CMDLINE[@]}" run -d --console-socket "$CONSOLE_SOCKET" ctr
[ "$status" -eq 0 ]
sane_run taskset -c "$first" "${RUNC_CMDLINE[@]}" exec ctr grep -F Cpus_allowed_list: /proc/self/status
[ "$status" -eq 0 ]
[[ "$output" != $'Cpus_allowed_list:\t'"$first" ]]
# XXX: For some reason, systemd-cgroup leads to us using the all-set
# cpumask rather than the cpuset we configured?
[ -v RUNC_USE_SYSTEMD ] || [[ "$output" == $'Cpus_allowed_list:\t'"$second" ]]
}
|