Skip to content
This repository has been archived by the owner on Jun 18, 2024. It is now read-only.

Commit

Permalink
scx: Add infeasible weights test
Browse files Browse the repository at this point in the history
Signed-off-by: David Vernet <[email protected]>
  • Loading branch information
Byte-Lab committed Jan 19, 2024
1 parent b5cdebc commit b1305be
Show file tree
Hide file tree
Showing 3 changed files with 210 additions and 1 deletion.
6 changes: 5 additions & 1 deletion tools/testing/selftests/scx/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ override define CLEAN
rm -f *.o *.bpf.o *.bpf.skel.h *.bpf.subskel.h
rm -f $(TEST_GEN_PROGS)
rm -f runner
rm -f highpri
endef

auto-test-targets := \
Expand Down Expand Up @@ -193,7 +194,10 @@ runner: $(SCXOBJ_DIR)/runner.o $(BPFOBJ) $(testcase-targets)

TEST_GEN_PROGS := runner

all: runner
highpri: highpri.c infeasible.sh
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<

all: runner highpri

.PHONY: all clean help

Expand Down
106 changes: 106 additions & 0 deletions tools/testing/selftests/scx/highpri.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#include <errno.h>
#include <libgen.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>

#define MIN_NICENESS -20
#define MAX_NICENESS 19
static int niceness = MIN_NICENESS;

#define MAX_THREADS 1024

static const char help_fmt[] =
"A helper for creating infeasible weight conditions.\n"
"\n"
"Usage: %s [-n NICENESS] [-t NTASKS] [-h]\n"
"\n"
" -n NICENESS The niceness value to use for each thread. Must be in [-20, 19].\n"
" -t NTASKS The number of tasks to create. Must not exceed 1024.\n"
" -h Display this help and exit\n";


static volatile int done = 0;

static void handle_sigint(int sig)
{
done = 1;
}

static void *busy_spin(void *ctx)
{
uint64_t value = 0;
pid_t pid = getpid();
pthread_t tid = pthread_self();

if (!nice(niceness) && errno != 0) {
fprintf(stderr, "Failure: (%s)\n", strerror(errno));
done = 1;
return NULL;
}

while (!done) {
value++;
if (value % 10000 == 0) {
printf("%d[%lu] nice= %d\n",
pid, tid, nice(0));
}
}

return NULL;
}

int main(int argc, char **argv)
{
unsigned num_threads = 1, i;
pthread_t tids[MAX_THREADS];
int opt;

signal(SIGINT, handle_sigint);
signal(SIGTERM, handle_sigint);

while ((opt = getopt(argc, argv, "n:t:h")) != -1) {
switch (opt) {
case 'n':
niceness = strtol(optarg, NULL, 10);
break;
case 't':
num_threads = strtol(optarg, NULL, 10);
break;
default:
fprintf(stderr, help_fmt, basename(argv[0]));
return opt != 'h';
}
}

if (niceness < MIN_NICENESS || niceness > MAX_NICENESS) {
fprintf(stderr, "Invalid niceness %d, must be in [%d, %d]\n",
niceness, MIN_NICENESS, MAX_NICENESS);
fprintf(stderr, help_fmt, basename(argv[0]));
return 1;
}

if (num_threads >= MAX_THREADS) {
fprintf(stderr, "%u exceeds max threads %u\n", num_threads,
MAX_THREADS);
fprintf(stderr, help_fmt, basename(argv[0]));
return 1;
}

for (i = 0; i < num_threads; i++) {
if (pthread_create(&tids[i], NULL, busy_spin, NULL)) {
fprintf(stderr, "Failed to create thread %u\n", i);
return 1;
}
}

for (i = 0; i < num_threads; i++)
pthread_join(tids[i], NULL);

return 0;
}
99 changes: 99 additions & 0 deletions tools/testing/selftests/scx/infeasible.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#!/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_ROOT="/sys/fs/cgroup/infeasible.scope"

function cgrp_n_tasks() {
return "${curr_pids}"
}

# create_cgrp() - Create the root infeasible cgroup
function create_cgrp() {
local weight=10000

if [[ ! -d "${INFEASIBLE_CGRP_ROOT}" ]]; then
mkdir "${INFEASIBLE_CGRP_ROOT}"
echo "created root infeasible group ${INFEASIBLE_CGRP_ROOT}"
else
echo "root infeasible group ${INFEASIBLE_CGRP_ROOT} already existed"
local curr_pids=$(cat "${INFEASIBLE_CGRP_ROOT}/pids.current")
if [ "${curr_pids}" != "0" ]; then
echo "ERR: tasks found in ${INFEASIBLE_CGRP_ROOT}"
exit 1
fi
fi

echo "setting ${INFEASIBLE_CGRP_ROOT} weight to ${weight}"
echo ${weight} > "${INFEASIBLE_CGRP_ROOT}/cpu.weight"
echo "set ${INFEASIBLE_CGRP_ROOT} weight to ${weight}"
}

# spawn_tasks(ntasks) - Spawn tasks with low niceness and return the pid
function spawn_tasks() {
local ntasks=$1

if [ -z $ntasks ]; then
ntasks=$(($(nproc)/4))
fi
echo "spawning ${ntasks} tasks"
./highpri -t ${ntasks} > /tmp/highpri.out 2> /tmp/highpri.err &
local status=$?
echo "status was: ${status}"
pid=$!
echo "pid is ${pid}"
echo "spawned highpri task ${pid}"
if [ ${pid} -le 0 ]; then
echo "ERR: failed to spawned highpri tasks"
exit 1
fi
}

# Move the tasks into the infeasible cgroup
function move_into_cgrp() {
local pid=$1
local procsfile="${INFEASIBLE_CGRP_ROOT}/cgroup.procs"
local pidsfile="${INFEASIBLE_CGRP_ROOT}/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})"
}

function cleanup() {
local curr_pids=$(cat "${INFEASIBLE_CGRP_ROOT}/pids.current")
if [ "${curr_pids}" != "0" ]; then
echo "WARN: ${curr_pids} tasks remaining in ${INFEASIBLE_CGRP_ROOT}"
fi
}

function _term() {
echo "Caught SIGINT signal"
kill -s SIGINT "${pid}"
}

create_cgrp
pid=""
trap _term SIGINT
spawn_tasks
move_into_cgrp ${pid}
echo "success: waiting for ${pid} to finish"
wait ${pid}
echo "${pid} exited. cleaning up..."
cleanup

0 comments on commit b1305be

Please sign in to comment.