This repository has been archived by the owner on Jun 18, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: David Vernet <[email protected]>
- Loading branch information
Showing
1 changed file
with
135 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
#!/bin/bash | ||
# SPDX-License-Identifier: GPL-2.0 | ||
# Copyright (C) 2024 David Vernet <[email protected]> | ||
# Copyright (C) 2024 Meta Platforms, Inc. and affiliates. | ||
|
||
# Script to make a cgroup with conditions that should cause the infeasible | ||
# weight problem to manifest | ||
|
||
INFEASIBLE_CGRP="/sys/fs/cgroup/infeasible.scope" | ||
MINIMAL_CGRP="/sys/fs/cgroup/minimal.scope" | ||
|
||
# create_cgrp(grp) - Create a child of the root cgroup, and set its weight | ||
# grp - The cgroup to create | ||
function create_cgrp() { | ||
local cgrp="$1" | ||
local weight=10000 | ||
if [[ ${cgrp} == ${MINIMAL_CGRP} ]]; then | ||
weight=1 | ||
fi | ||
|
||
if [[ ! -d "${cgrp}" ]]; then | ||
mkdir "${cgrp}" | ||
echo "created cgroup ${cgrp}" | ||
else | ||
echo "cgroup ${cgrp} already existed" | ||
local curr_pids=$(cat "${cgrp}/pids.current") | ||
if [ "${curr_pids}" != "0" ]; then | ||
echo "ERR: tasks found in ${cgrp}" | ||
exit 1 | ||
fi | ||
fi | ||
|
||
echo "setting ${cgrp} weight to ${weight}" | ||
echo ${weight} > "${cgrp}/cpu.weight" | ||
echo "set ${cgrp} weight to ${weight}" | ||
} | ||
|
||
# invoke_stressng(ncpus) - Invoke the stress-ng utility with the specified # of CPUs | ||
# ncpus - The number of CPU hogs to have spawned | ||
function invoke_stressng() { | ||
local cpus=$1 | ||
stress-ng -c ${cpus} --cpu-load 100 --cpu-method matrixprod > /tmp/stressng_${cpus}.out 2> /tmp/stressng_${cpus}.out & | ||
stressng_pid=$! | ||
echo "stress-ng pid is ${stressng_pid}" | ||
if [ ${stressng_pid} -le 0 ]; then | ||
echo "ERR: failed to invoke stress-ng" | ||
exit 1 | ||
fi | ||
} | ||
|
||
# move_into_cgrp(cgrp, pid) - Move @pid into the cgroup @cgrp | ||
# cgrp - The cgrp to be moved into | ||
# pid - The pid of the process being moved | ||
function move_into_cgrp() { | ||
local cgrp=$1 | ||
local pid=$2 | ||
|
||
local procsfile="${cgrp}/cgroup.procs" | ||
local pidsfile="${cgrp}/pids.current" | ||
|
||
echo "moving ${pid} into ${procsfile}" | ||
echo " procs in before: $(cat ${pidsfile})" | ||
echo "${pid}" >> "${procsfile}" | ||
local status=$? | ||
echo "status was: ${status}" | ||
if [ ${status} -ne 0 ]; then | ||
echo "ERR: failed to move ${pid} into ${procsfile}" | ||
echo "ERR: destroying ${pid}" | ||
kill -9 ${pid} | ||
echo "ERR: killed ${pid}. waiting for exit..." | ||
wait | ||
echo "ERR: ${pid} exited" | ||
exit 1 | ||
fi | ||
echo " procs in after: $(cat ${pidsfile})" | ||
} | ||
|
||
# cleanup - Clean up after the script has run | ||
function cleanup() { | ||
# Nothing to clean up, really. Just do some sanity checking at the end. | ||
local curr_pids=$(cat "${INFEASIBLE_CGRP}/pids.current") | ||
if [ "${curr_pids}" != "0" ]; then | ||
echo "WARN: ${curr_pids} tasks remaining in ${INFEASIBLE_CGRP}" | ||
fi | ||
|
||
curr_pids=$(cat "${MINIMAL_CGRP}/pids.current") | ||
if [ "${curr_pids}" != "0" ]; then | ||
echo "WARN: ${curr_pids} tasks remaining in ${MINIMAL_CGRP}" | ||
fi | ||
} | ||
|
||
# _term - Catch SIGINT and forward to the children so we can exit the script | ||
# cleanly. | ||
function _term() { | ||
echo "Caught SIGINT signal" | ||
kill -s SIGINT "${infeas_pid}" | ||
kill -s SIGINT "${feas_pid}" | ||
} | ||
|
||
# Create the infeasible and minimal cgroups | ||
create_cgrp "${INFEASIBLE_CGRP}" | ||
create_cgrp "${MINIMAL_CGRP}" | ||
|
||
# The pids of the stress-ng processes we'll create | ||
infeas_pid="" | ||
feas_pid="" | ||
stressng_pid="" | ||
|
||
# Forward sigint so we can exit the script | ||
trap _term SIGINT | ||
|
||
# Move the script into a cgroup before spawning children. The children are | ||
# placed into whatever cgroup the parent is in, so this avoids any possible | ||
# races with stress-ng fork() / exec()'ing children after we move stress-ng | ||
# itself. | ||
|
||
# First the infeasible group | ||
move_into_cgrp "${INFEASIBLE_CGRP}" "$$" | ||
invoke_stressng 2 | ||
infeas_pid=${stressng_pid} | ||
|
||
# Then feasible | ||
move_into_cgrp "${INFEASIBLE_CGRP}" "${infeas_pid}" | ||
move_into_cgrp "${MINIMAL_CGRP}" "$$" | ||
invoke_stressng $(nproc) | ||
feas_pid=${stressng_pid} | ||
move_into_cgrp "${MINIMAL_CGRP}" "${feas_pid}" | ||
|
||
# Done spawning + moving around. Let's let things run until we send a SIGINT | ||
echo "success" | ||
wait ${infeas_pid} | ||
echo "${infeas_pid} exited" | ||
wait ${feas_pid} | ||
echo "${feas_pid} exited" | ||
cleanup |