Received: by 2002:a05:7412:b995:b0:f9:9502:5bb8 with SMTP id it21csp680496rdb; Fri, 22 Dec 2023 01:32:33 -0800 (PST) X-Google-Smtp-Source: AGHT+IFAAFeSmJmnwq+LHZL89QvcSTUaelWLunLnEv6p9O3scvP1H2FyDijJEwaL33EGIkALhIYY X-Received: by 2002:a05:6808:1708:b0:3b9:d7a0:d15c with SMTP id bc8-20020a056808170800b003b9d7a0d15cmr869952oib.34.1703237552670; Fri, 22 Dec 2023 01:32:32 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1703237552; cv=none; d=google.com; s=arc-20160816; b=g6X7ofO0Aoxzrpx5AuG8/TAfqb8ivC5lBRH+QKsf5lLQEeGQp8lnXZQDVSvSTXODzY VayjpCxpeqt126RnF8Xa4br0ewIYZP9wR+H1RhancdhYzFd8I+Vw9TC9GFLtv3lj6OPd vI8fH1esJYSGgc7fGIrkVGGEVRYvNEaoN1KBD/Lz56D/+ZyGRBpYVbvfUaHTeG/JTmIM HezxBEL9u3H6ZXsk4hXoh4cWJE7cXXAOApB2zhiYRWHUsl7eAx3Osflnju70FWPnoKIQ Ps+i+K8Clfcc+jPAUMKD6wJU6l33wghT5Us0RItAnbxv5WM8gZdwHdN5EYeGVOpXK4l8 TWQA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:in-reply-to:from:references:cc:to :content-language:subject:user-agent:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:date:message-id; bh=H5EE6uuF32+6sJoHxXDJRdzs4kqQHjcgrJ0kJ2EkNrg=; fh=IIn5181kkf6eV43uezdjLqEXV63ArwY//WIorpexdA4=; b=j0pxqPF+w8cGzk31YAcSfMxxmz5K8Qd5ZCLZcsW1A20MJAEFC2NEjt37xVLoOU91bl LwPdpi+4G5+ElsffEtGBY8OrLu6sCjs+EqmBlVAoQx4TJZ/VMD4f2oSJRT9cDc0kbI4T hChoSp1u2DIAjx1zz2L2iqR6iI4N8fBytxaPahIoIZwOY9Ft5wFc8oR7MLz3b0isEUNf yPLtTHrY0FCXRNYS2blBO4gCEpFHv/R60cZKVwhH6cLDd8OaSl8ZNPj6Kw2u1qrWcmht 0GCBG5n5M1Wgxaa/y32px/Zc9/CNA0D92cm4V3efS9JWtRn15rhE9W8TOfiQ9JkIOnde Z/bw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel+bounces-9545-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) smtp.mailfrom="linux-kernel+bounces-9545-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=arm.com Return-Path: Received: from ny.mirrors.kernel.org (ny.mirrors.kernel.org. [147.75.199.223]) by mx.google.com with ESMTPS id x13-20020a05620a258d00b0077f6e25988asi3977035qko.61.2023.12.22.01.32.32 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 Dec 2023 01:32:32 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-9545-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) client-ip=147.75.199.223; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel+bounces-9545-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) smtp.mailfrom="linux-kernel+bounces-9545-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=arm.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ny.mirrors.kernel.org (Postfix) with ESMTPS id 5DCCB1C2406F for ; Fri, 22 Dec 2023 09:32:32 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 3DCEDF9EF; Fri, 22 Dec 2023 09:32:25 +0000 (UTC) X-Original-To: linux-kernel@vger.kernel.org Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 4DF92F9C8 for ; Fri, 22 Dec 2023 09:32:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 1F9582F4; Fri, 22 Dec 2023 01:33:00 -0800 (PST) Received: from [10.57.87.46] (unknown [10.57.87.46]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 782FD3F738; Fri, 22 Dec 2023 01:32:11 -0800 (PST) Message-ID: <4cdaca00-dc4e-4ac0-a362-56b90ca584f0@arm.com> Date: Fri, 22 Dec 2023 09:32:10 +0000 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH v7 17/23] sched: Initial sched_football test implementation Content-Language: en-US To: John Stultz , LKML Cc: Joel Fernandes , Qais Yousef , Ingo Molnar , Peter Zijlstra , Juri Lelli , Vincent Guittot , Dietmar Eggemann , Valentin Schneider , Steven Rostedt , Ben Segall , Zimuzo Ezeozue , Youssef Esmat , Mel Gorman , Daniel Bristot de Oliveira , Will Deacon , Waiman Long , Boqun Feng , "Paul E. McKenney" , Xuewen Yan , K Prateek Nayak , Thomas Gleixner , kernel-team@android.com References: <20231220001856.3710363-1-jstultz@google.com> <20231220001856.3710363-18-jstultz@google.com> From: Metin Kaya In-Reply-To: <20231220001856.3710363-18-jstultz@google.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit On 20/12/2023 12:18 am, John Stultz wrote: > Reimplementation of the sched_football test from LTP: > https://github.com/linux-test-project/ltp/blob/master/testcases/realtime/func/sched_football/sched_football.c > > But reworked to run in the kernel and utilize mutexes > to illustrate proper boosting of low priority mutex > holders. > > TODO: > * Need a rt_mutex version so it can work w/o proxy-execution > * Need a better place to put it I think also this patch can be upstreamed regardless of other Proxy Execution patches, right? > > Cc: Joel Fernandes > Cc: Qais Yousef > Cc: Ingo Molnar > Cc: Peter Zijlstra > Cc: Juri Lelli > Cc: Vincent Guittot > Cc: Dietmar Eggemann > Cc: Valentin Schneider > Cc: Steven Rostedt > Cc: Ben Segall > Cc: Zimuzo Ezeozue > Cc: Youssef Esmat > Cc: Mel Gorman > Cc: Daniel Bristot de Oliveira > Cc: Will Deacon > Cc: Waiman Long > Cc: Boqun Feng > Cc: "Paul E. McKenney" > Cc: Metin Kaya > Cc: Xuewen Yan > Cc: K Prateek Nayak > Cc: Thomas Gleixner > Cc: kernel-team@android.com > Signed-off-by: John Stultz > --- > kernel/sched/Makefile | 1 + > kernel/sched/test_sched_football.c | 242 +++++++++++++++++++++++++++++ > lib/Kconfig.debug | 14 ++ > 3 files changed, 257 insertions(+) > create mode 100644 kernel/sched/test_sched_football.c > > diff --git a/kernel/sched/Makefile b/kernel/sched/Makefile > index 976092b7bd45..2729d565dfd7 100644 > --- a/kernel/sched/Makefile > +++ b/kernel/sched/Makefile > @@ -32,3 +32,4 @@ obj-y += core.o > obj-y += fair.o > obj-y += build_policy.o > obj-y += build_utility.o > +obj-$(CONFIG_SCHED_RT_INVARIENT_TEST) += test_sched_football.o > diff --git a/kernel/sched/test_sched_football.c b/kernel/sched/test_sched_football.c > new file mode 100644 > index 000000000000..9742c45c0fe0 > --- /dev/null > +++ b/kernel/sched/test_sched_football.c > @@ -0,0 +1,242 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Module-based test case for RT scheduling invariant > + * > + * A reimplementation of my old sched_football test > + * found in LTP: > + * https://github.com/linux-test-project/ltp/blob/master/testcases/realtime/func/sched_football/sched_football.c > + * > + * Similar to that test, this tries to validate the RT > + * scheduling invariant, that the across N available cpus, the > + * top N priority tasks always running. > + * > + * This is done via having N offsensive players that are offensive > + * medium priority, which constantly are trying to increment the > + * ball_pos counter. > + * > + * Blocking this, are N defensive players that are higher > + * priority which just spin on the cpu, preventing the medium > + * priroity tasks from running. priority > + * > + * To complicate this, there are also N defensive low priority > + * tasks. These start first and each aquire one of N mutexes. > + * The high priority defense tasks will later try to grab the > + * mutexes and block, opening a window for the offsensive tasks > + * to run and increment the ball. If priority inheritance or > + * proxy execution is used, the low priority defense players > + * should be boosted to the high priority levels, and will > + * prevent the mid priority offensive tasks from running. > + * > + * Copyright © International Business Machines Corp., 2007, 2008 > + * Copyright (C) Google, 2023 > + * > + * Authors: John Stultz > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +atomic_t players_ready; > +atomic_t ball_pos; > +int players_per_team; Nit: Number of players cannot be lower than 0. Should it be unsigned then? > +bool game_over; > + > +struct mutex *mutex_low_list; > +struct mutex *mutex_mid_list; > + > +static inline > +struct task_struct *create_fifo_thread(int (*threadfn)(void *data), void *data, > + char *name, int prio) > +{ > + struct task_struct *kth; > + struct sched_attr attr = { > + .size = sizeof(struct sched_attr), > + .sched_policy = SCHED_FIFO, > + .sched_nice = 0, > + .sched_priority = prio, > + }; > + int ret; > + > + kth = kthread_create(threadfn, data, name); > + if (IS_ERR(kth)) { > + pr_warn("%s eerr, kthread_create failed\n", __func__); Extra e at eerr? > + return kth; > + } > + ret = sched_setattr_nocheck(kth, &attr); > + if (ret) { > + kthread_stop(kth); > + pr_warn("%s: failed to set SCHED_FIFO\n", __func__); > + return ERR_PTR(ret); > + } > + > + wake_up_process(kth); > + return kth; I think the result of this function is actually unused. So, create_fifo_thread()'s return type can be void? > +} > + > +int defense_low_thread(void *arg) > +{ > + long tnum = (long)arg; > + > + atomic_inc(&players_ready); > + mutex_lock(&mutex_low_list[tnum]); > + while (!READ_ONCE(game_over)) { > + if (kthread_should_stop()) > + break; > + schedule(); > + } > + mutex_unlock(&mutex_low_list[tnum]); > + return 0; > +} > + > +int defense_mid_thread(void *arg) > +{ > + long tnum = (long)arg; > + > + atomic_inc(&players_ready); > + mutex_lock(&mutex_mid_list[tnum]); > + mutex_lock(&mutex_low_list[tnum]); > + while (!READ_ONCE(game_over)) { > + if (kthread_should_stop()) > + break; > + schedule(); > + } > + mutex_unlock(&mutex_low_list[tnum]); > + mutex_unlock(&mutex_mid_list[tnum]); > + return 0; > +} > + > +int offense_thread(void *) Does this (no param name) build fine on Android env? > +{ > + atomic_inc(&players_ready); > + while (!READ_ONCE(game_over)) { > + if (kthread_should_stop()) > + break; > + schedule(); > + atomic_inc(&ball_pos); > + } > + return 0; > +} > + > +int defense_hi_thread(void *arg) > +{ > + long tnum = (long)arg; > + > + atomic_inc(&players_ready); > + mutex_lock(&mutex_mid_list[tnum]); > + while (!READ_ONCE(game_over)) { > + if (kthread_should_stop()) > + break; > + schedule(); > + } > + mutex_unlock(&mutex_mid_list[tnum]); > + return 0; > +} > + > +int crazy_fan_thread(void *) Same (no param name) question here. > +{ > + int count = 0; > + > + atomic_inc(&players_ready); > + while (!READ_ONCE(game_over)) { > + if (kthread_should_stop()) > + break; > + schedule(); > + udelay(1000); > + msleep(2); > + count++; > + } > + return 0; > +} > + > +int ref_thread(void *arg) > +{ > + struct task_struct *kth; > + long game_time = (long)arg; > + unsigned long final_pos; > + long i; > + > + pr_info("%s: started ref, game_time: %ld secs !\n", __func__, > + game_time); > + > + /* Create low priority defensive team */ Sorry: extra space after `low`. > + for (i = 0; i < players_per_team; i++) > + kth = create_fifo_thread(defense_low_thread, (void *)i, > + "defese-low-thread", 2); > + /* Wait for the defense threads to start */ > + while (atomic_read(&players_ready) < players_per_team) > + msleep(1); > + > + for (i = 0; i < players_per_team; i++) > + kth = create_fifo_thread(defense_mid_thread, > + (void *)(players_per_team - i - 1), > + "defese-mid-thread", 3); > + /* Wait for the defense threads to start */ > + while (atomic_read(&players_ready) < players_per_team * 2) > + msleep(1); > + > + /* Create mid priority offensive team */ > + for (i = 0; i < players_per_team; i++) > + kth = create_fifo_thread(offense_thread, NULL, > + "offense-thread", 5); > + /* Wait for the offense threads to start */ > + while (atomic_read(&players_ready) < players_per_team * 3) > + msleep(1); > + > + /* Create high priority defensive team */ > + for (i = 0; i < players_per_team; i++) > + kth = create_fifo_thread(defense_hi_thread, (void *)i, > + "defese-hi-thread", 10); > + /* Wait for the defense threads to start */ > + while (atomic_read(&players_ready) < players_per_team * 4) > + msleep(1); > + > + /* Create high priority defensive team */ > + for (i = 0; i < players_per_team; i++) > + kth = create_fifo_thread(crazy_fan_thread, NULL, > + "crazy-fan-thread", 15); > + /* Wait for the defense threads to start */ > + while (atomic_read(&players_ready) < players_per_team * 5) > + msleep(1); > + > + pr_info("%s: all players checked in! Starting game.\n", __func__); > + atomic_set(&ball_pos, 0); > + msleep(game_time * 1000); > + final_pos = atomic_read(&ball_pos); > + pr_info("%s: final ball_pos: %ld\n", __func__, final_pos); > + WARN_ON(final_pos != 0); > + game_over = true; > + return 0; > +} > + > +static int __init test_sched_football_init(void) > +{ > + struct task_struct *kth; > + int i; > + > + players_per_team = num_online_cpus(); > + > + mutex_low_list = kmalloc_array(players_per_team, sizeof(struct mutex), GFP_ATOMIC); > + mutex_mid_list = kmalloc_array(players_per_team, sizeof(struct mutex), GFP_ATOMIC); * Extra space after `players_per_team,`. * Shouldn't we check result of `kmalloc_array()`? Same comments for `mutex_low_list` (previous) line. > + > + for (i = 0; i < players_per_team; i++) { > + mutex_init(&mutex_low_list[i]); > + mutex_init(&mutex_mid_list[i]); > + } > + > + kth = create_fifo_thread(ref_thread, (void *)10, "ref-thread", 20); > + > + return 0; > +} > +module_init(test_sched_football_init); > diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug > index 4405f81248fb..1d90059d190f 100644 > --- a/lib/Kconfig.debug > +++ b/lib/Kconfig.debug > @@ -1238,6 +1238,20 @@ config SCHED_DEBUG > that can help debug the scheduler. The runtime overhead of this > option is minimal. > > +config SCHED_RT_INVARIENT_TEST > + tristate "RT invarient scheduling tester" > + depends on DEBUG_KERNEL > + help > + This option provides a kernel module that runs tests to make > + sure the RT invarient holds (top N priority tasks run on N > + available cpus). > + > + Say Y here if you want kernel rt scheduling tests > + to be built into the kernel. > + Say M if you want this test to build as a module. > + Say N if you are unsure. > + > + > config SCHED_INFO > bool > default n