2 # SPDX-License-Identifier: LGPL-2.1-or-later
7 # shellcheck disable=SC2181
8 if [[ $?
-ne 0 ]]; then
9 # We're exiting with a non-zero EC, let's dump test artifacts
10 # for easier debugging
11 [[ -v straceLog
&& -f "$straceLog" ]] && cat "$straceLog"
12 [[ -v journalLog
&& -f "$journalLog" ]] && cat "$journalLog"
18 systemd-analyze log-level debug
19 systemd-analyze log-target journal
22 straceLog
='strace.log'
23 journalLog
='journal.log'
25 # Systemd config files
26 testUnit
='numa-test.service'
27 testUnitFile
="/run/systemd/system/$testUnit"
28 testUnitNUMAConf
="$testUnitFile.d/numa.conf"
30 # Sleep constants (we should probably figure out something better but nothing comes to mind)
33 # Journal cursor for easier navigation
34 journalCursorFile
="jounalCursorFile"
37 coproc strace
-qq -p 1 -o "$straceLog" -e set_mempolicy
-s 1024 ${1:+"$1"}
38 # Wait for strace to properly "initialize", i.e. until PID 1 has the TracerPid
39 # field set to the current strace's PID
40 while ! awk -v spid
="$COPROC_PID" '/^TracerPid:/ {exit !($2 == spid);}' /proc
/1/status
; do sleep 0.1; done
44 [[ -v COPROC_PID
]] ||
return
48 # Make sure the strace process is indeed dead
49 while kill -0 "$PID" 2>/dev
/null
; do sleep 0.1; done
53 : >"$journalCursorFile"
54 # Save journal's cursor for later navigation
55 journalctl
--no-pager --cursor-file="$journalCursorFile" -n0 -ocat
59 local unit
="${1:-init.scope}"
60 # Using journalctl --sync should be better than using SIGRTMIN+1, as
61 # the --sync wait until the synchronization is complete
62 echo "Force journald to write all queued messages"
64 journalctl
-u "$unit" --cursor-file="$journalCursorFile" >"$journalLog"
68 # NUMA enabled system should have at least NUMA node0
69 test -e /sys
/devices
/system
/node
/node0
72 writePID1NUMAPolicy
() {
73 cat >"$confDir/numa.conf" <<EOF
75 NUMAPolicy=${1:?missing argument: NUMAPolicy}
81 mkdir
-p "$testUnitFile.d/"
82 printf "[Service]\nExecStart=/bin/sleep 3600\n" >"$testUnitFile"
85 writeTestUnitNUMAPolicy
() {
86 cat >"$testUnitNUMAConf" <<EOF
88 NUMAPolicy=${1:?missing argument: NUMAPolicy}
91 systemctl daemon-reload
94 pid1ReloadWithStrace
() {
96 systemctl daemon-reload
97 sleep $sleepAfterStart
101 pid1ReloadWithJournal
() {
103 systemctl daemon-reload
107 pid1StartUnitWithStrace
() {
109 systemctl start
"${1:?missing unit name}"
110 sleep $sleepAfterStart
114 pid1StartUnitWithJournal
() {
116 systemctl start
"${1:?missing unit name}"
117 sleep $sleepAfterStart
122 systemctl stop
"${1:?missing unit name}"
125 systemctlCheckNUMAProperties
() {
126 local UNIT_NAME
="${1:?missing unit name}"
127 local NUMA_POLICY
="${2:?missing NUMAPolicy}"
128 local NUMA_MASK
="${3:-""}"
133 systemctl show
-p NUMAPolicy
"$UNIT_NAME" >"$LOGFILE"
134 grep "NUMAPolicy=$NUMA_POLICY" "$LOGFILE"
138 if [ -n "$NUMA_MASK" ]; then
139 systemctl show
-p NUMAMask
"$UNIT_NAME" >"$LOGFILE"
140 grep "NUMAMask=$NUMA_MASK" "$LOGFILE"
146 # Create systemd config drop-in directory
147 confDir
="/run/systemd/system.conf.d/"
151 echo >&2 "NUMA is not supported on this machine, switching to a simple sanity check"
153 echo "PID1 NUMAPolicy=default && NUMAMask=0 check without NUMA support"
154 writePID1NUMAPolicy
"default" "0"
156 systemctl daemon-reload
158 grep "NUMA support not available, ignoring" "$journalLog"
160 echo "systemd-run NUMAPolicy=default && NUMAMask=0 check without NUMA support"
161 runUnit
='numa-systemd-run-test.service'
163 systemd-run
-p NUMAPolicy
=default
-p NUMAMask
=0 --unit "$runUnit" sleep 1000
164 sleep $sleepAfterStart
165 pid1StopUnit
"$runUnit"
166 stopJournalctl
"$runUnit"
167 grep "NUMA support not available, ignoring" "$journalLog"
170 echo "PID1 NUMAPolicy support - Default policy w/o mask"
171 writePID1NUMAPolicy
"default"
173 # Kernel requires that nodemask argument is set to NULL when setting default policy
174 grep "set_mempolicy(MPOL_DEFAULT, NULL" "$straceLog"
176 echo "PID1 NUMAPolicy support - Default policy w/ mask"
177 writePID1NUMAPolicy
"default" "0"
179 grep "set_mempolicy(MPOL_DEFAULT, NULL" "$straceLog"
181 echo "PID1 NUMAPolicy support - Bind policy w/o mask"
182 writePID1NUMAPolicy
"bind"
183 pid1ReloadWithJournal
184 grep "Failed to set NUMA memory policy: Invalid argument" "$journalLog"
186 echo "PID1 NUMAPolicy support - Bind policy w/ mask"
187 writePID1NUMAPolicy
"bind" "0"
189 grep -P "set_mempolicy\(MPOL_BIND, \[0x0*1\]" "$straceLog"
191 echo "PID1 NUMAPolicy support - Interleave policy w/o mask"
192 writePID1NUMAPolicy
"interleave"
193 pid1ReloadWithJournal
194 grep "Failed to set NUMA memory policy: Invalid argument" "$journalLog"
196 echo "PID1 NUMAPolicy support - Interleave policy w/ mask"
197 writePID1NUMAPolicy
"interleave" "0"
199 grep -P "set_mempolicy\(MPOL_INTERLEAVE, \[0x0*1\]" "$straceLog"
201 echo "PID1 NUMAPolicy support - Preferred policy w/o mask"
202 writePID1NUMAPolicy
"preferred"
203 pid1ReloadWithJournal
204 # Preferred policy with empty node mask is actually allowed and should reset allocation policy to default
205 grep "Failed to set NUMA memory policy: Invalid argument" "$journalLog" && { echo >&2 "unexpected pass"; exit 1; }
207 echo "PID1 NUMAPolicy support - Preferred policy w/ mask"
208 writePID1NUMAPolicy
"preferred" "0"
210 grep -P "set_mempolicy\(MPOL_PREFERRED, \[0x0*1\]" "$straceLog"
212 echo "PID1 NUMAPolicy support - Local policy w/o mask"
213 writePID1NUMAPolicy
"local"
215 # Kernel requires that nodemask argument is set to NULL when setting default policy
216 # The unpatched versions of strace don't recognize the MPOL_LOCAL constant and
217 # return a numerical constant instead (with a comment):
218 # set_mempolicy(0x4 /* MPOL_??? */, NULL, 0) = 0
219 # Let's cover this scenario as well
220 grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" "$straceLog"
222 echo "PID1 NUMAPolicy support - Local policy w/ mask"
223 writePID1NUMAPolicy
"local" "0"
225 grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" "$straceLog"
227 echo "Unit file NUMAPolicy support - Default policy w/o mask"
228 writeTestUnitNUMAPolicy
"default"
229 pid1StartUnitWithStrace
"$testUnit"
230 systemctlCheckNUMAProperties
"$testUnit" "default"
231 pid1StopUnit
"$testUnit"
232 grep "set_mempolicy(MPOL_DEFAULT, NULL" "$straceLog"
234 echo "Unit file NUMAPolicy support - Default policy w/ mask"
235 writeTestUnitNUMAPolicy
"default" "0"
236 pid1StartUnitWithStrace
"$testUnit"
237 systemctlCheckNUMAProperties
"$testUnit" "default" "0"
238 pid1StopUnit
$testUnit
239 # Mask must be ignored
240 grep "set_mempolicy(MPOL_DEFAULT, NULL" "$straceLog"
242 echo "Unit file NUMAPolicy support - Bind policy w/o mask"
243 writeTestUnitNUMAPolicy
"bind"
244 pid1StartUnitWithJournal
"$testUnit"
245 pid1StopUnit
"$testUnit"
246 grep "numa-test.service: Main process exited, code=exited, status=242/NUMA" "$journalLog"
248 echo "Unit file NUMAPolicy support - Bind policy w/ mask"
249 writeTestUnitNUMAPolicy
"bind" "0"
250 pid1StartUnitWithStrace
"$testUnit"
251 systemctlCheckNUMAProperties
"$testUnit" "bind" "0"
252 pid1StopUnit
"$testUnit"
253 grep -P "set_mempolicy\(MPOL_BIND, \[0x0*1\]" "$straceLog"
255 echo "Unit file NUMAPolicy support - Interleave policy w/o mask"
256 writeTestUnitNUMAPolicy
"interleave"
257 pid1StartUnitWithStrace
"$testUnit"
258 pid1StopUnit
"$testUnit"
259 grep "numa-test.service: Main process exited, code=exited, status=242/NUMA" "$journalLog"
261 echo "Unit file NUMAPolicy support - Interleave policy w/ mask"
262 writeTestUnitNUMAPolicy
"interleave" "0"
263 pid1StartUnitWithStrace
"$testUnit"
264 systemctlCheckNUMAProperties
"$testUnit" "interleave" "0"
265 pid1StopUnit
"$testUnit"
266 grep -P "set_mempolicy\(MPOL_INTERLEAVE, \[0x0*1\]" "$straceLog"
268 echo "Unit file NUMAPolicy support - Preferred policy w/o mask"
269 writeTestUnitNUMAPolicy
"preferred"
270 pid1StartUnitWithJournal
"$testUnit"
271 systemctlCheckNUMAProperties
"$testUnit" "preferred"
272 pid1StopUnit
"$testUnit"
273 grep "numa-test.service: Main process exited, code=exited, status=242/NUMA" "$journalLog" && { echo >&2 "unexpected pass"; exit 1; }
275 echo "Unit file NUMAPolicy support - Preferred policy w/ mask"
276 writeTestUnitNUMAPolicy
"preferred" "0"
277 pid1StartUnitWithStrace
"$testUnit"
278 systemctlCheckNUMAProperties
"$testUnit" "preferred" "0"
279 pid1StopUnit
"$testUnit"
280 grep -P "set_mempolicy\(MPOL_PREFERRED, \[0x0*1\]" "$straceLog"
282 echo "Unit file NUMAPolicy support - Local policy w/o mask"
283 writeTestUnitNUMAPolicy
"local"
284 pid1StartUnitWithStrace
"$testUnit"
285 systemctlCheckNUMAProperties
"$testUnit" "local"
286 pid1StopUnit
"$testUnit"
287 grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" "$straceLog"
289 echo "Unit file NUMAPolicy support - Local policy w/ mask"
290 writeTestUnitNUMAPolicy
"local" "0"
291 pid1StartUnitWithStrace
"$testUnit"
292 systemctlCheckNUMAProperties
"$testUnit" "local" "0"
293 pid1StopUnit
"$testUnit"
294 # Mask must be ignored
295 grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" "$straceLog"
297 echo "Unit file CPUAffinity=NUMA support"
298 writeTestUnitNUMAPolicy
"bind" "0"
299 echo "CPUAffinity=numa" >>"$testUnitNUMAConf"
300 systemctl daemon-reload
301 systemctl start
"$testUnit"
302 systemctlCheckNUMAProperties
"$testUnit" "bind" "0"
303 cpulist
="$(cat /sys/devices/system/node/node0/cpulist)"
304 affinity_systemd
="$(systemctl show --value -p CPUAffinity "$testUnit")"
305 [ "$cpulist" = "$affinity_systemd" ]
306 pid1StopUnit
"$testUnit"
308 echo "systemd-run NUMAPolicy support"
309 runUnit
='numa-systemd-run-test.service'
311 systemd-run
-p NUMAPolicy
=default
--unit "$runUnit" sleep 1000
312 systemctlCheckNUMAProperties
"$runUnit" "default"
313 pid1StopUnit
"$runUnit"
315 systemd-run
-p NUMAPolicy
=default
-p NUMAMask
=0 --unit "$runUnit" sleep 1000
316 systemctlCheckNUMAProperties
"$runUnit" "default" ""
317 pid1StopUnit
"$runUnit"
319 systemd-run
-p NUMAPolicy
=bind -p NUMAMask
=0 --unit "$runUnit" sleep 1000
320 systemctlCheckNUMAProperties
"$runUnit" "bind" "0"
321 pid1StopUnit
"$runUnit"
323 systemd-run
-p NUMAPolicy
=interleave
-p NUMAMask
=0 --unit "$runUnit" sleep 1000
324 systemctlCheckNUMAProperties
"$runUnit" "interleave" "0"
325 pid1StopUnit
"$runUnit"
327 systemd-run
-p NUMAPolicy
=preferred
-p NUMAMask
=0 --unit "$runUnit" sleep 1000
328 systemctlCheckNUMAProperties
"$runUnit" "preferred" "0"
329 pid1StopUnit
"$runUnit"
331 systemd-run
-p NUMAPolicy
=local --unit "$runUnit" sleep 1000
332 systemctlCheckNUMAProperties
"$runUnit" "local"
333 pid1StopUnit
"$runUnit"
335 systemd-run
-p NUMAPolicy
=local -p NUMAMask
=0 --unit "$runUnit" sleep 1000
336 systemctlCheckNUMAProperties
"$runUnit" "local" ""
337 pid1StopUnit
"$runUnit"
339 systemd-run
-p NUMAPolicy
=local -p NUMAMask
=0 -p CPUAffinity
=numa
--unit "$runUnit" sleep 1000
340 systemctlCheckNUMAProperties
"$runUnit" "local" ""
341 systemctl
cat "$runUnit" |
grep -q 'CPUAffinity=numa'
342 pid1StopUnit
"$runUnit"
347 systemctl daemon-reload
349 systemd-analyze log-level info