From: Ziyang Men <ziyang.meme@gmail.com>
To: Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Andrii Nakryiko <andrii@kernel.org>,
Eduard Zingerman <eddyz87@gmail.com>,
Kumar Kartikeya Dwivedi <memxor@gmail.com>,
bpf@vger.kernel.org
Cc: Martin KaFai Lau <martin.lau@linux.dev>,
Song Liu <song@kernel.org>,
Yonghong Song <yonghong.song@linux.dev>,
Jiri Olsa <jolsa@kernel.org>,
Emil Tsalapatis <emil@etsalapatis.com>,
Shuah Khan <shuah@kernel.org>,
Roman Gushchin <roman.gushchin@linux.dev>,
kernel-team@meta.com, linux-mm@kvack.org,
cgroups@vger.kernel.org, linux-kselftest@vger.kernel.org,
linux-kernel@vger.kernel.org, Ziyang Men <ziyang.meme@gmail.com>,
Shakeel Butt <shakeel.butt@linux.dev>
Subject: [PATCH 0/3] selftests/bpf: compare BPF and memory.stat memcg stat readers
Date: Fri, 3 Jul 2026 21:56:14 -0700 [thread overview]
Message-ID: <20260704045617.487664-1-ziyang.meme@gmail.com> (raw)
Dear reviewers,
This is my first attempt at contributing to the Linux kernel. I am doing
an internship at Meta on the Linux team, and have recently been learning
the basics of the memory controller (cgroup v2) and BPF. I find these
topics really interesting; to help other beginners like me understand
how BPF is used, and to make a small contribution to this great
community, I wrote a few self-tests that compare two ways of reading
memory-cgroup statistics for a whole cgroup subtree:
(A) the traditional path: open, read and parse memory.stat (plus
memory.current / memory.max) for every cgroup from user space; and
(B) a BPF path: a single SEC("iter.s/cgroup") program walked over the
subtree that calls the memcg kfuncs (bpf_get_mem_cgroup,
bpf_mem_cgroup_flush_stats, bpf_mem_cgroup_page_state,
bpf_mem_cgroup_vm_events, bpf_put_mem_cgroup) for each cgroup and
stores the results in a hash map, drained once afterwards.
The series builds on the memcg BPF kfuncs (mm/bpf_memcontrol.c). When those
kfuncs are unavailable (for example CONFIG_MEMCG=n) the tests skip cleanly
rather than failing to load.
These tests may also be useful as a small, self-contained comparison of the
BPF cgroup iterator against the file-based interface across cgroup trees of
different sizes and under different load. The pass/fail result of every test
depends only on the correctness / structural checks; the timing tables are
informational and are printed only under -v (or when a test fails), never on
a normal PASS.
The patches are:
1/3 memcg_stat_reader - reads a quiescent (charged once) subtree both
ways, asserts that the BPF snapshot agrees with memory.stat for the
anon counter (which is rstat-flushed and deterministic), and reports
the wall-clock cost of each path. It also adds a small
read_cgroup_file() helper to cgroup_helpers (the read counterpart of
write_cgroup_file) and selects CONFIG_MEMCG=y in the base selftest
config.
2/3 memcg_stat_churn - runs the same comparison while the tree is under
continuous allocation churn (one busy mmap()/memset()/munmap() process
per selected leaf), so each read pays a realistic rstat flush. It
reuses the BPF program and map from patch 1 verbatim; only the
user-space load model and sampling loop are new. Pass/fail is
structural only. This is a closer simulation of real-world
workloads than the first test.
3/3 memcg_stat_churn_percpu - extends the churn test to make the
per-cgroup cross-CPU rstat flush fan-out an explicit knob: each
churner migrates across K CPUs, so a cgroup's statistics become dirty
on K CPUs and a reader's flush must visit K per-cpu trees for it. This
shows how the cost of the two readers changes as that fan-out grows.
In my testing (a 60-CPU VM) the BPF path is roughly an order of magnitude
faster than the per-cgroup memory.stat parse for a whole-tree scan, mainly
because it avoids the per-cgroup open/read and string parsing. The gap
narrows as the rstat flush that both paths share grows larger, for example
when a cgroup's statistics are dirty on many CPUs at once. The exact numbers
are included in each patch's changelog.
I used AI tools in part to help me understand these subsystems and to help
write the code. I have reviewed all of the code myself.
I would be very grateful for any feedback, and I apologise in advance for
anything I have gotten wrong. Thank you for taking the time to look at this.
Have a good day!
Suggested-by: Shakeel Butt <shakeel.butt@linux.dev>
Signed-off-by: Ziyang Men <ziyang.meme@gmail.com>
Ziyang Men (3):
selftests/bpf: add memcg_stat_reader BPF-vs-memory.stat benchmark
selftests/bpf: add memcg_stat_churn BPF-vs-memory.stat benchmark under
churn
selftests/bpf: add memcg_stat_churn_percpu BPF-vs-memory.stat
benchmark under cross-CPU churn
tools/testing/selftests/bpf/cgroup_helpers.c | 46 +
tools/testing/selftests/bpf/cgroup_helpers.h | 2 +
tools/testing/selftests/bpf/config | 1 +
.../testing/selftests/bpf/memcg_stat_reader.h | 35 +
.../bpf/prog_tests/memcg_stat_churn.c | 716 ++++++++++++++
.../bpf/prog_tests/memcg_stat_churn_percpu.c | 902 ++++++++++++++++++
.../bpf/prog_tests/memcg_stat_reader.c | 617 ++++++++++++
.../selftests/bpf/progs/memcg_stat_reader.c | 181 ++++
8 files changed, 2500 insertions(+)
create mode 100644 tools/testing/selftests/bpf/memcg_stat_reader.h
create mode 100644 tools/testing/selftests/bpf/prog_tests/memcg_stat_churn.c
create mode 100644 tools/testing/selftests/bpf/prog_tests/memcg_stat_churn_percpu.c
create mode 100644 tools/testing/selftests/bpf/prog_tests/memcg_stat_reader.c
create mode 100644 tools/testing/selftests/bpf/progs/memcg_stat_reader.c
--
2.53.0-Meta
next reply other threads:[~2026-07-04 4:56 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-04 4:56 Ziyang Men [this message]
2026-07-04 4:56 ` [PATCH 1/3] selftests/bpf: add memcg_stat_reader BPF-vs-memory.stat benchmark Ziyang Men
2026-07-04 4:56 ` [PATCH 2/3] selftests/bpf: add memcg_stat_churn BPF-vs-memory.stat benchmark under churn Ziyang Men
2026-07-04 5:39 ` bot+bpf-ci
2026-07-04 4:56 ` [PATCH 3/3] selftests/bpf: add memcg_stat_churn_percpu BPF-vs-memory.stat benchmark under cross-CPU churn Ziyang Men
2026-07-04 5:58 ` bot+bpf-ci
2026-07-07 0:17 ` [PATCH 0/3] selftests/bpf: compare BPF and memory.stat memcg stat readers Eduard Zingerman
2026-07-07 1:50 ` Shakeel Butt
2026-07-07 9:21 ` Eduard Zingerman
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=20260704045617.487664-1-ziyang.meme@gmail.com \
--to=ziyang.meme@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=cgroups@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=emil@etsalapatis.com \
--cc=jolsa@kernel.org \
--cc=kernel-team@meta.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=martin.lau@linux.dev \
--cc=memxor@gmail.com \
--cc=roman.gushchin@linux.dev \
--cc=shakeel.butt@linux.dev \
--cc=shuah@kernel.org \
--cc=song@kernel.org \
--cc=yonghong.song@linux.dev \
/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