From: Peter Oskolkov <posk@posk.io>
To: Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
Thomas Gleixner <tglx@linutronix.de>,
Ingo Molnar <mingo@redhat.com>, Ingo Molnar <mingo@kernel.org>,
Peter Zijlstra <peterz@infradead.org>,
Darren Hart <dvhart@infradead.org>,
Vincent Guittot <vincent.guittot@linaro.org>
Cc: Peter Oskolkov <posk@google.com>,
Andrei Vagin <avagin@google.com>, Paul Turner <pjt@google.com>,
Ben Segall <bsegall@google.com>, Aaron Lu <aaron.lwe@gmail.com>
Subject: [PATCH for 5.9 v2 3/4] futex/sched: add wake_up_swap, use in FUTEX_SWAP
Date: Mon, 3 Aug 2020 15:15:09 -0700 [thread overview]
Message-ID: <20200803221510.170674-4-posk@posk.io> (raw)
In-Reply-To: <20200803221510.170674-1-posk@posk.io>
From: Peter Oskolkov <posk@google.com>
As described in the previous patch in this patchset, it is
often beneficial to wake a task and run it on the same CPU
where the current (=going to sleep) task it running.
Internally at Google, switchto_switch sycall not only
migrates the wakee to the current CPU, but also moves
the waker's load stats to the wakee, thus ensuring
that the migration to the current CPU does not interfere
with load balancing. switchto_switch also does the
context switch into the wakee, bypassing schedule().
This patchset does not go that far yet, it simply
migrates the wakee to the current CPU and calls schedule().
In follow-up patches I will try to fune-tune the behavior by adjusting
load stats and schedule(): our internal switchto_switch
is still about 2x faster than FUTEX_SWAP (see numbers below).
And now about performance: futex_swap benchmark
from the last patch in this patchset produces this typical
output:
$ ./futex_swap -i 100000
------- running SWAP_WAKE_WAIT -----------
completed 100000 swap and back iterations in 850686650 ns: 4253 ns per swap
PASS
------- running SWAP_SWAP -----------
completed 100000 swap and back iterations in 123800593 ns: 619 ns per swap
PASS
In the above, the first benchmark (SWAP_WAKE_WAIT) calls FUTEX_WAKE,
then FUTEX_WAIT; the second benchmark (SWAP_SWAP) calls FUTEX_SWAP.
If the benchmark is restricted to a single cpu:
$ taskset -c 1 ./futex_swap -i 1000000
The numbers are very similar, as expected (with wake+wait being
a bit slower than swap due to two vs one syscalls).
Please also note that switchto_switch is about 2x faster than
FUTEX_SWAP because it does a contex switch to the wakee immediately,
bypassing schedule(), so this is one of the options I'll
explore in further patches (if/when this initial patchset is
accepted).
Tested: see the last patch is this patchset.
Signed-off-by: Peter Oskolkov <posk@google.com>
---
include/linux/sched.h | 6 ++++++
kernel/futex.c | 9 ++++-----
kernel/sched/core.c | 5 +++++
kernel/sched/fair.c | 3 +++
kernel/sched/sched.h | 1 +
5 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 060e9214c8b5..857d68fd0f8a 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1711,6 +1711,12 @@ extern int wake_up_state(struct task_struct *tsk, unsigned int state);
extern int wake_up_process(struct task_struct *tsk);
extern void wake_up_new_task(struct task_struct *tsk);
+/*
+ * Wake up tsk and try to swap it into the current tasks place, which
+ * initially means just trying to migrate it to the current CPU.
+ */
+extern int wake_up_swap(struct task_struct *tsk);
+
#ifdef CONFIG_SMP
extern void kick_process(struct task_struct *tsk);
#else
diff --git a/kernel/futex.c b/kernel/futex.c
index a81d62a16e72..3c9a7402e69e 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -2602,12 +2602,11 @@ static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q,
*/
if (!timeout || timeout->task) {
if (next) {
- /*
- * wake_up_process() below will be
- * replaced in the next patch with
- * wake_up_swap().
- */
+#ifdef CONFIG_SMP
+ wake_up_swap(next);
+#else
wake_up_process(next);
+#endif
put_task_struct(next);
next = NULL;
}
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 2142c6767682..9747bf1591ce 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -2737,6 +2737,11 @@ int wake_up_process(struct task_struct *p)
}
EXPORT_SYMBOL(wake_up_process);
+int wake_up_swap(struct task_struct *tsk)
+{
+ return try_to_wake_up(tsk, TASK_NORMAL, WF_CURRENT_CPU);
+}
+
int wake_up_state(struct task_struct *p, unsigned int state)
{
return try_to_wake_up(p, state, 0);
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 04fa8dbcfa4d..ae244d85c15e 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -6668,6 +6668,9 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_f
int want_affine = 0;
int sync = (wake_flags & WF_SYNC) && !(current->flags & PF_EXITING);
+ if ((wake_flags & WF_CURRENT_CPU) && cpumask_test_cpu(cpu, p->cpus_ptr))
+ return cpu;
+
if (sd_flag & SD_BALANCE_WAKE) {
record_wakee(p);
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 877fb08eb1b0..103f0865a590 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1683,6 +1683,7 @@ static inline int task_on_rq_migrating(struct task_struct *p)
#define WF_FORK 0x02 /* Child wakeup after fork */
#define WF_MIGRATED 0x04 /* Internal use, task got migrated */
#define WF_ON_CPU 0x08 /* Wakee is on_cpu */
+#define WF_CURRENT_CPU 0x10 /* Prefer to move wakee to the current CPU */
/*
* To aid in avoiding the subversion of "niceness" due to uneven distribution
--
2.25.1
next prev parent reply other threads:[~2020-08-03 22:15 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-08-03 22:15 [PATCH for 5.9 v2 0/4] FUTEX_SWAP (tip/locking/core) Peter Oskolkov
2020-08-03 22:15 ` [PATCH for 5.9 v2 1/4] futex: introduce FUTEX_SWAP operation Peter Oskolkov
2020-08-04 12:31 ` peterz
2020-08-11 15:26 ` Rik van Riel
2020-08-03 22:15 ` [PATCH for 5.9 v2 2/4] futex: implement FUTEX_SWAP as wake+wait Peter Oskolkov
2020-08-03 22:15 ` Peter Oskolkov [this message]
2020-08-03 22:15 ` [PATCH for 5.9 v2 4/4] selftests/futex: add futex_swap selftest Peter Oskolkov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200803221510.170674-4-posk@posk.io \
--to=posk@posk.io \
--cc=aaron.lwe@gmail.com \
--cc=avagin@google.com \
--cc=bsegall@google.com \
--cc=dvhart@infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@kernel.org \
--cc=mingo@redhat.com \
--cc=peterz@infradead.org \
--cc=pjt@google.com \
--cc=posk@google.com \
--cc=tglx@linutronix.de \
--cc=vincent.guittot@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®