From: Andrii Nakryiko <andrii@kernel.org>
To: linux-trace-kernel@vger.kernel.org, peterz@infradead.org,
oleg@redhat.com
Cc: rostedt@goodmis.org, mhiramat@kernel.org, bpf@vger.kernel.org,
linux-kernel@vger.kernel.org, jolsa@kernel.org,
paulmck@kernel.org, willy@infradead.org, surenb@google.com,
akpm@linux-foundation.org, linux-mm@kvack.org, mjguzik@gmail.com,
brauner@kernel.org, jannh@google.com,
Andrii Nakryiko <andrii@kernel.org>
Subject: [PATCH 1/2] mm: introduce mmap_lock_speculation_{start|end}
Date: Thu, 5 Sep 2024 22:12:04 -0700 [thread overview]
Message-ID: <20240906051205.530219-2-andrii@kernel.org> (raw)
In-Reply-To: <20240906051205.530219-1-andrii@kernel.org>
From: Suren Baghdasaryan <surenb@google.com>
Add helper functions to speculatively perform operations without
read-locking mmap_lock, expecting that mmap_lock will not be
write-locked and mm is not modified from under us.
A few will-it-scale ([0]) bechmarks were run with and without the
changes in this patch on a beefy server. The test script below was used.
Most of background activity on the server was stopped, but there could
still be some sporadic sources of noise. And frankly, will-it-scale
benchmarks themselves aren't 100% noise-free and do fluctuate somewhat.
Also malloc1 benchmark was getting stuck for some reason, so it was
skipped from benchmarks. But I think it was still useful as a bit of
sanity check, but take all of them with a grain of salt.
Benchmark script:
# cat will_it_scale.sh
#!/bin/bash
set -eufo pipefail
for b in page_fault1 page_fault2 page_fault3 malloc2; do
for p in 40; do
echo BENCH $b CPU$p $(will-it-scale/${b}_threads -m -t$p -s60 | grep average)
done;
done;
Before (w/o this patch)
=======================
BENCH page_fault1 CPU40 average:5403940
BENCH page_fault2 CPU40 average:5019159
BENCH page_fault3 CPU40 average:971057
BENCH malloc2 CPU40 average:1364730680
After (w/ this patch)
=====================
BENCH page_fault1 CPU40 average:5485892
BENCH page_fault2 CPU40 average:5047923
BENCH page_fault3 CPU40 average:982953
BENCH malloc2 CPU40 average:1361339890
Results seem to be within the noise of measurements, but perhaps mm
folks might have better benchmarks to try.
[0] https://github.com/antonblanchard/will-it-scale
Suggested-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
---
include/linux/mm_types.h | 3 +++
include/linux/mmap_lock.h | 53 +++++++++++++++++++++++++++++++--------
kernel/fork.c | 3 ---
3 files changed, 46 insertions(+), 13 deletions(-)
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 485424979254..d5e3f907eea4 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -876,6 +876,9 @@ struct mm_struct {
* Roughly speaking, incrementing the sequence number is
* equivalent to releasing locks on VMAs; reading the sequence
* number can be part of taking a read lock on a VMA.
+ * Incremented every time mmap_lock is write-locked/unlocked.
+ * Initialized to 0, therefore odd values indicate mmap_lock
+ * is write-locked and even values that it's released.
*
* Can be modified under write mmap_lock using RELEASE
* semantics.
diff --git a/include/linux/mmap_lock.h b/include/linux/mmap_lock.h
index de9dc20b01ba..5410ce741d75 100644
--- a/include/linux/mmap_lock.h
+++ b/include/linux/mmap_lock.h
@@ -71,15 +71,12 @@ static inline void mmap_assert_write_locked(const struct mm_struct *mm)
}
#ifdef CONFIG_PER_VMA_LOCK
-/*
- * Drop all currently-held per-VMA locks.
- * This is called from the mmap_lock implementation directly before releasing
- * a write-locked mmap_lock (or downgrading it to read-locked).
- * This should normally NOT be called manually from other places.
- * If you want to call this manually anyway, keep in mind that this will release
- * *all* VMA write locks, including ones from further up the stack.
- */
-static inline void vma_end_write_all(struct mm_struct *mm)
+static inline void init_mm_lock_seq(struct mm_struct *mm)
+{
+ mm->mm_lock_seq = 0;
+}
+
+static inline void inc_mm_lock_seq(struct mm_struct *mm)
{
mmap_assert_write_locked(mm);
/*
@@ -91,19 +88,52 @@ static inline void vma_end_write_all(struct mm_struct *mm)
*/
smp_store_release(&mm->mm_lock_seq, mm->mm_lock_seq + 1);
}
+
+static inline bool mmap_lock_speculation_start(struct mm_struct *mm, int *seq)
+{
+ /* Pairs with RELEASE semantics in inc_mm_lock_seq(). */
+ *seq = smp_load_acquire(&mm->mm_lock_seq);
+ /* Allow speculation if mmap_lock is not write-locked */
+ return (*seq & 1) == 0;
+}
+
+static inline bool mmap_lock_speculation_end(struct mm_struct *mm, int seq)
+{
+ /* Pairs with RELEASE semantics in inc_mm_lock_seq(). */
+ return seq == smp_load_acquire(&mm->mm_lock_seq);
+}
+
#else
-static inline void vma_end_write_all(struct mm_struct *mm) {}
+static inline void init_mm_lock_seq(struct mm_struct *mm) {}
+static inline void inc_mm_lock_seq(struct mm_struct *mm) {}
+static inline bool mmap_lock_speculation_start(struct mm_struct *mm, int *seq) { return false; }
+static inline bool mmap_lock_speculation_end(struct mm_struct *mm, int seq) { return false; }
#endif
+/*
+ * Drop all currently-held per-VMA locks.
+ * This is called from the mmap_lock implementation directly before releasing
+ * a write-locked mmap_lock (or downgrading it to read-locked).
+ * This should normally NOT be called manually from other places.
+ * If you want to call this manually anyway, keep in mind that this will release
+ * *all* VMA write locks, including ones from further up the stack.
+ */
+static inline void vma_end_write_all(struct mm_struct *mm)
+{
+ inc_mm_lock_seq(mm);
+}
+
static inline void mmap_init_lock(struct mm_struct *mm)
{
init_rwsem(&mm->mmap_lock);
+ init_mm_lock_seq(mm);
}
static inline void mmap_write_lock(struct mm_struct *mm)
{
__mmap_lock_trace_start_locking(mm, true);
down_write(&mm->mmap_lock);
+ inc_mm_lock_seq(mm);
__mmap_lock_trace_acquire_returned(mm, true, true);
}
@@ -111,6 +141,7 @@ static inline void mmap_write_lock_nested(struct mm_struct *mm, int subclass)
{
__mmap_lock_trace_start_locking(mm, true);
down_write_nested(&mm->mmap_lock, subclass);
+ inc_mm_lock_seq(mm);
__mmap_lock_trace_acquire_returned(mm, true, true);
}
@@ -120,6 +151,8 @@ static inline int mmap_write_lock_killable(struct mm_struct *mm)
__mmap_lock_trace_start_locking(mm, true);
ret = down_write_killable(&mm->mmap_lock);
+ if (!ret)
+ inc_mm_lock_seq(mm);
__mmap_lock_trace_acquire_returned(mm, true, ret == 0);
return ret;
}
diff --git a/kernel/fork.c b/kernel/fork.c
index 18bdc87209d0..c44b71d354ee 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1259,9 +1259,6 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p,
seqcount_init(&mm->write_protect_seq);
mmap_init_lock(mm);
INIT_LIST_HEAD(&mm->mmlist);
-#ifdef CONFIG_PER_VMA_LOCK
- mm->mm_lock_seq = 0;
-#endif
mm_pgtables_bytes_init(mm);
mm->map_count = 0;
mm->locked_vm = 0;
--
2.43.5
next prev parent reply other threads:[~2024-09-06 5:12 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-09-06 5:12 [PATCH 0/2] uprobes,mm: speculative lockless VMA-to-uprobe lookup Andrii Nakryiko
2024-09-06 5:12 ` Andrii Nakryiko [this message]
2024-09-09 12:35 ` [PATCH 1/2] mm: introduce mmap_lock_speculation_{start|end} Jann Horn
2024-09-10 2:09 ` Suren Baghdasaryan
2024-09-10 15:31 ` Jann Horn
2024-09-11 21:34 ` Andrii Nakryiko
2024-09-11 21:48 ` Suren Baghdasaryan
2024-09-12 21:02 ` [PATCH v2 1/1] " Suren Baghdasaryan
2024-09-12 21:04 ` Suren Baghdasaryan
2024-09-12 22:19 ` Andrii Nakryiko
2024-09-12 22:24 ` Suren Baghdasaryan
2024-09-12 22:52 ` Jann Horn
2024-09-24 17:15 ` Matthew Wilcox
2024-09-24 18:00 ` Jann Horn
2024-09-06 5:12 ` [PATCH 2/2] uprobes: add speculative lockless VMA-to-inode-to-uprobe resolution Andrii Nakryiko
2024-09-08 1:22 ` Liam R. Howlett
2024-09-09 1:08 ` Andrii Nakryiko
2024-09-09 13:12 ` Jann Horn
2024-09-09 21:29 ` Andrii Nakryiko
2024-09-10 15:39 ` Jann Horn
2024-09-10 20:56 ` Andrii Nakryiko
2024-09-10 16:32 ` Suren Baghdasaryan
2024-09-10 20:58 ` Andrii Nakryiko
2024-09-12 11:17 ` Christian Brauner
2024-09-12 17:54 ` Andrii Nakryiko
2024-09-15 15:04 ` Oleg Nesterov
2024-09-17 8:19 ` Andrii Nakryiko
2024-09-10 16:06 ` [PATCH 0/2] uprobes,mm: speculative lockless VMA-to-uprobe lookup Jann Horn
2024-09-10 17:58 ` Andrii Nakryiko
2024-09-10 18:13 ` Jann Horn
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=20240906051205.530219-2-andrii@kernel.org \
--to=andrii@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=bpf@vger.kernel.org \
--cc=brauner@kernel.org \
--cc=jannh@google.com \
--cc=jolsa@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=mhiramat@kernel.org \
--cc=mjguzik@gmail.com \
--cc=oleg@redhat.com \
--cc=paulmck@kernel.org \
--cc=peterz@infradead.org \
--cc=rostedt@goodmis.org \
--cc=surenb@google.com \
--cc=willy@infradead.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.