From: Kunwu Chan <kunwu.chan@gmail.com>
To: Ravi Jonnalagadda <ravis.opensrc@gmail.com>
Cc: Kunwu Chan <kunwu.chan@gmail.com>, SJ Park <sj@kernel.org>,
Andrew Morton <akpm@linux-foundation.org>,
damon@lists.linux.dev, linux-mm@kvack.org,
linux-kernel@vger.kernel.org, Gregory Price <gourry@gourry.net>,
David Rientjes <rientjes@google.com>, Wei Xu <weixugc@google.com>,
Jonathan Corbet <corbet@lwn.net>,
Bijan Tabatabai <bijan311@gmail.com>,
Ajay Joshi <ajayjoshi@micron.com>,
Honggyu Kim <honggyu.kim@sk.com>,
Yunjeong Mun <yunjeong.mun@sk.com>,
Akinobu Mita <akinobu.mita@gmail.com>,
Lian Wang <lianux.mm@gmail.com>,
Kunwu Chan <kunwu.chan@linux.dev>,
Jonathan Cameron <jic23@kernel.org>
Subject: Re: [RFC PATCH v3 2/9] mm/damon/core: replace the access report buffer with per-context rings
Date: Sun, 4 Oct 2026 17:10:21 +0800 [thread overview]
Message-ID: <20261004091023.630362-1-kunwu.chan@gmail.com> (raw)
In-Reply-To: <20261003-damon-perf-rfc-v3-send-2026-10-03-v3-2-0f00417b41bc@gmail.com>
On Sat, 03 Oct 2026 14:07:55 -0700 Ravi Jonnalagadda <ravis.opensrc@gmail.com> wrote:
[...]
>
> @@ -2519,30 +2662,107 @@ int damos_walk(struct damon_ctx *ctx, struct damos_walk_control *control)
> * damon_report_access() - Report identified access events to DAMON.
> * @report: The reporting access information.
> *
> - * Report access events to DAMON.
> + * Report access events to DAMON via a per-context per-CPU SPSC lockless ring
> + * (ctx->perf_rings). Producer is the local CPU (typically NMI from a
> + * hardware-sampling backend); consumer is the kdamond drain in
> + * kdamond_check_reported_accesses().
> + *
> + * The destination ring is selected by this_cpu_ptr(), i.e. by the CPU calling
> + * this function, not by @report->cpu, which is sample metadata used by the
> + * drain-side filter. The two coincide for a sample delivered by an interrupt
> + * on the CPU that produced it.
> + *
> + * A backend whose PMU writes a record stream into a memory buffer instead of
> + * raising a per-sample interrupt, or one reading a device counter table, must
> + * therefore decode CPU N's buffer on CPU N -- for example by queueing per-CPU
> + * work with queue_work_on() -- rather than calling this function in a loop
> + * from one thread. A single-thread loop puts every report in that thread's
> + * ring, which caps machine-wide capacity at DAMON_REPORT_RING_SIZE - 1
> + * reports per drain regardless of the number of producing CPUs, and does not
> + * satisfy the single-producer invariant if the thread can migrate.
> + *
> + * Context: any (NMI-safe). An NMI nesting on top of a process-context
> + * producer on the same CPU would otherwise stomp the same entries[head]
> + * slot; the busy guard detects and drops in that case.
> *
> - * Context: May sleep.
> + * If the ring is full, the sample is dropped and the per-CPU ring-full
> + * counter incremented; a busy-guard drop increments the busy-drop counter.
> *
> - * NOTE: we may be able to implement this as a lockless queue, and allow any
> - * context. As the overhead is unknown, and region-based DAMON logics would
> - * guarantee the reports would be not made that frequently, let's start with
> - * this simple implementation.
> + * Return: true if the report was queued, false if it was dropped. A producer
> + * holding a single report may ignore this. A producer decoding a batch out
> + * of a hardware buffer should stop on false and leave the remainder in that
> + * buffer for the next round, since a report released from the buffer but not
> + * queued here is not delivered.
> */
> -void damon_report_access(struct damon_access_report *report)
> +bool damon_report_access(struct damon_access_report *report)
> {
> - struct damon_access_report *dst;
> + /*
> + * Only perf-event reports (probe_idx >= 1) have a ring to feed: the
> + * global page_fault ring this dispatch also fed has been removed.
> + * A probe_idx == DAMON_PROBE_IDX_NONE report has nowhere to go and is
> + * dropped here rather than at each caller.
> + */
> + struct damon_report_ring *ring;
> + cpumask_t *pending;
> + int __percpu *busy_pcpu;
> + unsigned int head, next;
> + int busy;
> + bool queued = false;
> + struct damon_ctx *pctx = report->ctx;
> +
> + if (report->probe_idx == DAMON_PROBE_IDX_NONE)
> + return false;
>
> - /* silently fail for races */
> - if (!mutex_trylock(&damon_access_reports_lock))
> - return;
> - dst = &damon_access_reports[damon_access_reports_len++];
> - /* just drop all existing reports in favor of simplicity. */
> - if (damon_access_reports_len == DAMON_ACCESS_REPORTS_CAP)
> - damon_access_reports_len = 0;
> - *dst = *report;
> - dst->report_jiffies = jiffies;
> - mutex_unlock(&damon_access_reports_lock);
> + /*
> + * A perf report must carry its owning ctx (set by the overflow handler)
> + * and that ctx must have an allocated per-ctx perf ring. If either is
> + * missing (e.g. an overflow racing teardown after the ring was freed, or
> + * a report raised before the ring was allocated), drop the sample rather
> + * than touch NULL/freed storage.
> + */
> + if (!pctx || !pctx->perf_rings || !pctx->perf_ring_busy)
> + return false;
> +
> + /* Pin to a CPU so the SPSC invariant holds for preemptible callers. */
> + preempt_disable();
> + busy_pcpu = pctx->perf_ring_busy;
> + busy = this_cpu_inc_return(*busy_pcpu);
> + if (busy != 1) {
> + /* NMI nested on a process-context producer; drop. */
> + this_cpu_inc(damon_report_busy_drop_perf);
> + goto out;
> + }
> +
> + ring = this_cpu_ptr(pctx->perf_rings);
> + pending = &pctx->perf_pending;
> + head = ring->head;
> + next = (head + 1) & DAMON_REPORT_RING_MASK;
> +
> + if (next == READ_ONCE(ring->tail)) {
> + this_cpu_inc(damon_report_ring_full_perf);
> + goto out;
> + }
> +
Hi Ravi,
I noticed that ring overflow drops reports and updates an
internal counter.
Since hardware sampling is used as an access observation source,
could userspace get any indication that reports were lost during
an aggregation window?
Without such visibility, users cannot distinguish an aggregation
result affected by report loss from one collected without loss.
This may make it difficult to evaluate the reliability of the
observed access information.
Thanks,
Kunwu
[...]
Sent using hkml (https://github.com/sjp38/hackermail)
next prev parent reply other threads:[~2026-10-04 9:10 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-03 21:07 [RFC PATCH v3 0/9] mm/damon: hardware-sampled access reports Ravi Jonnalagadda
2026-10-03 21:07 ` [RFC PATCH v3 1/9] mm/damon/paddr: remove page_fault access check primitive Ravi Jonnalagadda
2026-10-03 21:07 ` [RFC PATCH v3 2/9] mm/damon/core: replace the access report buffer with per-context rings Ravi Jonnalagadda
2026-10-04 8:30 ` Kunwu Chan
2026-10-05 9:09 ` Ravi Jonnalagadda
2026-10-04 9:10 ` Kunwu Chan [this message]
2026-10-05 9:11 ` Ravi Jonnalagadda
2026-10-03 21:07 ` [RFC PATCH v3 3/9] mm/damon: add perf-event overflow handler feeding the report ring Ravi Jonnalagadda
2026-10-03 21:07 ` [RFC PATCH v3 4/9] mm/damon/ops-common: use probe-weighted score when probe weights are set Ravi Jonnalagadda
2026-10-03 21:07 ` [RFC PATCH v3 5/9] mm/damon: add perf_event prep type, core lifecycle, and PMU arm/disarm Ravi Jonnalagadda
2026-10-03 21:07 ` [RFC PATCH v3 6/9] mm/damon/sysfs: expose perf_event prep attributes Ravi Jonnalagadda
2026-10-03 21:08 ` [RFC PATCH v3 7/9] mm/damon/tests/drain-kunit: kunit for report rings and ring drain Ravi Jonnalagadda
2026-10-03 21:08 ` [RFC PATCH v3 8/9] mm/damon/core: cap the region merge threshold per target Ravi Jonnalagadda
2026-10-03 21:08 ` [RFC PATCH v3 9/9] mm/damon/core: allow both primitives disabled when a perf probe is present Ravi Jonnalagadda
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=20261004091023.630362-1-kunwu.chan@gmail.com \
--to=kunwu.chan@gmail.com \
--cc=ajayjoshi@micron.com \
--cc=akinobu.mita@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=bijan311@gmail.com \
--cc=corbet@lwn.net \
--cc=damon@lists.linux.dev \
--cc=gourry@gourry.net \
--cc=honggyu.kim@sk.com \
--cc=jic23@kernel.org \
--cc=kunwu.chan@linux.dev \
--cc=lianux.mm@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=ravis.opensrc@gmail.com \
--cc=rientjes@google.com \
--cc=sj@kernel.org \
--cc=weixugc@google.com \
--cc=yunjeong.mun@sk.com \
/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®