1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2021 SUSE LLC <rpalethorpe@suse.com> 4f08c3bdfSopenharmony_ci * Copyright (c) Linux Test Project, 2021-2023 5f08c3bdfSopenharmony_ci */ 6f08c3bdfSopenharmony_ci 7f08c3bdfSopenharmony_ci/*\ 8f08c3bdfSopenharmony_ci * [Description] 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * Creates a multi-level CGroup hierarchy with the cpu controller 11f08c3bdfSopenharmony_ci * enabled. The leaf groups are populated with "busy" processes which 12f08c3bdfSopenharmony_ci * simulate intermittent cpu load. They spin for some time then sleep 13f08c3bdfSopenharmony_ci * then repeat. 14f08c3bdfSopenharmony_ci * 15f08c3bdfSopenharmony_ci * Both the trunk and leaf groups are set cpu bandwidth limits. The 16f08c3bdfSopenharmony_ci * busy processes will intermittently exceed these limits. Causing 17f08c3bdfSopenharmony_ci * them to be throttled. When they begin sleeping this will then cause 18f08c3bdfSopenharmony_ci * them to be unthrottle. 19f08c3bdfSopenharmony_ci * 20f08c3bdfSopenharmony_ci * The test is known to reproduce an issue with an update to 21f08c3bdfSopenharmony_ci * SLE-15-SP1 (kernel 4.12.14-197.64, 22f08c3bdfSopenharmony_ci * https://bugzilla.suse.com/show_bug.cgi?id=1179093). 23f08c3bdfSopenharmony_ci * 24f08c3bdfSopenharmony_ci * Also as an reproducer for another bug: 25f08c3bdfSopenharmony_ci * 26f08c3bdfSopenharmony_ci * commit fdaba61ef8a268d4136d0a113d153f7a89eb9984 27f08c3bdfSopenharmony_ci * Author: Rik van Riel <riel@surriel.com> 28f08c3bdfSopenharmony_ci * Date: Mon Jun 21 19:43:30 2021 +0200 29f08c3bdfSopenharmony_ci * 30f08c3bdfSopenharmony_ci * sched/fair: Ensure that the CFS parent is added after unthrottling 31f08c3bdfSopenharmony_ci */ 32f08c3bdfSopenharmony_ci 33f08c3bdfSopenharmony_ci#include <stdlib.h> 34f08c3bdfSopenharmony_ci 35f08c3bdfSopenharmony_ci#include "tst_test.h" 36f08c3bdfSopenharmony_ci#include "tst_timer.h" 37f08c3bdfSopenharmony_ci 38f08c3bdfSopenharmony_cistatic struct tst_cg_group *cg_level2, *cg_level3a, *cg_level3b; 39f08c3bdfSopenharmony_cistatic struct tst_cg_group *cg_workers[3]; 40f08c3bdfSopenharmony_cistatic int may_have_waiters = 0; 41f08c3bdfSopenharmony_ci 42f08c3bdfSopenharmony_cistatic void set_cpu_quota(const struct tst_cg_group *const cg, 43f08c3bdfSopenharmony_ci const float quota_percent) 44f08c3bdfSopenharmony_ci{ 45f08c3bdfSopenharmony_ci const unsigned int period_us = 10000; 46f08c3bdfSopenharmony_ci const unsigned int quota_us = (quota_percent / 100) * (float)period_us; 47f08c3bdfSopenharmony_ci 48f08c3bdfSopenharmony_ci if (!TST_CG_VER_IS_V1(cg, "cpu")) { 49f08c3bdfSopenharmony_ci SAFE_CG_PRINTF(cg, "cpu.max", 50f08c3bdfSopenharmony_ci "%u %u", quota_us, period_us); 51f08c3bdfSopenharmony_ci } else { 52f08c3bdfSopenharmony_ci SAFE_CG_PRINTF(cg, "cpu.cfs_period_us", 53f08c3bdfSopenharmony_ci "%u", period_us); 54f08c3bdfSopenharmony_ci SAFE_CG_PRINTF(cg, "cpu.max", 55f08c3bdfSopenharmony_ci "%u", quota_us); 56f08c3bdfSopenharmony_ci } 57f08c3bdfSopenharmony_ci 58f08c3bdfSopenharmony_ci tst_res(TINFO, "Set '%s/cpu.max' = '%d %d'", 59f08c3bdfSopenharmony_ci tst_cg_group_name(cg), quota_us, period_us); 60f08c3bdfSopenharmony_ci} 61f08c3bdfSopenharmony_ci 62f08c3bdfSopenharmony_cistatic void mk_cpu_cgroup(struct tst_cg_group **cg, 63f08c3bdfSopenharmony_ci const struct tst_cg_group *const cg_parent, 64f08c3bdfSopenharmony_ci const char *const cg_child_name, 65f08c3bdfSopenharmony_ci const float quota_percent) 66f08c3bdfSopenharmony_ci 67f08c3bdfSopenharmony_ci{ 68f08c3bdfSopenharmony_ci *cg = tst_cg_group_mk(cg_parent, "%s", cg_child_name); 69f08c3bdfSopenharmony_ci 70f08c3bdfSopenharmony_ci set_cpu_quota(*cg, quota_percent); 71f08c3bdfSopenharmony_ci} 72f08c3bdfSopenharmony_ci 73f08c3bdfSopenharmony_cistatic void busy_loop(const unsigned int sleep_ms) 74f08c3bdfSopenharmony_ci{ 75f08c3bdfSopenharmony_ci for (;;) { 76f08c3bdfSopenharmony_ci tst_timer_start(CLOCK_MONOTONIC_RAW); 77f08c3bdfSopenharmony_ci while (!tst_timer_expired_ms(20)) 78f08c3bdfSopenharmony_ci ; 79f08c3bdfSopenharmony_ci 80f08c3bdfSopenharmony_ci const int ret = tst_checkpoint_wait(0, sleep_ms); 81f08c3bdfSopenharmony_ci 82f08c3bdfSopenharmony_ci if (!ret) 83f08c3bdfSopenharmony_ci exit(0); 84f08c3bdfSopenharmony_ci 85f08c3bdfSopenharmony_ci if (errno != ETIMEDOUT) 86f08c3bdfSopenharmony_ci tst_brk(TBROK | TERRNO, "tst_checkpoint_wait"); 87f08c3bdfSopenharmony_ci } 88f08c3bdfSopenharmony_ci} 89f08c3bdfSopenharmony_ci 90f08c3bdfSopenharmony_cistatic void fork_busy_procs_in_cgroup(const struct tst_cg_group *const cg) 91f08c3bdfSopenharmony_ci{ 92f08c3bdfSopenharmony_ci const unsigned int sleeps_ms[] = {3000, 1000, 10}; 93f08c3bdfSopenharmony_ci const pid_t worker_pid = SAFE_FORK(); 94f08c3bdfSopenharmony_ci size_t i; 95f08c3bdfSopenharmony_ci 96f08c3bdfSopenharmony_ci if (worker_pid) 97f08c3bdfSopenharmony_ci return; 98f08c3bdfSopenharmony_ci 99f08c3bdfSopenharmony_ci for (i = 0; i < ARRAY_SIZE(sleeps_ms); i++) { 100f08c3bdfSopenharmony_ci const pid_t busy_pid = SAFE_FORK(); 101f08c3bdfSopenharmony_ci 102f08c3bdfSopenharmony_ci if (!busy_pid) 103f08c3bdfSopenharmony_ci busy_loop(sleeps_ms[i]); 104f08c3bdfSopenharmony_ci 105f08c3bdfSopenharmony_ci SAFE_CG_PRINTF(cg, "cgroup.procs", "%d", busy_pid); 106f08c3bdfSopenharmony_ci } 107f08c3bdfSopenharmony_ci 108f08c3bdfSopenharmony_ci tst_reap_children(); 109f08c3bdfSopenharmony_ci 110f08c3bdfSopenharmony_ci exit(0); 111f08c3bdfSopenharmony_ci} 112f08c3bdfSopenharmony_ci 113f08c3bdfSopenharmony_cistatic void do_test(void) 114f08c3bdfSopenharmony_ci{ 115f08c3bdfSopenharmony_ci size_t i; 116f08c3bdfSopenharmony_ci 117f08c3bdfSopenharmony_ci may_have_waiters = 1; 118f08c3bdfSopenharmony_ci for (i = 0; i < ARRAY_SIZE(cg_workers); i++) 119f08c3bdfSopenharmony_ci fork_busy_procs_in_cgroup(cg_workers[i]); 120f08c3bdfSopenharmony_ci 121f08c3bdfSopenharmony_ci tst_res(TPASS, "Scheduled bandwidth constrained workers"); 122f08c3bdfSopenharmony_ci 123f08c3bdfSopenharmony_ci sleep(1); 124f08c3bdfSopenharmony_ci 125f08c3bdfSopenharmony_ci set_cpu_quota(cg_level2, 50); 126f08c3bdfSopenharmony_ci 127f08c3bdfSopenharmony_ci sleep(2); 128f08c3bdfSopenharmony_ci 129f08c3bdfSopenharmony_ci TST_CHECKPOINT_WAKE2(0, 3 * 3); 130f08c3bdfSopenharmony_ci tst_reap_children(); 131f08c3bdfSopenharmony_ci may_have_waiters = 0; 132f08c3bdfSopenharmony_ci 133f08c3bdfSopenharmony_ci tst_res(TPASS, "Workers exited"); 134f08c3bdfSopenharmony_ci} 135f08c3bdfSopenharmony_ci 136f08c3bdfSopenharmony_cistatic void setup(void) 137f08c3bdfSopenharmony_ci{ 138f08c3bdfSopenharmony_ci cg_level2 = tst_cg_group_mk(tst_cg, "level2"); 139f08c3bdfSopenharmony_ci 140f08c3bdfSopenharmony_ci cg_level3a = tst_cg_group_mk(cg_level2, "level3a"); 141f08c3bdfSopenharmony_ci mk_cpu_cgroup(&cg_workers[0], cg_level3a, "worker1", 30); 142f08c3bdfSopenharmony_ci mk_cpu_cgroup(&cg_workers[1], cg_level3a, "worker2", 20); 143f08c3bdfSopenharmony_ci 144f08c3bdfSopenharmony_ci cg_level3b = tst_cg_group_mk(cg_level2, "level3b"); 145f08c3bdfSopenharmony_ci mk_cpu_cgroup(&cg_workers[2], cg_level3b, "worker3", 30); 146f08c3bdfSopenharmony_ci} 147f08c3bdfSopenharmony_ci 148f08c3bdfSopenharmony_cistatic void cleanup(void) 149f08c3bdfSopenharmony_ci{ 150f08c3bdfSopenharmony_ci size_t i; 151f08c3bdfSopenharmony_ci 152f08c3bdfSopenharmony_ci if (may_have_waiters) { 153f08c3bdfSopenharmony_ci TST_CHECKPOINT_WAKE2(0, 3 * 3); 154f08c3bdfSopenharmony_ci tst_reap_children(); 155f08c3bdfSopenharmony_ci may_have_waiters = 0; 156f08c3bdfSopenharmony_ci } 157f08c3bdfSopenharmony_ci 158f08c3bdfSopenharmony_ci for (i = 0; i < ARRAY_SIZE(cg_workers); i++) { 159f08c3bdfSopenharmony_ci if (cg_workers[i]) 160f08c3bdfSopenharmony_ci cg_workers[i] = tst_cg_group_rm(cg_workers[i]); 161f08c3bdfSopenharmony_ci } 162f08c3bdfSopenharmony_ci 163f08c3bdfSopenharmony_ci if (cg_level3a) 164f08c3bdfSopenharmony_ci cg_level3a = tst_cg_group_rm(cg_level3a); 165f08c3bdfSopenharmony_ci if (cg_level3b) 166f08c3bdfSopenharmony_ci cg_level3b = tst_cg_group_rm(cg_level3b); 167f08c3bdfSopenharmony_ci if (cg_level2) 168f08c3bdfSopenharmony_ci cg_level2 = tst_cg_group_rm(cg_level2); 169f08c3bdfSopenharmony_ci} 170f08c3bdfSopenharmony_ci 171f08c3bdfSopenharmony_cistatic struct tst_test test = { 172f08c3bdfSopenharmony_ci .test_all = do_test, 173f08c3bdfSopenharmony_ci .setup = setup, 174f08c3bdfSopenharmony_ci .cleanup = cleanup, 175f08c3bdfSopenharmony_ci .forks_child = 1, 176f08c3bdfSopenharmony_ci .needs_checkpoints = 1, 177f08c3bdfSopenharmony_ci .max_runtime = 20, 178f08c3bdfSopenharmony_ci .taint_check = TST_TAINT_W | TST_TAINT_D, 179f08c3bdfSopenharmony_ci .needs_kconfigs = (const char *[]) { 180f08c3bdfSopenharmony_ci "CONFIG_CFS_BANDWIDTH", 181f08c3bdfSopenharmony_ci NULL 182f08c3bdfSopenharmony_ci }, 183f08c3bdfSopenharmony_ci .needs_cgroup_ctrls = (const char *const []){"cpu", NULL}, 184f08c3bdfSopenharmony_ci .tags = (const struct tst_tag[]) { 185f08c3bdfSopenharmony_ci {"linux-git", "39f23ce07b93"}, 186f08c3bdfSopenharmony_ci {"linux-git", "b34cb07dde7c"}, 187f08c3bdfSopenharmony_ci {"linux-git", "fe61468b2cbc"}, 188f08c3bdfSopenharmony_ci {"linux-git", "5ab297bab984"}, 189f08c3bdfSopenharmony_ci {"linux-git", "6d4d22468dae"}, 190f08c3bdfSopenharmony_ci {"linux-git", "fdaba61ef8a2"}, 191f08c3bdfSopenharmony_ci { } 192f08c3bdfSopenharmony_ci } 193f08c3bdfSopenharmony_ci}; 194