Message ID | 20231220001856.3710363-18-jstultz@google.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel+bounces-6153-ouuuleilei=gmail.com@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7300:24d3:b0:fb:cd0c:d3e with SMTP id r19csp2324369dyi; Tue, 19 Dec 2023 16:24:26 -0800 (PST) X-Google-Smtp-Source: AGHT+IH2szhQnQamoksCcalpMxXVlK8nBOhfF65Z+mTOfJOmQS8ZKNdIOzyMX0IBJ47VdxsFiQFW X-Received: by 2002:a05:6808:120c:b0:3b8:b063:505e with SMTP id a12-20020a056808120c00b003b8b063505emr22807429oil.95.1703031866688; Tue, 19 Dec 2023 16:24:26 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1703031866; cv=none; d=google.com; s=arc-20160816; b=NNxfSkz6yf8Nj7BcwlcJBoC26YxXfNpLAC7dWHt6Zvp9jmIhJIfK/8BLfrVMkOxICM 0Yy21Jku1MJlIwgtfeL9mV03YdTp224WDipK55ieEiyQDXJCSl80XxL21KgHO2F8LMTt gxuwx35wY8Ryd8ItiRtFcOdOvYnKhKMfsu+poUhAb1/0K3oQwBFlKaKKScdSTidUKfaL bymEpWHabkX48dFlYbDQLHqrrzbK7qrQ3zHe0cGbMveq7vpCyluXR8ZlexfC2GT1p77i ndWWQReqP0+280Vx6HNMP7lPsc4+NjpERt9mubvkMhxbGPUSSMrkn4dB7VmD1fq+emEL Aa1Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:cc:to:from:subject:message-id:references :mime-version:list-unsubscribe:list-subscribe:list-id:precedence :in-reply-to:date:dkim-signature; bh=AIfyyqU8vvkBxzT4xph+dm2KvcH+GhhY/2ZmCVqXntI=; fh=lq1k4m46TqOToIb7rHC/F2KmHTJTjmaV9sS3Am9W7nA=; b=0eGig8GVr2RhdHF67bwiQiOS+ZLYT1ug6Iz1x9Ebgi9BpoA+AqRbbB3S2Bmqkymt/F X7jvuPEutzZfOisCYYBfLxh4xPXm+RgC+X2rTPQ19VnxIgJCCUQENIgxhQC/U6CNZ6Jk dLC9iVtGRW5rZx9tPNRskGDv+4NG94BTTi/YRjDhWiGy25Xp6Xt7eC4aigACocOCvLrd fCR6hwVJnEPNSoIX4/ADnORxxINKlI1C9kK6rODlwcaob2TeFeK7uDXBLcZMd+pip+2h NtJZahY5A0G/1BBHsFNy0lg1YruXZbhz3Ao6ncoMsD7Ga1gZu17bz9EW5PZ4N+0ty8ir UZ9w== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20230601 header.b=umVrC99g; spf=pass (google.com: domain of linux-kernel+bounces-6153-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45e3:2400::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-6153-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from sv.mirrors.kernel.org (sv.mirrors.kernel.org. [2604:1380:45e3:2400::1]) by mx.google.com with ESMTPS id oa16-20020a17090b1bd000b0028bb8de1428si1992019pjb.128.2023.12.19.16.24.26 for <ouuuleilei@gmail.com> (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 19 Dec 2023 16:24:26 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-6153-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45e3:2400::1 as permitted sender) client-ip=2604:1380:45e3:2400::1; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20230601 header.b=umVrC99g; spf=pass (google.com: domain of linux-kernel+bounces-6153-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45e3:2400::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-6153-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.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 sv.mirrors.kernel.org (Postfix) with ESMTPS id 25AD828847B for <ouuuleilei@gmail.com>; Wed, 20 Dec 2023 00:24:15 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 5017E21106; Wed, 20 Dec 2023 00:19:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="umVrC99g" X-Original-To: linux-kernel@vger.kernel.org Received: from mail-yw1-f201.google.com (mail-yw1-f201.google.com [209.85.128.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 95372200D5 for <linux-kernel@vger.kernel.org>; Wed, 20 Dec 2023 00:19:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--jstultz.bounces.google.com Received: by mail-yw1-f201.google.com with SMTP id 00721157ae682-5e73bd9079eso32578577b3.2 for <linux-kernel@vger.kernel.org>; Tue, 19 Dec 2023 16:19:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1703031572; x=1703636372; darn=vger.kernel.org; h=content-transfer-encoding:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:from:to:cc:subject:date:message-id :reply-to; bh=AIfyyqU8vvkBxzT4xph+dm2KvcH+GhhY/2ZmCVqXntI=; b=umVrC99gRoJhtjuT9Sr4qw/c6e1DLGzxutQKK5qOnxrXllsSXpXpOoA2UTVmAlqguj gyaNfHIrmyHWLONVtHRsNQKDJXulTbLVt7RHDCv3YSY+OgPu+4UeGXXM5alTZtsYp5xC WkuxSh6Vl6D+IkGLzG1m1yTHKs0AoEyQR94zrvJFIShEXdQ08bWpQg/wMQP87Ngru5vt QPJ/dGfucl8QV+1ThB4XHceWwhAUZ+CSHtQpJ7mbGCaw939xvSQ4/n2lWSxxNKzfXKgI ZL6HxUnRDsLOK2H4ur0IuUwjR2YVtL5UXCyOz7k+Vry/ZUzmF0DtZMp+oCtBV2DhMIEx DBDQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1703031572; x=1703636372; h=content-transfer-encoding:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:x-gm-message-state:from:to:cc:subject :date:message-id:reply-to; bh=AIfyyqU8vvkBxzT4xph+dm2KvcH+GhhY/2ZmCVqXntI=; b=plgU+p4OW9YSJtcZDuFFQzuZJbU/we6lJwaiB9vwQiRoHWlreqsCmAEi/Aa4B57ROC ZNqcBH00rKaPVXKT6BYDjcx5a/yZPe8LoB4Se4gTmm0ns6y19YwKVhFhWlbnLBInGAJq 9MWmStOpAN5oKF67vTmR5hMS7ot0k+ydOw2oGmjqVOFm2onbMonvR2QYlpEW6dHNrW0c hP5UCYhARmKoyQVeodP1CuwGWTchfHx9pffYpwNoBC1aRYJG35tb05sDphUBnqqZSxBu YO/acuXD5ojz9w8XOwcssFzbi7RM8D9INRpY5CDqK4hejCOUVJ+PAEWnIrObzR85P+58 4Fyg== X-Gm-Message-State: AOJu0Yyuw/YWSTKLd9rrxQJUH5+jQdpAVHuVnjaTcLeDpJWDgg1x5nWa uX8aFRF2uPXnF7IGb2nfXrtGV12we56sG/ejQGmFlmcFnhn48/vpcmMAV07ddvSCH5hbAILh95x egTCs1EyzIj7AvNUe0mZog7TrKvsTw/GnDy+SlATtL2RhCRlSaDX/NvsBr0j6mHZ9ptrG9O4= X-Received: from jstultz-noogler2.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:600]) (user=jstultz job=sendgmr) by 2002:a05:690c:4491:b0:5e8:3e57:6900 with SMTP id gr17-20020a05690c449100b005e83e576900mr423186ywb.1.1703031572518; Tue, 19 Dec 2023 16:19:32 -0800 (PST) Date: Tue, 19 Dec 2023 16:18:28 -0800 In-Reply-To: <20231220001856.3710363-1-jstultz@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: <linux-kernel.vger.kernel.org> List-Subscribe: <mailto:linux-kernel+subscribe@vger.kernel.org> List-Unsubscribe: <mailto:linux-kernel+unsubscribe@vger.kernel.org> Mime-Version: 1.0 References: <20231220001856.3710363-1-jstultz@google.com> X-Mailer: git-send-email 2.43.0.472.g3155946c3a-goog Message-ID: <20231220001856.3710363-18-jstultz@google.com> Subject: [PATCH v7 17/23] sched: Initial sched_football test implementation From: John Stultz <jstultz@google.com> To: LKML <linux-kernel@vger.kernel.org> Cc: John Stultz <jstultz@google.com>, Joel Fernandes <joelaf@google.com>, Qais Yousef <qyousef@google.com>, Ingo Molnar <mingo@redhat.com>, Peter Zijlstra <peterz@infradead.org>, Juri Lelli <juri.lelli@redhat.com>, Vincent Guittot <vincent.guittot@linaro.org>, Dietmar Eggemann <dietmar.eggemann@arm.com>, Valentin Schneider <vschneid@redhat.com>, Steven Rostedt <rostedt@goodmis.org>, Ben Segall <bsegall@google.com>, Zimuzo Ezeozue <zezeozue@google.com>, Youssef Esmat <youssefesmat@google.com>, Mel Gorman <mgorman@suse.de>, Daniel Bristot de Oliveira <bristot@redhat.com>, Will Deacon <will@kernel.org>, Waiman Long <longman@redhat.com>, Boqun Feng <boqun.feng@gmail.com>, "Paul E. McKenney" <paulmck@kernel.org>, Metin Kaya <Metin.Kaya@arm.com>, Xuewen Yan <xuewen.yan94@gmail.com>, K Prateek Nayak <kprateek.nayak@amd.com>, Thomas Gleixner <tglx@linutronix.de>, kernel-team@android.com Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1785758342650347186 X-GMAIL-MSGID: 1785758342650347186 |
Series |
Proxy Execution: A generalized form of Priority Inheritance v7
|
|
Commit Message
John Stultz
Dec. 20, 2023, 12:18 a.m. UTC
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
Cc: Joel Fernandes <joelaf@google.com>
Cc: Qais Yousef <qyousef@google.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>
Cc: Valentin Schneider <vschneid@redhat.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Ben Segall <bsegall@google.com>
Cc: Zimuzo Ezeozue <zezeozue@google.com>
Cc: Youssef Esmat <youssefesmat@google.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Daniel Bristot de Oliveira <bristot@redhat.com>
Cc: Will Deacon <will@kernel.org>
Cc: Waiman Long <longman@redhat.com>
Cc: Boqun Feng <boqun.feng@gmail.com>
Cc: "Paul E. McKenney" <paulmck@kernel.org>
Cc: Metin Kaya <Metin.Kaya@arm.com>
Cc: Xuewen Yan <xuewen.yan94@gmail.com>
Cc: K Prateek Nayak <kprateek.nayak@amd.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: kernel-team@android.com
Signed-off-by: John Stultz <jstultz@google.com>
---
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
Comments
Hi John, On 12/19/23 16:18, 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 > > Cc: kernel-team@android.com > Signed-off-by: John Stultz <jstultz@google.com> > --- > 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/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 > + * medium priority, which constantly are trying to increment the > + * ball_pos counter. > + * > + * Blocking this, are N defensive players that are higher no comma ^ > + * priority which just spin on the cpu, preventing the medium > + * priroity tasks from running. > + * > + * To complicate this, there are also N defensive low priority > + * tasks. These start first and each aquire one of N mutexes. acquire > + * The high priority defense tasks will later try to grab the > + * mutexes and block, opening a window for the offsensive tasks offensive > + * 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 <jstultz@google.com> > + */ > + > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/kthread.h> > +#include <linux/delay.h> > +#include <linux/sched/rt.h> > +#include <linux/spinlock.h> > +#include <linux/mutex.h> > +#include <linux/rwsem.h> > +#include <linux/smp.h> > +#include <linux/slab.h> > +#include <linux/interrupt.h> > +#include <linux/sched.h> > +#include <uapi/linux/sched/types.h> > +#include <linux/rtmutex.h> > + > +atomic_t players_ready; > +atomic_t ball_pos; > +int players_per_team; > +bool game_over; > + > +struct mutex *mutex_low_list; > +struct mutex *mutex_mid_list; > + [] Is this the referee? > +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 */ > + for (i = 0; i < players_per_team; i++) > + kth = create_fifo_thread(defense_low_thread, (void *)i, > + "defese-low-thread", 2); defense > + /* 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); ditto > + /* 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); ditto > + /* 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; > +} > + > 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 INVARIANT > + tristate "RT invarient scheduling tester" invariant > + 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 invariant > + available cpus). > + > + Say Y here if you want kernel rt scheduling tests RT > + 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
On Tue, Dec 19, 2023 at 4:59 PM Randy Dunlap <rdunlap@infradead.org> wrote: > On 12/19/23 16:18, John Stultz wrote: > [] > > Is this the referee? Yea, good point. "ref" is an overloaded shorthand. Will fix. Thanks also for all the spelling corrections! Much appreciated. -john
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 <joelaf@google.com> > Cc: Qais Yousef <qyousef@google.com> > Cc: Ingo Molnar <mingo@redhat.com> > Cc: Peter Zijlstra <peterz@infradead.org> > Cc: Juri Lelli <juri.lelli@redhat.com> > Cc: Vincent Guittot <vincent.guittot@linaro.org> > Cc: Dietmar Eggemann <dietmar.eggemann@arm.com> > Cc: Valentin Schneider <vschneid@redhat.com> > Cc: Steven Rostedt <rostedt@goodmis.org> > Cc: Ben Segall <bsegall@google.com> > Cc: Zimuzo Ezeozue <zezeozue@google.com> > Cc: Youssef Esmat <youssefesmat@google.com> > Cc: Mel Gorman <mgorman@suse.de> > Cc: Daniel Bristot de Oliveira <bristot@redhat.com> > Cc: Will Deacon <will@kernel.org> > Cc: Waiman Long <longman@redhat.com> > Cc: Boqun Feng <boqun.feng@gmail.com> > Cc: "Paul E. McKenney" <paulmck@kernel.org> > Cc: Metin Kaya <Metin.Kaya@arm.com> > Cc: Xuewen Yan <xuewen.yan94@gmail.com> > Cc: K Prateek Nayak <kprateek.nayak@amd.com> > Cc: Thomas Gleixner <tglx@linutronix.de> > Cc: kernel-team@android.com > Signed-off-by: John Stultz <jstultz@google.com> > --- > 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 <jstultz@google.com> > + */ > + > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/kthread.h> > +#include <linux/delay.h> > +#include <linux/sched/rt.h> > +#include <linux/spinlock.h> > +#include <linux/mutex.h> > +#include <linux/rwsem.h> > +#include <linux/smp.h> > +#include <linux/slab.h> > +#include <linux/interrupt.h> > +#include <linux/sched.h> > +#include <uapi/linux/sched/types.h> > +#include <linux/rtmutex.h> > + > +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
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 > > Cc: Joel Fernandes <joelaf@google.com> > Cc: Qais Yousef <qyousef@google.com> > Cc: Ingo Molnar <mingo@redhat.com> > Cc: Peter Zijlstra <peterz@infradead.org> > Cc: Juri Lelli <juri.lelli@redhat.com> > Cc: Vincent Guittot <vincent.guittot@linaro.org> > Cc: Dietmar Eggemann <dietmar.eggemann@arm.com> > Cc: Valentin Schneider <vschneid@redhat.com> > Cc: Steven Rostedt <rostedt@goodmis.org> > Cc: Ben Segall <bsegall@google.com> > Cc: Zimuzo Ezeozue <zezeozue@google.com> > Cc: Youssef Esmat <youssefesmat@google.com> > Cc: Mel Gorman <mgorman@suse.de> > Cc: Daniel Bristot de Oliveira <bristot@redhat.com> > Cc: Will Deacon <will@kernel.org> > Cc: Waiman Long <longman@redhat.com> > Cc: Boqun Feng <boqun.feng@gmail.com> > Cc: "Paul E. McKenney" <paulmck@kernel.org> > Cc: Metin Kaya <Metin.Kaya@arm.com> > Cc: Xuewen Yan <xuewen.yan94@gmail.com> > Cc: K Prateek Nayak <kprateek.nayak@amd.com> > Cc: Thomas Gleixner <tglx@linutronix.de> > Cc: kernel-team@android.com > Signed-off-by: John Stultz <jstultz@google.com> > --- > 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 > + * 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. > + * > + * 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 <jstultz@google.com> > + */ > + > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/kthread.h> > +#include <linux/delay.h> > +#include <linux/sched/rt.h> > +#include <linux/spinlock.h> > +#include <linux/mutex.h> > +#include <linux/rwsem.h> > +#include <linux/smp.h> > +#include <linux/slab.h> > +#include <linux/interrupt.h> > +#include <linux/sched.h> > +#include <uapi/linux/sched/types.h> > +#include <linux/rtmutex.h> > + > +atomic_t players_ready; > +atomic_t ball_pos; > +int players_per_team; > +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__); > + 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; > +} > + > +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 *) > +{ > + 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 *) > +{ > + 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 */ > + 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); > + > + 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); Hit `modpost: missing MODULE_LICENSE() in kernel/sched/test_sched_football.o` error when I build this module. JFYI: the module does not have MODULE_NAME(), MODULE_DESCRIPTION(), MODULE_AUTHOR(), module_exit(), ... as well. > 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
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 > > Cc: Joel Fernandes <joelaf@google.com> > Cc: Qais Yousef <qyousef@google.com> > Cc: Ingo Molnar <mingo@redhat.com> > Cc: Peter Zijlstra <peterz@infradead.org> > Cc: Juri Lelli <juri.lelli@redhat.com> > Cc: Vincent Guittot <vincent.guittot@linaro.org> > Cc: Dietmar Eggemann <dietmar.eggemann@arm.com> > Cc: Valentin Schneider <vschneid@redhat.com> > Cc: Steven Rostedt <rostedt@goodmis.org> > Cc: Ben Segall <bsegall@google.com> > Cc: Zimuzo Ezeozue <zezeozue@google.com> > Cc: Youssef Esmat <youssefesmat@google.com> > Cc: Mel Gorman <mgorman@suse.de> > Cc: Daniel Bristot de Oliveira <bristot@redhat.com> > Cc: Will Deacon <will@kernel.org> > Cc: Waiman Long <longman@redhat.com> > Cc: Boqun Feng <boqun.feng@gmail.com> > Cc: "Paul E. McKenney" <paulmck@kernel.org> > Cc: Metin Kaya <Metin.Kaya@arm.com> > Cc: Xuewen Yan <xuewen.yan94@gmail.com> > Cc: K Prateek Nayak <kprateek.nayak@amd.com> > Cc: Thomas Gleixner <tglx@linutronix.de> > Cc: kernel-team@android.com > Signed-off-by: John Stultz <jstultz@google.com> > --- > 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 > + * 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. > + * > + * 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 <jstultz@google.com> > + */ > + > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/kthread.h> > +#include <linux/delay.h> > +#include <linux/sched/rt.h> > +#include <linux/spinlock.h> > +#include <linux/mutex.h> > +#include <linux/rwsem.h> > +#include <linux/smp.h> > +#include <linux/slab.h> > +#include <linux/interrupt.h> > +#include <linux/sched.h> > +#include <uapi/linux/sched/types.h> > +#include <linux/rtmutex.h> > + > +atomic_t players_ready; > +atomic_t ball_pos; > +int players_per_team; > +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__); > + 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; > +} > + > +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 *) > +{ > + 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 *) > +{ > + int count = 0; > + > + atomic_inc(&players_ready); > + while (!READ_ONCE(game_over)) { > + if (kthread_should_stop()) > + break; > + schedule(); > + udelay(1000); > + msleep(2); > + count++; @count is only increased. Is it really necessary? > + } > + 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 */ > + 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); > + > + 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; > +} * Please prepend a prefix to prints to ease capturing the module logs. * I think `rmmod test_sched_football` throws `Device or resource busy` error and fails to remove the module because of missing module_exit(). > +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
On Fri, Dec 22, 2023 at 1:32 AM Metin Kaya <metin.kaya@arm.com> wrote: > > 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? Well, we would need to use rt_mutexes for the !PROXY case to validate inheritance. But something like it could be included before PROXY lands. > > + * > > + * This is done via having N offsensive players that are > > offensive Fixed. > > + * 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 Fixed. > > +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? Fixed. > > +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? Fixed. > > + 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? It's not used, but it probably should be. At least I should be checking for the failure cases. I'll rework to fix this. > > + > > +int offense_thread(void *) > > Does this (no param name) build fine on Android env? Good point, I've only been testing this bit with qemu. I'll fix it up. > > +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`. Fixed. > > + 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. Yep. Thanks for all the suggestions! -john
On Thu, Dec 28, 2023 at 7:19 AM Metin Kaya <metin.kaya@arm.com> wrote: > On 20/12/2023 12:18 am, John Stultz wrote: > > +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); > > + > > + 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); > > Hit `modpost: missing MODULE_LICENSE() in > kernel/sched/test_sched_football.o` error when I build this module. > > JFYI: the module does not have MODULE_NAME(), MODULE_DESCRIPTION(), > MODULE_AUTHOR(), module_exit(), ... as well. Good point. I've only been using it as a built-in. Added all of those except for module_exit() for now, as I don't want it to be unloaded while the kthreads are running. thanks -john
On Thu, Dec 28, 2023 at 8:36 AM Metin Kaya <metin.kaya@arm.com> wrote: > On 20/12/2023 12:18 am, John Stultz wrote: > > +int crazy_fan_thread(void *) > > +{ > > + int count = 0; > > + > > + atomic_inc(&players_ready); > > + while (!READ_ONCE(game_over)) { > > + if (kthread_should_stop()) > > + break; > > + schedule(); > > + udelay(1000); > > + msleep(2); > > + count++; > > @count is only increased. Is it really necessary? Nope. Just remnants of earlier debug code. > > * Please prepend a prefix to prints to ease capturing the module logs. Done. > * I think `rmmod test_sched_football` throws `Device or resource busy` > error and fails to remove the module because of missing module_exit(). Yep. I'm skipping this for now, but I'll see about adding it later after I figure out the changes I need to manufacture the problematic load-balancing condition I'm worried about, as it doesn't seem to appear on its own so far. thanks -john
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 + * 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. + * + * 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 <jstultz@google.com> + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/kthread.h> +#include <linux/delay.h> +#include <linux/sched/rt.h> +#include <linux/spinlock.h> +#include <linux/mutex.h> +#include <linux/rwsem.h> +#include <linux/smp.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/sched.h> +#include <uapi/linux/sched/types.h> +#include <linux/rtmutex.h> + +atomic_t players_ready; +atomic_t ball_pos; +int players_per_team; +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__); + 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; +} + +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 *) +{ + 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 *) +{ + 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 */ + 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); + + 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