Received: by 2002:a05:6a10:6d10:0:0:0:0 with SMTP id gq16csp931771pxb; Fri, 22 Apr 2022 14:40:05 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyPLwhETRZbFUnB2LMc90hDvEv0hejjVA2FTh+6UVDWAEtJUbrRhFhiWYyfvLbhvZ8VfmyZ X-Received: by 2002:a65:6657:0:b0:381:1b99:3f04 with SMTP id z23-20020a656657000000b003811b993f04mr5479996pgv.512.1650663605104; Fri, 22 Apr 2022 14:40:05 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1650663605; cv=none; d=google.com; s=arc-20160816; b=vlM2nKRDwcuF9W6CcUAQxfPwCUloOSDNVqtvNStAIY74P9K0V7p/SS4rTDkMX8ZHt9 VWSd8jHPyry1QlpQ9vlcLHzMYgHzr+ONhIgmTYGm4J/wzDJ9VHH1MBLlOqJNKgdrGLgG DBxi38LyL+jiWUZqDPsDmVUTeQMli1GdzJYk5qBEHCRVlL27NPltsdYzVLNCTmz8hRwJ hDqRXlRWevkvYuMduf6kvsl3KalvOT9MJ1YWqj4Odwn99UpVV6UBec2qIezUN2QVJXV4 0WCrODor4QgBbrWHurJzS4ltlAgpETrJb1BT+9EVzQUbSqqQV0bk3ct0+TeC2Gt4LitN A0Lg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=d/Ucq9GPy/+6d7dpHjxvay/RmHJPJU/gWJXLA2RvJP4=; b=r/+qW0tFUbUsMgEMbpXnN97NlVXEq2HQvy6CAN1tWwsXw5SGKc6wYZlSvgqoESZupl sqZHbSr62NUlIMYwNDaZTCS0kecqTb7FkVNighSCVF1ZSHEuMlQJvz4qhMbpeAZpQdWQ xOTg2yOO5Kc1SN4/PDeLk0C7sIDrclvJnkSBRXhSD/aLO4TGS+oJ31kaYK3dbyA6PnIT /AtqXYU+YYJmMxyQtDyJrqGnyazK58IuEzJS0PDv4tsIjTV9M5jPQ7qv/Qb/GrfZda9T NjDh8ZdudK8PoScyQfSm+8zMPK3CfhKn0ye99paW1NjUkeGPVISGk3o7issXX1Wp/X+k ZplA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net. [2620:137:e000::1:18]) by mx.google.com with ESMTPS id y21-20020a1709029b9500b001542a6e4c9bsi8584021plp.485.2022.04.22.14.40.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 Apr 2022 14:40:05 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) client-ip=2620:137:e000::1:18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 061FD3111A9; Fri, 22 Apr 2022 12:47:36 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1358021AbiDSVgB (ORCPT + 99 others); Tue, 19 Apr 2022 17:36:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60836 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1358024AbiDSVfz (ORCPT ); Tue, 19 Apr 2022 17:35:55 -0400 Received: from mail-qt1-f173.google.com (mail-qt1-f173.google.com [209.85.160.173]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 55B7037023; Tue, 19 Apr 2022 14:33:06 -0700 (PDT) Received: by mail-qt1-f173.google.com with SMTP id f22so4061948qtp.13; Tue, 19 Apr 2022 14:33:06 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=d/Ucq9GPy/+6d7dpHjxvay/RmHJPJU/gWJXLA2RvJP4=; b=f3R6/pepxyNxbeQJmifygfFFshnz/ZL8HqiMWcfrI4eJOAMjEbJHMQqLf/6zLAnqsg b2gtrTgvmZ/JBgv36nIy6A9qqR+jvSqT1RZ0bRK3MRtlqPdkHF65Bn7LT3PfrZsWo1UW 22JtaKAHVtonbwht2IbWZrRw+BojAOrr9/e98ECNOddWwhNQVM+DLa3MKCVz5/riP7cj kwV3KVCeDav06zy+dT/IAdyOxWdKALTfi1n4KvLZRybVXRFT39QE91AlQlUQRkADKh6s qtLit6Zbd7u0LTx+vAfeq2bxoUoRGyqbmmIpSPucPCHkgcdp2sItNWKp0oPkkcyA7EM+ IIHA== X-Gm-Message-State: AOAM532uGEL0ZGcmQosA2kojZqOkFTo7cUVvVjfqghLTlNIyunpVM4Ty QURgEHdU+Sf7ZJWJQjBEhYw= X-Received: by 2002:ac8:1191:0:b0:2ed:bb6:ab07 with SMTP id d17-20020ac81191000000b002ed0bb6ab07mr12064899qtj.418.1650403985357; Tue, 19 Apr 2022 14:33:05 -0700 (PDT) Received: from localhost (fwdproxy-ash-022.fbsv.net. [2a03:2880:20ff:16::face:b00c]) by smtp.gmail.com with ESMTPSA id b22-20020a05620a0f9600b0069e8ab5034dsm558131qkn.1.2022.04.19.14.33.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 19 Apr 2022 14:33:05 -0700 (PDT) From: David Vernet To: tj@kernel.org, lizefan.x@bytedance.com, hannes@cmpxchg.org, cgroups@vger.kernel.org, linux-kernel@vger.kernel.org Cc: kernel-team@fb.com Subject: [PATCH 4/4] cgroup: Add test_cgcpu_weight_underprovisioned() testcase Date: Tue, 19 Apr 2022 14:32:45 -0700 Message-Id: <20220419213244.2104972-5-void@manifault.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220419213244.2104972-1-void@manifault.com> References: <20220419213244.2104972-1-void@manifault.com> MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RDNS_NONE, SPF_HELO_NONE autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org test_cpu.c includes testcases that validate the cgroup cpu controller. This patch adds a new testcase called test_cgcpu_weight_underprovisioned() that verifies that processes with different cpu.weight that are all running on an underprovisioned system, still get roughly the same amount of cpu time. Because test_cgcpu_weight_underprovisioned() is very similar to test_cgcpu_weight_overprovisioned(), this patch also pulls the common logic into a separate helper function that is invoked from both testcases, and which uses function pointers to invoke the unique portions of the testcases. Signed-off-by: David Vernet --- tools/testing/selftests/cgroup/test_cpu.c | 149 +++++++++++++++++----- 1 file changed, 114 insertions(+), 35 deletions(-) diff --git a/tools/testing/selftests/cgroup/test_cpu.c b/tools/testing/selftests/cgroup/test_cpu.c index 2afac9f9e1e2..7adeadba88c4 100644 --- a/tools/testing/selftests/cgroup/test_cpu.c +++ b/tools/testing/selftests/cgroup/test_cpu.c @@ -19,6 +19,12 @@ enum hog_clock_type { CPU_HOG_CLOCK_WALL, }; +struct cpu_hogger { + char *cgroup; + pid_t pid; + long usage; +}; + struct cpu_hog_func_param { int nprocs; long runtime_nsec; @@ -198,31 +204,15 @@ static int test_cgcpu_stats(const char *root) return ret; } -/* - * First, this test creates the following hierarchy: - * A - * A/B cpu.weight = 50 - * A/C cpu.weight = 100 - * A/D cpu.weight = 150 - * - * A separate process is then created for each child cgroup which spawns as - * many threads as there are cores, and hogs each CPU as much as possible - * for some time interval. - * - * Once all of the children have exited, we verify that each child cgroup - * was given proportional runtime as informed by their cpu.weight. - */ -static int test_cgcpu_weight_overprovisioned(const char *root) +static int +run_cgcpu_weight_test( + const char *root, + pid_t (*spawn_child)(const struct cpu_hogger *child), + int (*validate)(const struct cpu_hogger *children, int num_children)) { - struct child { - char *cgroup; - pid_t pid; - long usage; - }; int ret = KSFT_FAIL, i; char *parent = NULL; - struct child children[3] = {NULL}; - long usage_seconds = 10; + struct cpu_hogger children[3] = {NULL}; parent = cg_name(root, "cgcpu_test_0"); if (!parent) @@ -248,13 +238,7 @@ static int test_cgcpu_weight_overprovisioned(const char *root) } for (i = 0; i < ARRAY_SIZE(children); i++) { - struct cpu_hog_func_param param = { - .nprocs = get_nprocs(), - .runtime_nsec = usage_seconds * NSEC_PER_SEC, - .clock_type = CPU_HOG_CLOCK_WALL, - }; - pid_t pid = cg_run_nowait(children[i].cgroup, hog_cpus_timed, - (void *)¶m); + pid_t pid = spawn_child(&children[i]); if (pid <= 0) goto cleanup; children[i].pid = pid; @@ -274,7 +258,43 @@ static int test_cgcpu_weight_overprovisioned(const char *root) children[i].usage = cg_read_key_long(children[i].cgroup, "cpu.stat", "usage_usec"); - for (i = 0; i < ARRAY_SIZE(children) - 1; i++) { + if (validate(children, ARRAY_SIZE(children))) + goto cleanup; + + ret = KSFT_PASS; +cleanup: + for (i = 0; i < ARRAY_SIZE(children); i++) { + cg_destroy(children[i].cgroup); + free(children[i].cgroup); + } + cg_destroy(parent); + free(parent); + + return ret; +} + +static pid_t weight_hog_ncpus(const struct cpu_hogger *child, int ncpus) +{ + long usage_seconds = 10; + struct cpu_hog_func_param param = { + .nprocs = ncpus, + .runtime_nsec = usage_seconds * NSEC_PER_SEC, + .clock_type = CPU_HOG_CLOCK_WALL, + }; + return cg_run_nowait(child->cgroup, hog_cpus_timed, (void *)¶m); +} + +static pid_t weight_hog_all_cpus(const struct cpu_hogger *child) +{ + return weight_hog_ncpus(child, get_nprocs()); +} + +static int +overprovision_validate(const struct cpu_hogger *children, int num_children) +{ + int ret = KSFT_FAIL, i; + + for (i = 0; i < num_children - 1; i++) { long delta; if (children[i + 1].usage <= children[i].usage) @@ -287,16 +307,74 @@ static int test_cgcpu_weight_overprovisioned(const char *root) ret = KSFT_PASS; cleanup: - for (i = 0; i < ARRAY_SIZE(children); i++) { - cg_destroy(children[i].cgroup); - free(children[i].cgroup); + return ret; +} + +/* + * First, this test creates the following hierarchy: + * A + * A/B cpu.weight = 50 + * A/C cpu.weight = 100 + * A/D cpu.weight = 150 + * + * A separate process is then created for each child cgroup which spawns as + * many threads as there are cores, and hogs each CPU as much as possible + * for some time interval. + * + * Once all of the children have exited, we verify that each child cgroup + * was given proportional runtime as informed by their cpu.weight. + */ +static int test_cgcpu_weight_overprovisioned(const char *root) +{ + return run_cgcpu_weight_test(root, weight_hog_all_cpus, + overprovision_validate); +} + +static pid_t weight_hog_one_cpu(const struct cpu_hogger *child) +{ + return weight_hog_ncpus(child, 1); +} + +static int +underprovision_validate(const struct cpu_hogger *children, int num_children) +{ + int ret = KSFT_FAIL, i; + + for (i = 0; i < num_children - 1; i++) { + if (!values_close(children[i + 1].usage, children[0].usage, 15)) + goto cleanup; } - cg_destroy(parent); - free(parent); + ret = KSFT_PASS; +cleanup: return ret; } +/* + * First, this test creates the following hierarchy: + * A + * A/B cpu.weight = 50 + * A/C cpu.weight = 100 + * A/D cpu.weight = 150 + * + * A separate process is then created for each child cgroup which spawns a + * single thread that hogs a CPU. The testcase is only run on systems that + * have at least one core per-thread in the child processes. + * + * Once all of the children have exited, we verify that each child cgroup + * had roughly the same runtime despite having different cpu.weight. + */ +static int test_cgcpu_weight_underprovisioned(const char *root) +{ + // Only run the test if there are enough cores to avoid overprovisioning + // the system. + if (get_nprocs() < 4) + return KSFT_SKIP; + + return run_cgcpu_weight_test(root, weight_hog_one_cpu, + underprovision_validate); +} + #define T(x) { x, #x } struct cgcpu_test { int (*fn)(const char *root); @@ -305,6 +383,7 @@ struct cgcpu_test { T(test_cgcpu_subtree_control), T(test_cgcpu_stats), T(test_cgcpu_weight_overprovisioned), + T(test_cgcpu_weight_underprovisioned), }; #undef T -- 2.30.2