* [PATCH 0/2] tracing: add ring-buffer memory usage statistics
@ 2026-09-05 11:27 Xiang Gao
2026-09-05 11:27 ` [PATCH 1/2] tracing: add ring-buffer memory usage statistics in tracefs Xiang Gao
` (3 more replies)
0 siblings, 4 replies; 24+ messages in thread
From: Xiang Gao @ 2026-09-05 11:27 UTC (permalink / raw)
To: Steven Rostedt
Cc: Masami Hiramatsu, Mathieu Desnoyers, Lorenzo Stoakes, gao xu,
yinchuang1, linux-trace-kernel, linux-kernel, Xiang Gao
Report the memory consumed by the tracing ring buffers, rather than the
usable data capacity exposed by buffer_size_kb. Android low-memory
diagnostics need this to attribute the memory used by tracing when
calculating lost RAM.
The buffers can be spread across the global trace array, dynamically
created instances, and snapshot buffers. Userspace currently has to
discover and sum every instance, and snapshot memory is not exposed by
the per-instance totals.
Patch 1 adds:
/sys/kernel/tracing/trace_stats/memory_usage_kb
reporting:
buffers: ...
snapshot_buffers: ...
covering the global trace array and all instances across all CPUs.
Patch 2 adds the per-CPU view under
trace_stats/per_cpu/cpuN/memory_usage_kb.
The values account for the full pages backing the data sub-buffers and
reader page, plus the cached read page and mmap metadata page when
present. Slab-allocated ring-buffer metadata is not included.
Xiang Gao (2):
tracing: add ring-buffer memory usage statistics in tracefs
tracing: add per-CPU memory usage statistics in tracefs
Documentation/trace/ftrace.rst | 15 +++++
include/linux/ring_buffer.h | 1 +
kernel/trace/ring_buffer.c | 41 +++++++++++++
kernel/trace/trace.c | 104 +++++++++++++++++++++++++++++++++
4 files changed, 161 insertions(+)
--
2.34.1
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH 1/2] tracing: add ring-buffer memory usage statistics in tracefs
2026-09-05 11:27 [PATCH 0/2] tracing: add ring-buffer memory usage statistics Xiang Gao
@ 2026-09-05 11:27 ` Xiang Gao
2026-09-05 11:38 ` sashiko-bot
2026-09-07 9:26 ` Vincent Donnefort
2026-09-05 11:27 ` [PATCH 2/2] tracing: add per-CPU " Xiang Gao
` (2 subsequent siblings)
3 siblings, 2 replies; 24+ messages in thread
From: Xiang Gao @ 2026-09-05 11:27 UTC (permalink / raw)
To: Steven Rostedt
Cc: Masami Hiramatsu, Mathieu Desnoyers, Lorenzo Stoakes, gao xu,
yinchuang1, linux-trace-kernel, linux-kernel, Xiang Gao
Report the memory consumed by the tracing ring buffers, rather than the
usable data capacity exposed by buffer_size_kb. Android low-memory
diagnostics need this to attribute the memory used by tracing when
calculating lost RAM.
The buffers can be spread across the global trace array, dynamically
created instances, and snapshot buffers. Userspace currently has to
discover and sum every instance, and snapshot memory is not exposed by
the per-instance totals.
Add a trace_stats directory with memory_usage_kb reporting:
buffers:
snapshot_buffers:
covering the global trace array and all instances across all CPUs.
The values account for the full pages backing the data sub-buffers and
reader page, plus the cached read page and mmap metadata page when
present. Slab-allocated ring-buffer metadata is not included, as it is
already reported through Slab and would be double-counted when
subtracting tracing memory from lost RAM. Range and remote buffers,
whose pages are externally owned, report zero.
Signed-off-by: Xiang Gao <gaoxiang17@xiaomi.com>
---
Documentation/trace/ftrace.rst | 12 +++++++
include/linux/ring_buffer.h | 1 +
kernel/trace/ring_buffer.c | 41 +++++++++++++++++++++++
kernel/trace/trace.c | 60 ++++++++++++++++++++++++++++++++++
4 files changed, 114 insertions(+)
diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst
index 84f06bf0da9b..ff9d604dd1b8 100644
--- a/Documentation/trace/ftrace.rst
+++ b/Documentation/trace/ftrace.rst
@@ -218,6 +218,18 @@ of ftrace. Here is a list of some of the key files:
This displays the total combined size of all the trace buffers.
+ trace_stats/memory_usage_kb:
+
+ This reports the memory consumed by the ring buffers, as opposed to
+ the usable data capacity shown by buffer_size_kb. The value covers the
+ main and snapshot buffers of the global trace array and all tracing
+ instances. It does not include slab-allocated ring-buffer metadata.
+
+ Output::
+
+ buffers: ...
+ snapshot_buffers: ...
+
buffer_subbuf_size_kb:
This sets or displays the sub buffer size. The ring buffer is broken up
diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
index 0670742b2d60..64eded40222c 100644
--- a/include/linux/ring_buffer.h
+++ b/include/linux/ring_buffer.h
@@ -166,6 +166,7 @@ int ring_buffer_iter_empty(struct ring_buffer_iter *iter);
bool ring_buffer_iter_dropped(struct ring_buffer_iter *iter);
unsigned long ring_buffer_size(struct trace_buffer *buffer, int cpu);
+unsigned long ring_buffer_memory_size(struct trace_buffer *buffer, int cpu);
unsigned long ring_buffer_max_event_size(struct trace_buffer *buffer);
void ring_buffer_reset_cpu(struct trace_buffer *buffer, int cpu);
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 8e2485bb3aa8..a8719b517798 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -6464,6 +6464,47 @@ unsigned long ring_buffer_size(struct trace_buffer *buffer, int cpu)
}
EXPORT_SYMBOL_GPL(ring_buffer_size);
+/**
+ * ring_buffer_memory_size - return the memory used by the buffer (in bytes)
+ * @buffer: The ring buffer.
+ * @cpu: The CPU to get ring buffer memory from.
+ *
+ * Returns the page-allocator memory consumed by @cpu, including the data
+ * sub-buffers, the reader page, the cached read page, and the mmap
+ * metadata page. Unlike ring_buffer_size(), which reports the usable data
+ * capacity, this accounts for the full pages allocated to the buffer.
+ * Range and remote buffers do not own page-allocator memory and report zero.
+ */
+unsigned long ring_buffer_memory_size(struct trace_buffer *buffer, int cpu)
+{
+ struct ring_buffer_per_cpu *cpu_buffer;
+ unsigned long subbuf_size;
+ unsigned long size;
+
+ if (!cpumask_test_cpu(cpu, buffer->cpumask))
+ return 0;
+
+ /* Range and remote buffers use externally owned memory. */
+ if (buffer->range_addr_start || buffer->remote)
+ return 0;
+
+ cpu_buffer = buffer->buffers[cpu];
+ subbuf_size = PAGE_SIZE << buffer->subbuf_order;
+
+ /* Data sub-buffers plus the reader page. */
+ size = (cpu_buffer->nr_pages + 1) * subbuf_size;
+
+ /* The cached read page, if present, is a full sub-buffer page. */
+ if (cpu_buffer->free_page)
+ size += subbuf_size;
+
+ /* The mmap metadata page is a single system page. */
+ if (cpu_buffer->meta_page)
+ size += PAGE_SIZE;
+
+ return size;
+}
+
/**
* ring_buffer_max_event_size - return the max data size of an event
* @buffer: The ring buffer.
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 01a5e87af299..b343e03a6cf8 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -5769,6 +5769,52 @@ tracing_total_entries_read(struct file *filp, char __user *ubuf,
return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
}
+struct trace_mem_stats {
+ unsigned long buffers;
+ unsigned long snapshot;
+};
+
+static void
+trace_array_buffer_memory(struct trace_array *tr, int cpu,
+ unsigned long *buffers, unsigned long *snapshot)
+{
+ if (tr->array_buffer.buffer)
+ *buffers += ring_buffer_memory_size(tr->array_buffer.buffer, cpu);
+
+#ifdef CONFIG_TRACER_SNAPSHOT
+ if (tr->snapshot_buffer.buffer)
+ *snapshot += ring_buffer_memory_size(tr->snapshot_buffer.buffer, cpu);
+#endif
+}
+
+static struct trace_mem_stats trace_buffers_memory(void)
+{
+ struct trace_mem_stats stats = {};
+ struct trace_array *tr;
+ int cpu;
+
+ guard(mutex)(&trace_types_lock);
+
+ list_for_each_entry(tr, &ftrace_trace_arrays, list) {
+ for_each_tracing_cpu(cpu)
+ trace_array_buffer_memory(tr, cpu, &stats.buffers,
+ &stats.snapshot);
+ }
+
+ return stats;
+}
+
+static int trace_mem_show(struct seq_file *m, void *v)
+{
+ struct trace_mem_stats stats = trace_buffers_memory();
+
+ seq_printf(m, "buffers: %lu\n", stats.buffers >> 10);
+ seq_printf(m, "snapshot_buffers: %lu\n", stats.snapshot >> 10);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(trace_mem);
+
#define LAST_BOOT_HEADER ((void *)1)
static void *l_next(struct seq_file *m, void *v, loff_t *pos)
@@ -9188,6 +9234,18 @@ static struct notifier_block trace_module_nb = {
};
#endif /* CONFIG_MODULES */
+static __init void init_trace_stats_tracefs(void)
+{
+ struct dentry *stats_dir;
+
+ stats_dir = tracefs_create_dir("trace_stats", NULL);
+ if (!stats_dir)
+ return;
+
+ trace_create_file("memory_usage_kb", TRACE_MODE_READ, stats_dir,
+ NULL, &trace_mem_fops);
+}
+
static __init void tracer_init_tracefs_work_func(struct work_struct *work)
{
@@ -9196,6 +9254,8 @@ static __init void tracer_init_tracefs_work_func(struct work_struct *work)
init_tracer_tracefs(&global_trace, NULL);
ftrace_init_tracefs_toplevel(&global_trace, NULL);
+ init_trace_stats_tracefs();
+
trace_create_file("tracing_thresh", TRACE_MODE_WRITE, NULL,
&global_trace, &tracing_thresh_fops);
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 2/2] tracing: add per-CPU memory usage statistics in tracefs
2026-09-05 11:27 [PATCH 0/2] tracing: add ring-buffer memory usage statistics Xiang Gao
2026-09-05 11:27 ` [PATCH 1/2] tracing: add ring-buffer memory usage statistics in tracefs Xiang Gao
@ 2026-09-05 11:27 ` Xiang Gao
2026-09-11 15:50 ` [PATCH v2 0/2] tracing: add ring-buffer memory usage statistics Xiang Gao
2026-09-11 17:22 ` [PATCH 0/2] tracing: add ring-buffer memory usage statistics Vincent Donnefort
3 siblings, 0 replies; 24+ messages in thread
From: Xiang Gao @ 2026-09-05 11:27 UTC (permalink / raw)
To: Steven Rostedt
Cc: Masami Hiramatsu, Mathieu Desnoyers, Lorenzo Stoakes, gao xu,
yinchuang1, linux-trace-kernel, linux-kernel, Xiang Gao
Provide a per-CPU view of the tracing ring-buffer memory usage under
trace_stats/per_cpu/cpuN/memory_usage_kb, using the same format as the
aggregate file. Each file reports only the buffers belonging to that CPU
across the global trace array and all tracing instances.
Signed-off-by: Xiang Gao <gaoxiang17@xiaomi.com>
---
Documentation/trace/ftrace.rst | 3 +++
kernel/trace/trace.c | 46 +++++++++++++++++++++++++++++++++-
2 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst
index ff9d604dd1b8..694c9ed8f241 100644
--- a/Documentation/trace/ftrace.rst
+++ b/Documentation/trace/ftrace.rst
@@ -230,6 +230,9 @@ of ftrace. Here is a list of some of the key files:
buffers: ...
snapshot_buffers: ...
+ The same file is provided under trace_stats/per_cpu/cpuN/, reporting
+ only the buffers belonging to that CPU.
+
buffer_subbuf_size_kb:
This sets or displays the sub buffer size. The ring buffer is broken up
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index b343e03a6cf8..ea05077af4a0 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -5815,6 +5815,31 @@ static int trace_mem_show(struct seq_file *m, void *v)
}
DEFINE_SHOW_ATTRIBUTE(trace_mem);
+static struct trace_mem_stats trace_buffers_memory_cpu(int cpu)
+{
+ struct trace_mem_stats stats = {};
+ struct trace_array *tr;
+
+ guard(mutex)(&trace_types_lock);
+
+ list_for_each_entry(tr, &ftrace_trace_arrays, list)
+ trace_array_buffer_memory(tr, cpu, &stats.buffers,
+ &stats.snapshot);
+
+ return stats;
+}
+
+static int trace_mem_per_cpu_show(struct seq_file *m, void *v)
+{
+ struct trace_mem_stats stats = trace_buffers_memory_cpu((long)m->private);
+
+ seq_printf(m, "buffers: %lu\n", stats.buffers >> 10);
+ seq_printf(m, "snapshot_buffers: %lu\n", stats.snapshot >> 10);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(trace_mem_per_cpu);
+
#define LAST_BOOT_HEADER ((void *)1)
static void *l_next(struct seq_file *m, void *v, loff_t *pos)
@@ -9236,7 +9261,9 @@ static struct notifier_block trace_module_nb = {
static __init void init_trace_stats_tracefs(void)
{
- struct dentry *stats_dir;
+ struct dentry *stats_dir, *per_cpu_dir, *cpu_dir;
+ char cpu_dir_name[30];
+ int cpu;
stats_dir = tracefs_create_dir("trace_stats", NULL);
if (!stats_dir)
@@ -9244,6 +9271,23 @@ static __init void init_trace_stats_tracefs(void)
trace_create_file("memory_usage_kb", TRACE_MODE_READ, stats_dir,
NULL, &trace_mem_fops);
+
+ per_cpu_dir = tracefs_create_dir("per_cpu", stats_dir);
+ if (!per_cpu_dir)
+ return;
+
+ for_each_tracing_cpu(cpu) {
+ snprintf(cpu_dir_name, 30, "cpu%d", cpu);
+ cpu_dir = tracefs_create_dir(cpu_dir_name, per_cpu_dir);
+ if (!cpu_dir) {
+ pr_warn("Could not create tracefs '%s' entry\n",
+ cpu_dir_name);
+ continue;
+ }
+
+ trace_create_file("memory_usage_kb", TRACE_MODE_READ, cpu_dir,
+ (void *)(long)cpu, &trace_mem_per_cpu_fops);
+ }
}
static __init void tracer_init_tracefs_work_func(struct work_struct *work)
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [PATCH 1/2] tracing: add ring-buffer memory usage statistics in tracefs
2026-09-05 11:27 ` [PATCH 1/2] tracing: add ring-buffer memory usage statistics in tracefs Xiang Gao
@ 2026-09-05 11:38 ` sashiko-bot
2026-09-07 9:26 ` Vincent Donnefort
1 sibling, 0 replies; 24+ messages in thread
From: sashiko-bot @ 2026-09-05 11:38 UTC (permalink / raw)
To: Xiang Gao; +Cc: linux-trace-kernel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] Compilation failure due to evaluating a struct type in a boolean context.
--
commit 59684c76ae178c23d488e6128dbc2d350cbbec1d
Author: Xiang Gao <gxxa03070307@gmail.com>
tracing: add ring-buffer memory usage statistics in tracefs
This commit adds memory consumption statistics for tracing ring buffers to
tracefs. It reports the memory consumed by the main and snapshot buffers
across all instances, tracking the full pages backing the sub-buffers.
> diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
> index 5fc009edc1ec9..4579053d34ec4 100644
> --- a/kernel/trace/ring_buffer.c
> +++ b/kernel/trace/ring_buffer.c
[ ... ]
> @@ -6526,6 +6526,47 @@ unsigned long ring_buffer_size(struct trace_buffer *buffer, int cpu)
[ ... ]
> +unsigned long ring_buffer_memory_size(struct trace_buffer *buffer, int cpu)
> +{
> + struct ring_buffer_per_cpu *cpu_buffer;
> + unsigned long subbuf_size;
> + unsigned long size;
> +
> + if (!cpumask_test_cpu(cpu, buffer->cpumask))
> + return 0;
> +
> + /* Range and remote buffers use externally owned memory. */
> + if (buffer->range_addr_start || buffer->remote)
> + return 0;
> +
> + cpu_buffer = buffer->buffers[cpu];
> + subbuf_size = PAGE_SIZE << buffer->subbuf_order;
> +
> + /* Data sub-buffers plus the reader page. */
> + size = (cpu_buffer->nr_pages + 1) * subbuf_size;
> +
> + /* The cached read page, if present, is a full sub-buffer page. */
> + if (cpu_buffer->free_page)
[Severity: Low]
Does this code cause a compilation failure?
The free_page member of struct ring_buffer_per_cpu is an embedded struct
(struct buffer_data_read_page), rather than a pointer. Evaluating it
directly in a boolean context will cause a compiler error because a scalar
value is required.
Should this condition check a field within the struct instead, such as
cpu_buffer->free_page.data?
> + size += subbuf_size;
> +
> + /* The mmap metadata page is a single system page. */
> + if (cpu_buffer->meta_page)
> + size += PAGE_SIZE;
> +
> + return size;
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260905112732.3705405-1-gaoxiang17@xiaomi.com?part=1
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 1/2] tracing: add ring-buffer memory usage statistics in tracefs
2026-09-05 11:27 ` [PATCH 1/2] tracing: add ring-buffer memory usage statistics in tracefs Xiang Gao
2026-09-05 11:38 ` sashiko-bot
@ 2026-09-07 9:26 ` Vincent Donnefort
1 sibling, 0 replies; 24+ messages in thread
From: Vincent Donnefort @ 2026-09-07 9:26 UTC (permalink / raw)
To: Xiang Gao
Cc: Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Lorenzo Stoakes, gao xu, yinchuang1, linux-trace-kernel,
linux-kernel, Xiang Gao
On Sat, Sep 05, 2026 at 07:27:31PM +0800, Xiang Gao wrote:
> Report the memory consumed by the tracing ring buffers, rather than the
> usable data capacity exposed by buffer_size_kb. Android low-memory
> diagnostics need this to attribute the memory used by tracing when
> calculating lost RAM.
>
> The buffers can be spread across the global trace array, dynamically
> created instances, and snapshot buffers. Userspace currently has to
> discover and sum every instance, and snapshot memory is not exposed by
> the per-instance totals.
>
> Add a trace_stats directory with memory_usage_kb reporting:
>
> buffers:
> snapshot_buffers:
>
> covering the global trace array and all instances across all CPUs.
>
> The values account for the full pages backing the data sub-buffers and
> reader page, plus the cached read page and mmap metadata page when
> present. Slab-allocated ring-buffer metadata is not included, as it is
> already reported through Slab and would be double-counted when
> subtracting tracing memory from lost RAM. Range and remote buffers,
> whose pages are externally owned, report zero.
>
> Signed-off-by: Xiang Gao <gaoxiang17@xiaomi.com>
> ---
> Documentation/trace/ftrace.rst | 12 +++++++
> include/linux/ring_buffer.h | 1 +
> kernel/trace/ring_buffer.c | 41 +++++++++++++++++++++++
> kernel/trace/trace.c | 60 ++++++++++++++++++++++++++++++++++
> 4 files changed, 114 insertions(+)
>
> diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst
> index 84f06bf0da9b..ff9d604dd1b8 100644
> --- a/Documentation/trace/ftrace.rst
> +++ b/Documentation/trace/ftrace.rst
> @@ -218,6 +218,18 @@ of ftrace. Here is a list of some of the key files:
>
> This displays the total combined size of all the trace buffers.
>
> + trace_stats/memory_usage_kb:
> +
> + This reports the memory consumed by the ring buffers, as opposed to
> + the usable data capacity shown by buffer_size_kb. The value covers the
> + main and snapshot buffers of the global trace array and all tracing
> + instances. It does not include slab-allocated ring-buffer metadata.
> +
> + Output::
> +
> + buffers: ...
> + snapshot_buffers: ...
> +
> buffer_subbuf_size_kb:
>
> This sets or displays the sub buffer size. The ring buffer is broken up
> diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
> index 0670742b2d60..64eded40222c 100644
> --- a/include/linux/ring_buffer.h
> +++ b/include/linux/ring_buffer.h
> @@ -166,6 +166,7 @@ int ring_buffer_iter_empty(struct ring_buffer_iter *iter);
> bool ring_buffer_iter_dropped(struct ring_buffer_iter *iter);
>
> unsigned long ring_buffer_size(struct trace_buffer *buffer, int cpu);
> +unsigned long ring_buffer_memory_size(struct trace_buffer *buffer, int cpu);
> unsigned long ring_buffer_max_event_size(struct trace_buffer *buffer);
>
> void ring_buffer_reset_cpu(struct trace_buffer *buffer, int cpu);
> diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
> index 8e2485bb3aa8..a8719b517798 100644
> --- a/kernel/trace/ring_buffer.c
> +++ b/kernel/trace/ring_buffer.c
> @@ -6464,6 +6464,47 @@ unsigned long ring_buffer_size(struct trace_buffer *buffer, int cpu)
> }
> EXPORT_SYMBOL_GPL(ring_buffer_size);
>
> +/**
> + * ring_buffer_memory_size - return the memory used by the buffer (in bytes)
> + * @buffer: The ring buffer.
> + * @cpu: The CPU to get ring buffer memory from.
> + *
> + * Returns the page-allocator memory consumed by @cpu, including the data
> + * sub-buffers, the reader page, the cached read page, and the mmap
> + * metadata page. Unlike ring_buffer_size(), which reports the usable data
> + * capacity, this accounts for the full pages allocated to the buffer.
> + * Range and remote buffers do not own page-allocator memory and report zero.
> + */
> +unsigned long ring_buffer_memory_size(struct trace_buffer *buffer, int cpu)
> +{
> + struct ring_buffer_per_cpu *cpu_buffer;
> + unsigned long subbuf_size;
> + unsigned long size;
> +
> + if (!cpumask_test_cpu(cpu, buffer->cpumask))
> + return 0;
> +
> + /* Range and remote buffers use externally owned memory. */
> + if (buffer->range_addr_start || buffer->remote)
> + return 0;
Hum, why not including that? This is still memory immobilised for tracing.
(notice though remote buffers wouldn't appear in ftrace_trace_arrays)
> +
> + cpu_buffer = buffer->buffers[cpu];
> + subbuf_size = PAGE_SIZE << buffer->subbuf_order;
READ_ONCE(buffer->subbuf_order);
> +
> + /* Data sub-buffers plus the reader page. */
> + size = (cpu_buffer->nr_pages + 1) * subbuf_size;
> +
> + /* The cached read page, if present, is a full sub-buffer page. */
> + if (cpu_buffer->free_page)
> + size += subbuf_size;
> +
> + /* The mmap metadata page is a single system page. */
> + if (cpu_buffer->meta_page)
> + size += PAGE_SIZE;
> +
> + return size;
> +}
> +
> /**
> * ring_buffer_max_event_size - return the max data size of an event
> * @buffer: The ring buffer.
> diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
> index 01a5e87af299..b343e03a6cf8 100644
> --- a/kernel/trace/trace.c
> +++ b/kernel/trace/trace.c
> @@ -5769,6 +5769,52 @@ tracing_total_entries_read(struct file *filp, char __user *ubuf,
> return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
> }
>
> +struct trace_mem_stats {
> + unsigned long buffers;
> + unsigned long snapshot;
> +};
> +
> +static void
> +trace_array_buffer_memory(struct trace_array *tr, int cpu,
> + unsigned long *buffers, unsigned long *snapshot)
> +{
> + if (tr->array_buffer.buffer)
> + *buffers += ring_buffer_memory_size(tr->array_buffer.buffer, cpu);
> +
> +#ifdef CONFIG_TRACER_SNAPSHOT
> + if (tr->snapshot_buffer.buffer)
> + *snapshot += ring_buffer_memory_size(tr->snapshot_buffer.buffer, cpu);
> +#endif
> +}
> +
> +static struct trace_mem_stats trace_buffers_memory(void)
> +{
> + struct trace_mem_stats stats = {};
> + struct trace_array *tr;
> + int cpu;
> +
> + guard(mutex)(&trace_types_lock);
> +
> + list_for_each_entry(tr, &ftrace_trace_arrays, list) {
> + for_each_tracing_cpu(cpu)
> + trace_array_buffer_memory(tr, cpu, &stats.buffers,
> + &stats.snapshot);
> + }
> +
> + return stats;
> +}
> +
> +static int trace_mem_show(struct seq_file *m, void *v)
> +{
> + struct trace_mem_stats stats = trace_buffers_memory();
> +
> + seq_printf(m, "buffers: %lu\n", stats.buffers >> 10);
> + seq_printf(m, "snapshot_buffers: %lu\n", stats.snapshot >> 10);
> +
> + return 0;
> +}
> +DEFINE_SHOW_ATTRIBUTE(trace_mem);
> +
> #define LAST_BOOT_HEADER ((void *)1)
>
> static void *l_next(struct seq_file *m, void *v, loff_t *pos)
> @@ -9188,6 +9234,18 @@ static struct notifier_block trace_module_nb = {
> };
> #endif /* CONFIG_MODULES */
>
> +static __init void init_trace_stats_tracefs(void)
> +{
> + struct dentry *stats_dir;
> +
> + stats_dir = tracefs_create_dir("trace_stats", NULL);
> + if (!stats_dir)
> + return;
> +
> + trace_create_file("memory_usage_kb", TRACE_MODE_READ, stats_dir,
> + NULL, &trace_mem_fops);
> +}
> +
> static __init void tracer_init_tracefs_work_func(struct work_struct *work)
> {
>
> @@ -9196,6 +9254,8 @@ static __init void tracer_init_tracefs_work_func(struct work_struct *work)
> init_tracer_tracefs(&global_trace, NULL);
> ftrace_init_tracefs_toplevel(&global_trace, NULL);
>
> + init_trace_stats_tracefs();
> +
> trace_create_file("tracing_thresh", TRACE_MODE_WRITE, NULL,
> &global_trace, &tracing_thresh_fops);
>
> --
> 2.34.1
>
>
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 0/2] tracing: add ring-buffer memory usage statistics
2026-09-05 11:27 [PATCH 0/2] tracing: add ring-buffer memory usage statistics Xiang Gao
2026-09-05 11:27 ` [PATCH 1/2] tracing: add ring-buffer memory usage statistics in tracefs Xiang Gao
2026-09-05 11:27 ` [PATCH 2/2] tracing: add per-CPU " Xiang Gao
@ 2026-09-11 15:50 ` Xiang Gao
2026-09-11 15:50 ` [PATCH v2 1/2] tracing: add ring-buffer memory usage statistics in tracefs Xiang Gao
` (2 more replies)
2026-09-11 17:22 ` [PATCH 0/2] tracing: add ring-buffer memory usage statistics Vincent Donnefort
3 siblings, 3 replies; 24+ messages in thread
From: Xiang Gao @ 2026-09-11 15:50 UTC (permalink / raw)
To: Steven Rostedt, Vincent Donnefort
Cc: Masami Hiramatsu, Mathieu Desnoyers, Lorenzo Stoakes, gao xu,
yinchuang1, linux-trace-kernel, linux-kernel, Xiang Gao
Report the memory consumed by the tracing ring buffers, rather than the
usable data capacity exposed by buffer_size_kb. Android low-memory
diagnostics need this to attribute the memory used by tracing when
calculating lost RAM.
The buffers can be spread across the global trace array, dynamically
created instances, and snapshot buffers. Userspace currently has to
discover and sum every instance, and snapshot memory is not exposed by
the per-instance totals.
Patch 1 adds:
/sys/kernel/tracing/trace_stats/memory_usage_kb
reporting:
buffers: ...
snapshot_buffers: ...
covering the global trace array and all instances across all CPUs.
Patch 2 adds the per-CPU view under
trace_stats/per_cpu/cpuN/memory_usage_kb.
The values account for the full pages backing the data sub-buffers and
reader page, plus the cached read page and mmap metadata page when
present. Slab-allocated ring-buffer metadata is not included.
Changes since v1:
- Include range buffers in the accounting (Vincent Donnefort).
- Use READ_ONCE() for buffer->subbuf_order (Vincent Donnefort).
- Keep remote buffers excluded.
Xiang Gao (2):
tracing: add ring-buffer memory usage statistics in tracefs
tracing: add per-CPU memory usage statistics in tracefs
Documentation/trace/ftrace.rst | 15 +++++
include/linux/ring_buffer.h | 1 +
kernel/trace/ring_buffer.c | 41 +++++++++++++
kernel/trace/trace.c | 104 +++++++++++++++++++++++++++++++++
4 files changed, 161 insertions(+)
--
2.34.1
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 1/2] tracing: add ring-buffer memory usage statistics in tracefs
2026-09-11 15:50 ` [PATCH v2 0/2] tracing: add ring-buffer memory usage statistics Xiang Gao
@ 2026-09-11 15:50 ` Xiang Gao
2026-09-11 16:04 ` sashiko-bot
2026-09-13 16:37 ` Donggeun Yoo
2026-09-11 15:50 ` [PATCH v2 2/2] tracing: add per-CPU " Xiang Gao
2026-09-16 6:33 ` [PATCH v3 0/2] tracing: add ring-buffer memory usage statistics Xiang Gao
2 siblings, 2 replies; 24+ messages in thread
From: Xiang Gao @ 2026-09-11 15:50 UTC (permalink / raw)
To: Steven Rostedt, Vincent Donnefort
Cc: Masami Hiramatsu, Mathieu Desnoyers, Lorenzo Stoakes, gao xu,
yinchuang1, linux-trace-kernel, linux-kernel, Xiang Gao
Report the memory consumed by the tracing ring buffers, rather than the
usable data capacity exposed by buffer_size_kb. Android low-memory
diagnostics need this to attribute the memory used by tracing when
calculating lost RAM.
The buffers can be spread across the global trace array, dynamically
created instances, and snapshot buffers. Userspace currently has to
discover and sum every instance, and snapshot memory is not exposed by
the per-instance totals.
Add a trace_stats directory with memory_usage_kb reporting:
buffers:
snapshot_buffers:
covering the global trace array and all instances across all CPUs.
The values account for the full pages backing the data sub-buffers and
reader page, plus the cached read page and mmap metadata page when
present. Slab-allocated ring-buffer metadata is not included, as it is
already reported through Slab and would be double-counted when
subtracting tracing memory from lost RAM. Remote buffers, whose pages
are externally owned, report zero.
Signed-off-by: Xiang Gao <gaoxiang17@xiaomi.com>
---
Documentation/trace/ftrace.rst | 12 +++++++
include/linux/ring_buffer.h | 1 +
kernel/trace/ring_buffer.c | 41 +++++++++++++++++++++++
kernel/trace/trace.c | 60 ++++++++++++++++++++++++++++++++++
4 files changed, 114 insertions(+)
diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst
index 84f06bf0da9b..ff9d604dd1b8 100644
--- a/Documentation/trace/ftrace.rst
+++ b/Documentation/trace/ftrace.rst
@@ -218,6 +218,18 @@ of ftrace. Here is a list of some of the key files:
This displays the total combined size of all the trace buffers.
+ trace_stats/memory_usage_kb:
+
+ This reports the memory consumed by the ring buffers, as opposed to
+ the usable data capacity shown by buffer_size_kb. The value covers the
+ main and snapshot buffers of the global trace array and all tracing
+ instances. It does not include slab-allocated ring-buffer metadata.
+
+ Output::
+
+ buffers: ...
+ snapshot_buffers: ...
+
buffer_subbuf_size_kb:
This sets or displays the sub buffer size. The ring buffer is broken up
diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
index 0670742b2d60..64eded40222c 100644
--- a/include/linux/ring_buffer.h
+++ b/include/linux/ring_buffer.h
@@ -166,6 +166,7 @@ int ring_buffer_iter_empty(struct ring_buffer_iter *iter);
bool ring_buffer_iter_dropped(struct ring_buffer_iter *iter);
unsigned long ring_buffer_size(struct trace_buffer *buffer, int cpu);
+unsigned long ring_buffer_memory_size(struct trace_buffer *buffer, int cpu);
unsigned long ring_buffer_max_event_size(struct trace_buffer *buffer);
void ring_buffer_reset_cpu(struct trace_buffer *buffer, int cpu);
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 8e2485bb3aa8..292af4807c70 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -6464,6 +6464,47 @@ unsigned long ring_buffer_size(struct trace_buffer *buffer, int cpu)
}
EXPORT_SYMBOL_GPL(ring_buffer_size);
+/**
+ * ring_buffer_memory_size - return the memory used by the buffer (in bytes)
+ * @buffer: The ring buffer.
+ * @cpu: The CPU to get ring buffer memory from.
+ *
+ * Returns the page-allocator memory consumed by @cpu, including the data
+ * sub-buffers, the reader page, the cached read page, and the mmap
+ * metadata page. Unlike ring_buffer_size(), which reports the usable data
+ * capacity, this accounts for the full pages allocated to the buffer.
+ * Remote buffers do not own page-allocator memory and report zero.
+ */
+unsigned long ring_buffer_memory_size(struct trace_buffer *buffer, int cpu)
+{
+ struct ring_buffer_per_cpu *cpu_buffer;
+ unsigned long subbuf_size;
+ unsigned long size;
+
+ if (!cpumask_test_cpu(cpu, buffer->cpumask))
+ return 0;
+
+ /* Remote buffers use externally owned memory. */
+ if (buffer->remote)
+ return 0;
+
+ cpu_buffer = buffer->buffers[cpu];
+ subbuf_size = PAGE_SIZE << READ_ONCE(buffer->subbuf_order);
+
+ /* Data sub-buffers plus the reader page. */
+ size = (cpu_buffer->nr_pages + 1) * subbuf_size;
+
+ /* The cached read page, if present, is a full sub-buffer page. */
+ if (cpu_buffer->free_page)
+ size += subbuf_size;
+
+ /* The mmap metadata page is a single system page. */
+ if (cpu_buffer->meta_page)
+ size += PAGE_SIZE;
+
+ return size;
+}
+
/**
* ring_buffer_max_event_size - return the max data size of an event
* @buffer: The ring buffer.
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 01a5e87af299..b343e03a6cf8 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -5769,6 +5769,52 @@ tracing_total_entries_read(struct file *filp, char __user *ubuf,
return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
}
+struct trace_mem_stats {
+ unsigned long buffers;
+ unsigned long snapshot;
+};
+
+static void
+trace_array_buffer_memory(struct trace_array *tr, int cpu,
+ unsigned long *buffers, unsigned long *snapshot)
+{
+ if (tr->array_buffer.buffer)
+ *buffers += ring_buffer_memory_size(tr->array_buffer.buffer, cpu);
+
+#ifdef CONFIG_TRACER_SNAPSHOT
+ if (tr->snapshot_buffer.buffer)
+ *snapshot += ring_buffer_memory_size(tr->snapshot_buffer.buffer, cpu);
+#endif
+}
+
+static struct trace_mem_stats trace_buffers_memory(void)
+{
+ struct trace_mem_stats stats = {};
+ struct trace_array *tr;
+ int cpu;
+
+ guard(mutex)(&trace_types_lock);
+
+ list_for_each_entry(tr, &ftrace_trace_arrays, list) {
+ for_each_tracing_cpu(cpu)
+ trace_array_buffer_memory(tr, cpu, &stats.buffers,
+ &stats.snapshot);
+ }
+
+ return stats;
+}
+
+static int trace_mem_show(struct seq_file *m, void *v)
+{
+ struct trace_mem_stats stats = trace_buffers_memory();
+
+ seq_printf(m, "buffers: %lu\n", stats.buffers >> 10);
+ seq_printf(m, "snapshot_buffers: %lu\n", stats.snapshot >> 10);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(trace_mem);
+
#define LAST_BOOT_HEADER ((void *)1)
static void *l_next(struct seq_file *m, void *v, loff_t *pos)
@@ -9188,6 +9234,18 @@ static struct notifier_block trace_module_nb = {
};
#endif /* CONFIG_MODULES */
+static __init void init_trace_stats_tracefs(void)
+{
+ struct dentry *stats_dir;
+
+ stats_dir = tracefs_create_dir("trace_stats", NULL);
+ if (!stats_dir)
+ return;
+
+ trace_create_file("memory_usage_kb", TRACE_MODE_READ, stats_dir,
+ NULL, &trace_mem_fops);
+}
+
static __init void tracer_init_tracefs_work_func(struct work_struct *work)
{
@@ -9196,6 +9254,8 @@ static __init void tracer_init_tracefs_work_func(struct work_struct *work)
init_tracer_tracefs(&global_trace, NULL);
ftrace_init_tracefs_toplevel(&global_trace, NULL);
+ init_trace_stats_tracefs();
+
trace_create_file("tracing_thresh", TRACE_MODE_WRITE, NULL,
&global_trace, &tracing_thresh_fops);
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH v2 2/2] tracing: add per-CPU memory usage statistics in tracefs
2026-09-11 15:50 ` [PATCH v2 0/2] tracing: add ring-buffer memory usage statistics Xiang Gao
2026-09-11 15:50 ` [PATCH v2 1/2] tracing: add ring-buffer memory usage statistics in tracefs Xiang Gao
@ 2026-09-11 15:50 ` Xiang Gao
2026-09-16 6:33 ` [PATCH v3 0/2] tracing: add ring-buffer memory usage statistics Xiang Gao
2 siblings, 0 replies; 24+ messages in thread
From: Xiang Gao @ 2026-09-11 15:50 UTC (permalink / raw)
To: Steven Rostedt, Vincent Donnefort
Cc: Masami Hiramatsu, Mathieu Desnoyers, Lorenzo Stoakes, gao xu,
yinchuang1, linux-trace-kernel, linux-kernel, Xiang Gao
Provide a per-CPU view of the tracing ring-buffer memory usage under
trace_stats/per_cpu/cpuN/memory_usage_kb, using the same format as the
aggregate file. Each file reports only the buffers belonging to that CPU
across the global trace array and all tracing instances.
Signed-off-by: Xiang Gao <gaoxiang17@xiaomi.com>
---
Documentation/trace/ftrace.rst | 3 +++
kernel/trace/trace.c | 46 +++++++++++++++++++++++++++++++++-
2 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst
index ff9d604dd1b8..694c9ed8f241 100644
--- a/Documentation/trace/ftrace.rst
+++ b/Documentation/trace/ftrace.rst
@@ -230,6 +230,9 @@ of ftrace. Here is a list of some of the key files:
buffers: ...
snapshot_buffers: ...
+ The same file is provided under trace_stats/per_cpu/cpuN/, reporting
+ only the buffers belonging to that CPU.
+
buffer_subbuf_size_kb:
This sets or displays the sub buffer size. The ring buffer is broken up
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index b343e03a6cf8..ea05077af4a0 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -5815,6 +5815,31 @@ static int trace_mem_show(struct seq_file *m, void *v)
}
DEFINE_SHOW_ATTRIBUTE(trace_mem);
+static struct trace_mem_stats trace_buffers_memory_cpu(int cpu)
+{
+ struct trace_mem_stats stats = {};
+ struct trace_array *tr;
+
+ guard(mutex)(&trace_types_lock);
+
+ list_for_each_entry(tr, &ftrace_trace_arrays, list)
+ trace_array_buffer_memory(tr, cpu, &stats.buffers,
+ &stats.snapshot);
+
+ return stats;
+}
+
+static int trace_mem_per_cpu_show(struct seq_file *m, void *v)
+{
+ struct trace_mem_stats stats = trace_buffers_memory_cpu((long)m->private);
+
+ seq_printf(m, "buffers: %lu\n", stats.buffers >> 10);
+ seq_printf(m, "snapshot_buffers: %lu\n", stats.snapshot >> 10);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(trace_mem_per_cpu);
+
#define LAST_BOOT_HEADER ((void *)1)
static void *l_next(struct seq_file *m, void *v, loff_t *pos)
@@ -9236,7 +9261,9 @@ static struct notifier_block trace_module_nb = {
static __init void init_trace_stats_tracefs(void)
{
- struct dentry *stats_dir;
+ struct dentry *stats_dir, *per_cpu_dir, *cpu_dir;
+ char cpu_dir_name[30];
+ int cpu;
stats_dir = tracefs_create_dir("trace_stats", NULL);
if (!stats_dir)
@@ -9244,6 +9271,23 @@ static __init void init_trace_stats_tracefs(void)
trace_create_file("memory_usage_kb", TRACE_MODE_READ, stats_dir,
NULL, &trace_mem_fops);
+
+ per_cpu_dir = tracefs_create_dir("per_cpu", stats_dir);
+ if (!per_cpu_dir)
+ return;
+
+ for_each_tracing_cpu(cpu) {
+ snprintf(cpu_dir_name, 30, "cpu%d", cpu);
+ cpu_dir = tracefs_create_dir(cpu_dir_name, per_cpu_dir);
+ if (!cpu_dir) {
+ pr_warn("Could not create tracefs '%s' entry\n",
+ cpu_dir_name);
+ continue;
+ }
+
+ trace_create_file("memory_usage_kb", TRACE_MODE_READ, cpu_dir,
+ (void *)(long)cpu, &trace_mem_per_cpu_fops);
+ }
}
static __init void tracer_init_tracefs_work_func(struct work_struct *work)
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [PATCH v2 1/2] tracing: add ring-buffer memory usage statistics in tracefs
2026-09-11 15:50 ` [PATCH v2 1/2] tracing: add ring-buffer memory usage statistics in tracefs Xiang Gao
@ 2026-09-11 16:04 ` sashiko-bot
2026-09-13 16:37 ` Donggeun Yoo
1 sibling, 0 replies; 24+ messages in thread
From: sashiko-bot @ 2026-09-11 16:04 UTC (permalink / raw)
To: Xiang Gao; +Cc: linux-trace-kernel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] Persistent memory-mapped trace buffers are incorrectly accounted as page-allocator memory, leading to double-counting in lost RAM calculations.
- [Low] Evaluation of a struct type as a boolean condition causes a hard compilation error.
--
commit 339a95b19ea8f13ff179992c9814bfee94fa38b3
Author: Xiang Gao <gxxa03070307@gmail.com>
tracing: add ring-buffer memory usage statistics in tracefs
This commit adds memory usage reporting for tracing ring buffers to calculate
memory footprint more accurately than relying on buffer capacity. It exposes
a new memory_usage_kb file in tracefs which sums up the page allocator memory
used by the data pages and reader pages.
> diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
> index 9c03a555a6ba2..73e79c86035c2 100644
> --- a/kernel/trace/ring_buffer.c
> +++ b/kernel/trace/ring_buffer.c
[ ... ]
> @@ -6560,6 +6560,47 @@ unsigned long ring_buffer_size(struct trace_buffer *buffer, int cpu)
> }
> EXPORT_SYMBOL_GPL(ring_buffer_size);
>
> +/**
> + * ring_buffer_memory_size - return the memory used by the buffer (in bytes)
[ ... ]
> + */
> +unsigned long ring_buffer_memory_size(struct trace_buffer *buffer, int cpu)
> +{
> + struct ring_buffer_per_cpu *cpu_buffer;
> + unsigned long subbuf_size;
> + unsigned long size;
> +
> + if (!cpumask_test_cpu(cpu, buffer->cpumask))
> + return 0;
> +
> + /* Remote buffers use externally owned memory. */
> + if (buffer->remote)
> + return 0;
[Severity: Medium]
Does this check also need to exclude persistent memory-mapped trace buffers
where buffer->range_addr_start is set? Since those buffers also use
externally owned or reserved memory bypassing the page-allocator, not
skipping them here might result in double-counting their memory in lost
RAM calculations.
> +
> + cpu_buffer = buffer->buffers[cpu];
> + subbuf_size = PAGE_SIZE << READ_ONCE(buffer->subbuf_order);
> +
> + /* Data sub-buffers plus the reader page. */
> + size = (cpu_buffer->nr_pages + 1) * subbuf_size;
> +
> + /* The cached read page, if present, is a full sub-buffer page. */
> + if (cpu_buffer->free_page)
> + size += subbuf_size;
[Severity: Low]
Does evaluating cpu_buffer->free_page directly as a boolean condition
cause a compiler error here, since free_page is an embedded struct
(struct buffer_data_read_page) rather than a pointer? Should this check its
internal data pointer instead, such as if (cpu_buffer->free_page.data)?
> +
> + /* The mmap metadata page is a single system page. */
> + if (cpu_buffer->meta_page)
> + size += PAGE_SIZE;
> +
> + return size;
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260911155017.3377254-1-gaoxiang17@xiaomi.com?part=1
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 0/2] tracing: add ring-buffer memory usage statistics
2026-09-05 11:27 [PATCH 0/2] tracing: add ring-buffer memory usage statistics Xiang Gao
` (2 preceding siblings ...)
2026-09-11 15:50 ` [PATCH v2 0/2] tracing: add ring-buffer memory usage statistics Xiang Gao
@ 2026-09-11 17:22 ` Vincent Donnefort
3 siblings, 0 replies; 24+ messages in thread
From: Vincent Donnefort @ 2026-09-11 17:22 UTC (permalink / raw)
To: Xiang Gao
Cc: Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Lorenzo Stoakes, gao xu, yinchuang1, linux-trace-kernel,
linux-kernel, Xiang Gao
On Sat, Sep 05, 2026 at 07:27:30PM +0800, Xiang Gao wrote:
> Report the memory consumed by the tracing ring buffers, rather than the
> usable data capacity exposed by buffer_size_kb. Android low-memory
> diagnostics need this to attribute the memory used by tracing when
> calculating lost RAM.
>
> The buffers can be spread across the global trace array, dynamically
> created instances, and snapshot buffers. Userspace currently has to
> discover and sum every instance, and snapshot memory is not exposed by
> the per-instance totals.
>
> Patch 1 adds:
>
> /sys/kernel/tracing/trace_stats/memory_usage_kb
>
> reporting:
>
> buffers: ...
> snapshot_buffers: ...
>
> covering the global trace array and all instances across all CPUs.
>
> Patch 2 adds the per-CPU view under
> trace_stats/per_cpu/cpuN/memory_usage_kb.
>
> The values account for the full pages backing the data sub-buffers and
> reader page, plus the cached read page and mmap metadata page when
> present. Slab-allocated ring-buffer metadata is not included.
>
> Xiang Gao (2):
> tracing: add ring-buffer memory usage statistics in tracefs
> tracing: add per-CPU memory usage statistics in tracefs
>
> Documentation/trace/ftrace.rst | 15 +++++
> include/linux/ring_buffer.h | 1 +
> kernel/trace/ring_buffer.c | 41 +++++++++++++
> kernel/trace/trace.c | 104 +++++++++++++++++++++++++++++++++
> 4 files changed, 161 insertions(+)
>
> --
> 2.34.1
>
>
It looks like you have sent the same v1 again.
--
Vincent
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v2 1/2] tracing: add ring-buffer memory usage statistics in tracefs
2026-09-11 15:50 ` [PATCH v2 1/2] tracing: add ring-buffer memory usage statistics in tracefs Xiang Gao
2026-09-11 16:04 ` sashiko-bot
@ 2026-09-13 16:37 ` Donggeun Yoo
1 sibling, 0 replies; 24+ messages in thread
From: Donggeun Yoo @ 2026-09-13 16:37 UTC (permalink / raw)
To: Xiang Gao
Cc: Donggeun Yoo, Xiang Gao, Steven Rostedt, Vincent Donnefort,
Masami Hiramatsu, Mathieu Desnoyers, Lorenzo Stoakes, gao xu,
yinchuang1, linux-trace-kernel, linux-kernel
On Fri, Sep 11, 2026 at 11:50:16PM +0800, Xiang Gao wrote:
> + /* The cached read page, if present, is a full sub-buffer page. */
> + if (cpu_buffer->free_page)
> + size += subbuf_size;
Have you compile-tested this one? free_page is a struct, not a pointer:
kernel/trace/ring_buffer.c:6594:13: error: used struct type value where scalar is required
6594 | if (cpu_buffer->free_page)
| ^~~~~~~~~~
cpu_buffer->free_page.data should do it.
> + list_for_each_entry(tr, &ftrace_trace_arrays, list) {
> + for_each_tracing_cpu(cpu)
> + trace_array_buffer_memory(tr, cpu, &stats.buffers,
> + &stats.snapshot);
> + }
With that fixed the walk does match the changelog, but temp_buffer is out
of its reach. tracer_alloc_buffers() allocates it and never attaches it to
a trace array, so it is not on ftrace_trace_arrays, and its pages are the
kind you are counting: sub-buffers and a reader page from the page
allocator, not remote and not slab.
It is three sub-buffers per CPU at order 0 and is never resized, so it
disappears into the noise once a real buffer is sized up. At rest it does
not. On an 8 CPU x86_64 guest the file reports
buffers: 96
while temp_buffer holds another 96K. Freeing it hands back 24 pages, which
is what ring_buffer_memory_size() predicts for it.
Was that deliberate? For lost RAM accounting I would have expected it in.
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v3 0/2] tracing: add ring-buffer memory usage statistics
2026-09-11 15:50 ` [PATCH v2 0/2] tracing: add ring-buffer memory usage statistics Xiang Gao
2026-09-11 15:50 ` [PATCH v2 1/2] tracing: add ring-buffer memory usage statistics in tracefs Xiang Gao
2026-09-11 15:50 ` [PATCH v2 2/2] tracing: add per-CPU " Xiang Gao
@ 2026-09-16 6:33 ` Xiang Gao
2026-09-16 6:33 ` [PATCH v3 1/2] tracing: add ring-buffer memory usage statistics in tracefs Xiang Gao
` (2 more replies)
2 siblings, 3 replies; 24+ messages in thread
From: Xiang Gao @ 2026-09-16 6:33 UTC (permalink / raw)
To: Steven Rostedt, Vincent Donnefort, Donggeun Yoo
Cc: Masami Hiramatsu, Mathieu Desnoyers, Lorenzo Stoakes, gao xu,
yinchuang1, linux-trace-kernel, linux-kernel, Xiang Gao
Report the memory consumed by the tracing ring buffers, rather than the
usable data capacity exposed by buffer_size_kb. Android low-memory
diagnostics need this to attribute the memory used by tracing when
calculating lost RAM.
The buffers can be spread across the global trace array, dynamically
created instances, and snapshot buffers. Userspace currently has to
discover and sum every instance, and snapshot memory is not exposed by
the per-instance totals.
Patch 1 adds:
/sys/kernel/tracing/trace_stats/memory_usage_kb
reporting:
buffers: ...
snapshot_buffers: ...
covering the global trace array and all instances across all CPUs.
Patch 2 adds the per-CPU view under
trace_stats/per_cpu/cpuN/memory_usage_kb.
The values account for the full pages backing the data sub-buffers and
reader page, plus the cached read page and mmap metadata page when
present. Slab-allocated ring-buffer metadata is not included.
Changes since v2:
- Account for the bootstrapping temp_buffer (Donggeun Yoo).
- Rebase onto latest mainline; adapt to free_page becoming struct
buffer_data_read_page.
Tested on arm64 QEMU with global buffer resize, snapshot alloc/free,
instance create/remove, and per-CPU aggregation, all against the
baseline that includes temp_buffer (3 pages per CPU).
Xiang Gao (2):
tracing: add ring-buffer memory usage statistics in tracefs
tracing: add per-CPU memory usage statistics in tracefs
Documentation/trace/ftrace.rst | 15 +++++
include/linux/ring_buffer.h | 1 +
kernel/trace/ring_buffer.c | 41 ++++++++++++
kernel/trace/trace.c | 118 +++++++++++++++++++++++++++++++++
4 files changed, 175 insertions(+)
--
2.34.1
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v3 1/2] tracing: add ring-buffer memory usage statistics in tracefs
2026-09-16 6:33 ` [PATCH v3 0/2] tracing: add ring-buffer memory usage statistics Xiang Gao
@ 2026-09-16 6:33 ` Xiang Gao
2026-09-16 6:50 ` sashiko-bot
2026-09-16 6:33 ` [PATCH v3 2/2] tracing: add per-CPU " Xiang Gao
2026-09-21 11:30 ` [PATCH v4 0/2] tracing: add ring-buffer memory usage statistics Xiang Gao
2 siblings, 1 reply; 24+ messages in thread
From: Xiang Gao @ 2026-09-16 6:33 UTC (permalink / raw)
To: Steven Rostedt, Vincent Donnefort, Donggeun Yoo
Cc: Masami Hiramatsu, Mathieu Desnoyers, Lorenzo Stoakes, gao xu,
yinchuang1, linux-trace-kernel, linux-kernel, Xiang Gao
Report the memory consumed by the tracing ring buffers, rather than the
usable data capacity exposed by buffer_size_kb. Android low-memory
diagnostics need this to attribute the memory used by tracing when
calculating lost RAM.
The buffers can be spread across the global trace array, dynamically
created instances, and snapshot buffers. Userspace currently has to
discover and sum every instance, and snapshot memory is not exposed by
the per-instance totals.
Add a trace_stats directory with memory_usage_kb reporting:
buffers:
snapshot_buffers:
covering the global trace array, all instances, and the bootstrapping
temp_buffer across all CPUs.
The values account for the full pages backing the data sub-buffers and
reader page, plus the cached read page and mmap metadata page when
present. Slab-allocated ring-buffer metadata is not included, as it is
already reported through Slab and would be double-counted when
subtracting tracing memory from lost RAM. Remote buffers, whose pages
are externally owned, report zero.
Signed-off-by: Xiang Gao <gaoxiang17@xiaomi.com>
---
Documentation/trace/ftrace.rst | 12 ++++++
include/linux/ring_buffer.h | 1 +
kernel/trace/ring_buffer.c | 41 ++++++++++++++++++++
kernel/trace/trace.c | 70 ++++++++++++++++++++++++++++++++++
4 files changed, 124 insertions(+)
diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst
index 7261f25f8b4b..99ddfe26b7cd 100644
--- a/Documentation/trace/ftrace.rst
+++ b/Documentation/trace/ftrace.rst
@@ -218,6 +218,18 @@ of ftrace. Here is a list of some of the key files:
This displays the total combined size of all the trace buffers.
+ trace_stats/memory_usage_kb:
+
+ This reports the memory consumed by the ring buffers, as opposed to
+ the usable data capacity shown by buffer_size_kb. The value covers the
+ main and snapshot buffers of the global trace array and all tracing
+ instances. It does not include slab-allocated ring-buffer metadata.
+
+ Output::
+
+ buffers: ...
+ snapshot_buffers: ...
+
buffer_subbuf_size_kb:
This sets or displays the sub buffer size. The ring buffer is broken up
diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
index eac3e9080c3c..96b99e6757d4 100644
--- a/include/linux/ring_buffer.h
+++ b/include/linux/ring_buffer.h
@@ -167,6 +167,7 @@ int ring_buffer_iter_empty(struct ring_buffer_iter *iter);
bool ring_buffer_iter_dropped(struct ring_buffer_iter *iter);
unsigned long ring_buffer_size(struct trace_buffer *buffer, int cpu);
+unsigned long ring_buffer_memory_size(struct trace_buffer *buffer, int cpu);
unsigned long ring_buffer_max_event_size(struct trace_buffer *buffer);
void ring_buffer_reset_cpu(struct trace_buffer *buffer, int cpu);
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 04bb94c29f58..28002d343f09 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -6559,6 +6559,47 @@ unsigned long ring_buffer_size(struct trace_buffer *buffer, int cpu)
}
EXPORT_SYMBOL_GPL(ring_buffer_size);
+/**
+ * ring_buffer_memory_size - return the memory used by the buffer (in bytes)
+ * @buffer: The ring buffer.
+ * @cpu: The CPU to get ring buffer memory from.
+ *
+ * Returns the page-allocator memory consumed by @cpu, including the data
+ * sub-buffers, the reader page, the cached read page, and the mmap
+ * metadata page. Unlike ring_buffer_size(), which reports the usable data
+ * capacity, this accounts for the full pages allocated to the buffer.
+ * Remote buffers do not own page-allocator memory and report zero.
+ */
+unsigned long ring_buffer_memory_size(struct trace_buffer *buffer, int cpu)
+{
+ struct ring_buffer_per_cpu *cpu_buffer;
+ unsigned long subbuf_size;
+ unsigned long size;
+
+ if (!cpumask_test_cpu(cpu, buffer->cpumask))
+ return 0;
+
+ /* Remote buffers use externally owned memory. */
+ if (buffer->remote)
+ return 0;
+
+ cpu_buffer = buffer->buffers[cpu];
+ subbuf_size = PAGE_SIZE << READ_ONCE(buffer->subbuf_order);
+
+ /* Data sub-buffers plus the reader page. */
+ size = (cpu_buffer->nr_pages + 1) * subbuf_size;
+
+ /* The cached read page, if present, is a full sub-buffer page. */
+ if (cpu_buffer->free_page.data)
+ size += subbuf_size;
+
+ /* The mmap metadata page is a single system page. */
+ if (cpu_buffer->meta_page)
+ size += PAGE_SIZE;
+
+ return size;
+}
+
/**
* ring_buffer_max_event_size - return the max data size of an event
* @buffer: The ring buffer.
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index e4a490d3d08c..796e239fbaf9 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -5771,6 +5771,62 @@ tracing_total_entries_read(struct file *filp, char __user *ubuf,
return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
}
+struct trace_mem_stats {
+ unsigned long buffers;
+ unsigned long snapshot;
+};
+
+static void
+trace_array_buffer_memory(struct trace_array *tr, int cpu,
+ unsigned long *buffers, unsigned long *snapshot)
+{
+ if (tr->array_buffer.buffer)
+ *buffers += ring_buffer_memory_size(tr->array_buffer.buffer, cpu);
+
+#ifdef CONFIG_TRACER_SNAPSHOT
+ if (tr->snapshot_buffer.buffer)
+ *snapshot += ring_buffer_memory_size(tr->snapshot_buffer.buffer, cpu);
+#endif
+}
+
+static struct trace_mem_stats trace_buffers_memory(void)
+{
+ struct trace_mem_stats stats = {};
+ struct trace_array *tr;
+ int cpu;
+
+ guard(mutex)(&trace_types_lock);
+
+ list_for_each_entry(tr, &ftrace_trace_arrays, list) {
+ for_each_tracing_cpu(cpu)
+ trace_array_buffer_memory(tr, cpu, &stats.buffers,
+ &stats.snapshot);
+ }
+
+ /*
+ * temp_buffer is allocated in tracer_alloc_buffers() and is never
+ * attached to a trace array. It temporarily holds event data for
+ * triggers when tracing is off. Account for its pages too.
+ */
+ if (temp_buffer) {
+ for_each_tracing_cpu(cpu)
+ stats.buffers += ring_buffer_memory_size(temp_buffer, cpu);
+ }
+
+ return stats;
+}
+
+static int trace_mem_show(struct seq_file *m, void *v)
+{
+ struct trace_mem_stats stats = trace_buffers_memory();
+
+ seq_printf(m, "buffers: %lu\n", stats.buffers >> 10);
+ seq_printf(m, "snapshot_buffers: %lu\n", stats.snapshot >> 10);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(trace_mem);
+
#define LAST_BOOT_HEADER ((void *)1)
static void *l_next(struct seq_file *m, void *v, loff_t *pos)
@@ -9285,6 +9341,18 @@ static struct notifier_block trace_module_nb = {
};
#endif /* CONFIG_MODULES */
+static __init void init_trace_stats_tracefs(void)
+{
+ struct dentry *stats_dir;
+
+ stats_dir = tracefs_create_dir("trace_stats", NULL);
+ if (!stats_dir)
+ return;
+
+ trace_create_file("memory_usage_kb", TRACE_MODE_READ, stats_dir,
+ NULL, &trace_mem_fops);
+}
+
static __init void tracer_init_tracefs_work_func(struct work_struct *work)
{
@@ -9293,6 +9361,8 @@ static __init void tracer_init_tracefs_work_func(struct work_struct *work)
init_tracer_tracefs(&global_trace, NULL);
ftrace_init_tracefs_toplevel(&global_trace, NULL);
+ init_trace_stats_tracefs();
+
trace_create_file("tracing_thresh", TRACE_MODE_WRITE, NULL,
&global_trace, &tracing_thresh_fops);
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH v3 2/2] tracing: add per-CPU memory usage statistics in tracefs
2026-09-16 6:33 ` [PATCH v3 0/2] tracing: add ring-buffer memory usage statistics Xiang Gao
2026-09-16 6:33 ` [PATCH v3 1/2] tracing: add ring-buffer memory usage statistics in tracefs Xiang Gao
@ 2026-09-16 6:33 ` Xiang Gao
2026-09-21 11:30 ` [PATCH v4 0/2] tracing: add ring-buffer memory usage statistics Xiang Gao
2 siblings, 0 replies; 24+ messages in thread
From: Xiang Gao @ 2026-09-16 6:33 UTC (permalink / raw)
To: Steven Rostedt, Vincent Donnefort, Donggeun Yoo
Cc: Masami Hiramatsu, Mathieu Desnoyers, Lorenzo Stoakes, gao xu,
yinchuang1, linux-trace-kernel, linux-kernel, Xiang Gao
Provide a per-CPU view of the tracing ring-buffer memory usage under
trace_stats/per_cpu/cpuN/memory_usage_kb, using the same format as the
aggregate file. Each file reports only the buffers belonging to that CPU
across the global trace array and all tracing instances.
Signed-off-by: Xiang Gao <gaoxiang17@xiaomi.com>
---
Documentation/trace/ftrace.rst | 3 ++
kernel/trace/trace.c | 50 +++++++++++++++++++++++++++++++++-
2 files changed, 52 insertions(+), 1 deletion(-)
diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst
index 99ddfe26b7cd..e53cdd8d6702 100644
--- a/Documentation/trace/ftrace.rst
+++ b/Documentation/trace/ftrace.rst
@@ -230,6 +230,9 @@ of ftrace. Here is a list of some of the key files:
buffers: ...
snapshot_buffers: ...
+ The same file is provided under trace_stats/per_cpu/cpuN/, reporting
+ only the buffers belonging to that CPU.
+
buffer_subbuf_size_kb:
This sets or displays the sub buffer size. The ring buffer is broken up
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 796e239fbaf9..280003916677 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -5827,6 +5827,35 @@ static int trace_mem_show(struct seq_file *m, void *v)
}
DEFINE_SHOW_ATTRIBUTE(trace_mem);
+static struct trace_mem_stats trace_buffers_memory_cpu(int cpu)
+{
+ struct trace_mem_stats stats = {};
+ struct trace_array *tr;
+
+ guard(mutex)(&trace_types_lock);
+
+ list_for_each_entry(tr, &ftrace_trace_arrays, list)
+ trace_array_buffer_memory(tr, cpu, &stats.buffers,
+ &stats.snapshot);
+
+ /* Account for the bootstrapping temp_buffer as well. */
+ if (temp_buffer)
+ stats.buffers += ring_buffer_memory_size(temp_buffer, cpu);
+
+ return stats;
+}
+
+static int trace_mem_per_cpu_show(struct seq_file *m, void *v)
+{
+ struct trace_mem_stats stats = trace_buffers_memory_cpu((long)m->private);
+
+ seq_printf(m, "buffers: %lu\n", stats.buffers >> 10);
+ seq_printf(m, "snapshot_buffers: %lu\n", stats.snapshot >> 10);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(trace_mem_per_cpu);
+
#define LAST_BOOT_HEADER ((void *)1)
static void *l_next(struct seq_file *m, void *v, loff_t *pos)
@@ -9343,7 +9372,9 @@ static struct notifier_block trace_module_nb = {
static __init void init_trace_stats_tracefs(void)
{
- struct dentry *stats_dir;
+ struct dentry *stats_dir, *per_cpu_dir, *cpu_dir;
+ char cpu_dir_name[30];
+ int cpu;
stats_dir = tracefs_create_dir("trace_stats", NULL);
if (!stats_dir)
@@ -9351,6 +9382,23 @@ static __init void init_trace_stats_tracefs(void)
trace_create_file("memory_usage_kb", TRACE_MODE_READ, stats_dir,
NULL, &trace_mem_fops);
+
+ per_cpu_dir = tracefs_create_dir("per_cpu", stats_dir);
+ if (!per_cpu_dir)
+ return;
+
+ for_each_tracing_cpu(cpu) {
+ snprintf(cpu_dir_name, 30, "cpu%d", cpu);
+ cpu_dir = tracefs_create_dir(cpu_dir_name, per_cpu_dir);
+ if (!cpu_dir) {
+ pr_warn("Could not create tracefs '%s' entry\n",
+ cpu_dir_name);
+ continue;
+ }
+
+ trace_create_file("memory_usage_kb", TRACE_MODE_READ, cpu_dir,
+ (void *)(long)cpu, &trace_mem_per_cpu_fops);
+ }
}
static __init void tracer_init_tracefs_work_func(struct work_struct *work)
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [PATCH v3 1/2] tracing: add ring-buffer memory usage statistics in tracefs
2026-09-16 6:33 ` [PATCH v3 1/2] tracing: add ring-buffer memory usage statistics in tracefs Xiang Gao
@ 2026-09-16 6:50 ` sashiko-bot
0 siblings, 0 replies; 24+ messages in thread
From: sashiko-bot @ 2026-09-16 6:50 UTC (permalink / raw)
To: Xiang Gao; +Cc: linux-trace-kernel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] tracing: Use-After-Free on temp_buffer and tracing_buffer_mask when tracer_alloc_buffers fails
--
commit 74cf4963596c0d99d36452a0e504036b25685bcc
Author: Xiang Gao <gxxa03070307@gmail.com>
tracing: add ring-buffer memory usage statistics in tracefs
This commit adds a tracefs file, trace_stats/memory_usage_kb, to report
the memory consumed by tracing ring buffers. It calculates the memory
usage across the global trace array, instances, and snapshot buffers
using a new function, ring_buffer_memory_size().
> diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
> index 8658cad53cb59..5a023018f612e 100644
> --- a/kernel/trace/trace.c
> +++ b/kernel/trace/trace.c
[ ... ]
> @@ -5771,6 +5771,62 @@ tracing_total_entries_read(struct file *filp, char __user *ubuf,
> return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
> }
>
> +struct trace_mem_stats {
> + unsigned long buffers;
> + unsigned long snapshot;
> +};
> +
> +static void
> +trace_array_buffer_memory(struct trace_array *tr, int cpu,
> + unsigned long *buffers, unsigned long *snapshot)
> +{
> + if (tr->array_buffer.buffer)
> + *buffers += ring_buffer_memory_size(tr->array_buffer.buffer, cpu);
> +
> +#ifdef CONFIG_TRACER_SNAPSHOT
> + if (tr->snapshot_buffer.buffer)
> + *snapshot += ring_buffer_memory_size(tr->snapshot_buffer.buffer, cpu);
> +#endif
> +}
> +
> +static struct trace_mem_stats trace_buffers_memory(void)
> +{
> + struct trace_mem_stats stats = {};
> + struct trace_array *tr;
> + int cpu;
> +
> + guard(mutex)(&trace_types_lock);
> +
> + list_for_each_entry(tr, &ftrace_trace_arrays, list) {
> + for_each_tracing_cpu(cpu)
[Severity: High]
Does this code trigger a use-after-free if tracer_alloc_buffers() fails during
early boot?
If tracer_alloc_buffers() fails in kernel/trace/trace.c, it frees both
tracing_buffer_mask and temp_buffer but leaves their global pointers dangling:
kernel/trace/trace.c:tracer_alloc_buffers() {
...
out_free_buffer_mask:
...
ring_buffer_free(temp_buffer);
free_cpumask_var(tracing_buffer_mask);
...
}
Because trace_stats/memory_usage_kb is created unconditionally by
tracer_init_tracefs_work_func(), and its file operations (trace_mem_fops)
do not check the tracing_disabled flag, a local user can still read the file.
When trace_mem_show() executes trace_buffers_memory(), the
for_each_tracing_cpu() macro will dereference the dangling
tracing_buffer_mask.
> + trace_array_buffer_memory(tr, cpu, &stats.buffers,
> + &stats.snapshot);
> + }
> +
> + /*
> + * temp_buffer is allocated in tracer_alloc_buffers() and is never
> + * attached to a trace array. It temporarily holds event data for
> + * triggers when tracing is off. Account for its pages too.
> + */
> + if (temp_buffer) {
> + for_each_tracing_cpu(cpu)
> + stats.buffers += ring_buffer_memory_size(temp_buffer, cpu);
[Severity: High]
Does this also cause a use-after-free on temp_buffer in trace_buffers_memory()?
If tracer_alloc_buffers() fails, temp_buffer is freed but its pointer
is never set to NULL on the error path. This branch will evaluate the dangling
pointer as true and pass it to ring_buffer_memory_size(), which will
dereference the freed memory.
> + }
> +
> + return stats;
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260916063322.472172-1-gaoxiang17@xiaomi.com?part=1
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v4 0/2] tracing: add ring-buffer memory usage statistics
2026-09-16 6:33 ` [PATCH v3 0/2] tracing: add ring-buffer memory usage statistics Xiang Gao
2026-09-16 6:33 ` [PATCH v3 1/2] tracing: add ring-buffer memory usage statistics in tracefs Xiang Gao
2026-09-16 6:33 ` [PATCH v3 2/2] tracing: add per-CPU " Xiang Gao
@ 2026-09-21 11:30 ` Xiang Gao
2026-09-21 11:30 ` [PATCH v4 1/2] tracing: add ring-buffer memory usage statistics in tracefs Xiang Gao
2026-09-21 11:30 ` [PATCH v4 2/2] tracing: add per-CPU " Xiang Gao
2 siblings, 2 replies; 24+ messages in thread
From: Xiang Gao @ 2026-09-21 11:30 UTC (permalink / raw)
To: Steven Rostedt, Vincent Donnefort, Donggeun Yoo
Cc: Masami Hiramatsu, Mathieu Desnoyers, Lorenzo Stoakes, gao xu,
yinchuang1, linux-trace-kernel, linux-kernel, Xiang Gao
Report the memory consumed by the tracing ring buffers, rather than the
usable data capacity exposed by buffer_size_kb. Android low-memory
diagnostics need this to attribute the memory used by tracing when
calculating lost RAM.
The buffers can be spread across the global trace array, dynamically
created instances, and snapshot buffers. Userspace currently has to
discover and sum every instance, and snapshot memory is not exposed by
the per-instance totals.
Patch 1 adds:
/sys/kernel/tracing/trace_stats/memory_usage_kb
reporting:
buffers: ...
snapshot_buffers: ...
covering the global trace array and all instances across all CPUs.
Patch 2 adds the per-CPU view under
trace_stats/per_cpu/cpuN/memory_usage_kb.
The values account for the full pages backing the data sub-buffers and
reader page, plus the cached read page and mmap metadata page when
present. Slab-allocated ring-buffer metadata is not included.
Changes since v3:
- Check tracing_disabled on open and during init to avoid a use-after-free
on temp_buffer/tracing_buffer_mask when tracer_alloc_buffers() fails.
- Use READ_ONCE() for ring-buffer fields that can change concurrently.
Changes since v2:
- Account for the bootstrapping temp_buffer (Donggeun Yoo).
- Rebase onto latest mainline; adapt to free_page becoming struct
buffer_data_read_page.
Tested on arm64 QEMU with global buffer resize, snapshot alloc/free,
instance create/remove, and per-CPU aggregation, all against the
baseline that includes temp_buffer (3 pages per CPU).
Xiang Gao (2):
tracing: add ring-buffer memory usage statistics in tracefs
tracing: add per-CPU memory usage statistics in tracefs
Documentation/trace/ftrace.rst | 15 ++++
include/linux/ring_buffer.h | 1 +
kernel/trace/ring_buffer.c | 41 +++++++++
kernel/trace/trace.c | 160 +++++++++++++++++++++++++++++++++
4 files changed, 217 insertions(+)
--
2.34.1
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v4 1/2] tracing: add ring-buffer memory usage statistics in tracefs
2026-09-21 11:30 ` [PATCH v4 0/2] tracing: add ring-buffer memory usage statistics Xiang Gao
@ 2026-09-21 11:30 ` Xiang Gao
2026-09-22 9:41 ` Vincent Donnefort
2026-09-21 11:30 ` [PATCH v4 2/2] tracing: add per-CPU " Xiang Gao
1 sibling, 1 reply; 24+ messages in thread
From: Xiang Gao @ 2026-09-21 11:30 UTC (permalink / raw)
To: Steven Rostedt, Vincent Donnefort, Donggeun Yoo
Cc: Masami Hiramatsu, Mathieu Desnoyers, Lorenzo Stoakes, gao xu,
yinchuang1, linux-trace-kernel, linux-kernel, Xiang Gao
Report the memory consumed by the tracing ring buffers, rather than the
usable data capacity exposed by buffer_size_kb. Android low-memory
diagnostics need this to attribute the memory used by tracing when
calculating lost RAM.
The buffers can be spread across the global trace array, dynamically
created instances, and snapshot buffers. Userspace currently has to
discover and sum every instance, and snapshot memory is not exposed by
the per-instance totals.
Add a trace_stats directory with memory_usage_kb reporting:
buffers:
snapshot_buffers:
covering the global trace array, all instances, and the bootstrapping
temp_buffer across all CPUs.
The values account for the full pages backing the data sub-buffers and
reader page, plus the cached read page and mmap metadata page when
present. Slab-allocated ring-buffer metadata is not included, as it is
already reported through Slab and would be double-counted when
subtracting tracing memory from lost RAM. Remote buffers, whose pages
are externally owned, report zero.
Signed-off-by: Xiang Gao <gaoxiang17@xiaomi.com>
---
Documentation/trace/ftrace.rst | 12 +++++
include/linux/ring_buffer.h | 1 +
kernel/trace/ring_buffer.c | 41 +++++++++++++++
kernel/trace/trace.c | 95 ++++++++++++++++++++++++++++++++++
4 files changed, 149 insertions(+)
diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst
index 7261f25f8b4b..99ddfe26b7cd 100644
--- a/Documentation/trace/ftrace.rst
+++ b/Documentation/trace/ftrace.rst
@@ -218,6 +218,18 @@ of ftrace. Here is a list of some of the key files:
This displays the total combined size of all the trace buffers.
+ trace_stats/memory_usage_kb:
+
+ This reports the memory consumed by the ring buffers, as opposed to
+ the usable data capacity shown by buffer_size_kb. The value covers the
+ main and snapshot buffers of the global trace array and all tracing
+ instances. It does not include slab-allocated ring-buffer metadata.
+
+ Output::
+
+ buffers: ...
+ snapshot_buffers: ...
+
buffer_subbuf_size_kb:
This sets or displays the sub buffer size. The ring buffer is broken up
diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
index eac3e9080c3c..96b99e6757d4 100644
--- a/include/linux/ring_buffer.h
+++ b/include/linux/ring_buffer.h
@@ -167,6 +167,7 @@ int ring_buffer_iter_empty(struct ring_buffer_iter *iter);
bool ring_buffer_iter_dropped(struct ring_buffer_iter *iter);
unsigned long ring_buffer_size(struct trace_buffer *buffer, int cpu);
+unsigned long ring_buffer_memory_size(struct trace_buffer *buffer, int cpu);
unsigned long ring_buffer_max_event_size(struct trace_buffer *buffer);
void ring_buffer_reset_cpu(struct trace_buffer *buffer, int cpu);
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 04bb94c29f58..efb88bf8970c 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -6559,6 +6559,47 @@ unsigned long ring_buffer_size(struct trace_buffer *buffer, int cpu)
}
EXPORT_SYMBOL_GPL(ring_buffer_size);
+/**
+ * ring_buffer_memory_size - return the memory used by the buffer (in bytes)
+ * @buffer: The ring buffer.
+ * @cpu: The CPU to get ring buffer memory from.
+ *
+ * Returns the page-allocator memory consumed by @cpu, including the data
+ * sub-buffers, the reader page, the cached read page, and the mmap
+ * metadata page. Unlike ring_buffer_size(), which reports the usable data
+ * capacity, this accounts for the full pages allocated to the buffer.
+ * Remote buffers do not own page-allocator memory and report zero.
+ */
+unsigned long ring_buffer_memory_size(struct trace_buffer *buffer, int cpu)
+{
+ struct ring_buffer_per_cpu *cpu_buffer;
+ unsigned long subbuf_size;
+ unsigned long size;
+
+ if (!cpumask_test_cpu(cpu, buffer->cpumask))
+ return 0;
+
+ /* Remote buffers use externally owned memory. */
+ if (buffer->remote)
+ return 0;
+
+ cpu_buffer = buffer->buffers[cpu];
+ subbuf_size = PAGE_SIZE << READ_ONCE(buffer->subbuf_order);
+
+ /* Data sub-buffers plus the reader page. */
+ size = (READ_ONCE(cpu_buffer->nr_pages) + 1) * subbuf_size;
+
+ /* The cached read page, if present, is a full sub-buffer page. */
+ if (READ_ONCE(cpu_buffer->free_page.data))
+ size += subbuf_size;
+
+ /* The mmap metadata page is a single system page. */
+ if (READ_ONCE(cpu_buffer->meta_page))
+ size += PAGE_SIZE;
+
+ return size;
+}
+
/**
* ring_buffer_max_event_size - return the max data size of an event
* @buffer: The ring buffer.
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index e4a490d3d08c..d4a913ff8a69 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -5771,6 +5771,79 @@ tracing_total_entries_read(struct file *filp, char __user *ubuf,
return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
}
+struct trace_mem_stats {
+ unsigned long buffers;
+ unsigned long snapshot;
+};
+
+static void
+trace_array_buffer_memory(struct trace_array *tr, int cpu,
+ unsigned long *buffers, unsigned long *snapshot)
+{
+ if (tr->array_buffer.buffer)
+ *buffers += ring_buffer_memory_size(tr->array_buffer.buffer, cpu);
+
+#ifdef CONFIG_TRACER_SNAPSHOT
+ if (tr->snapshot_buffer.buffer)
+ *snapshot += ring_buffer_memory_size(tr->snapshot_buffer.buffer, cpu);
+#endif
+}
+
+static struct trace_mem_stats trace_buffers_memory(void)
+{
+ struct trace_mem_stats stats = {};
+ struct trace_array *tr;
+ int cpu;
+
+ guard(mutex)(&trace_types_lock);
+
+ list_for_each_entry(tr, &ftrace_trace_arrays, list) {
+ for_each_tracing_cpu(cpu)
+ trace_array_buffer_memory(tr, cpu, &stats.buffers,
+ &stats.snapshot);
+ }
+
+ /*
+ * temp_buffer is allocated in tracer_alloc_buffers() and is never
+ * attached to a trace array. It temporarily holds event data for
+ * triggers when tracing is off. Account for its pages too.
+ */
+ if (temp_buffer) {
+ for_each_tracing_cpu(cpu)
+ stats.buffers += ring_buffer_memory_size(temp_buffer, cpu);
+ }
+
+ return stats;
+}
+
+static int trace_mem_show(struct seq_file *m, void *v)
+{
+ struct trace_mem_stats stats = trace_buffers_memory();
+
+ seq_printf(m, "buffers: %lu\n", stats.buffers >> 10);
+ seq_printf(m, "snapshot_buffers: %lu\n", stats.snapshot >> 10);
+
+ return 0;
+}
+
+static int trace_mem_open(struct inode *inode, struct file *file)
+{
+ int ret;
+
+ ret = tracing_check_open_get_tr(NULL);
+ if (ret)
+ return ret;
+
+ return single_open(file, trace_mem_show, inode->i_private);
+}
+
+static const struct file_operations trace_mem_fops = {
+ .open = trace_mem_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
#define LAST_BOOT_HEADER ((void *)1)
static void *l_next(struct seq_file *m, void *v, loff_t *pos)
@@ -9285,6 +9358,26 @@ static struct notifier_block trace_module_nb = {
};
#endif /* CONFIG_MODULES */
+static __init void init_trace_stats_tracefs(void)
+{
+ struct dentry *stats_dir;
+
+ /*
+ * tracer_alloc_buffers() frees tracing_buffer_mask and temp_buffer
+ * on failure without NULLing them, so do not iterate tracing CPUs
+ * here when tracing failed to initialize.
+ */
+ if (tracing_disabled)
+ return;
+
+ stats_dir = tracefs_create_dir("trace_stats", NULL);
+ if (!stats_dir)
+ return;
+
+ trace_create_file("memory_usage_kb", TRACE_MODE_READ, stats_dir,
+ NULL, &trace_mem_fops);
+}
+
static __init void tracer_init_tracefs_work_func(struct work_struct *work)
{
@@ -9293,6 +9386,8 @@ static __init void tracer_init_tracefs_work_func(struct work_struct *work)
init_tracer_tracefs(&global_trace, NULL);
ftrace_init_tracefs_toplevel(&global_trace, NULL);
+ init_trace_stats_tracefs();
+
trace_create_file("tracing_thresh", TRACE_MODE_WRITE, NULL,
&global_trace, &tracing_thresh_fops);
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH v4 2/2] tracing: add per-CPU memory usage statistics in tracefs
2026-09-21 11:30 ` [PATCH v4 0/2] tracing: add ring-buffer memory usage statistics Xiang Gao
2026-09-21 11:30 ` [PATCH v4 1/2] tracing: add ring-buffer memory usage statistics in tracefs Xiang Gao
@ 2026-09-21 11:30 ` Xiang Gao
2026-09-22 9:42 ` Vincent Donnefort
2026-09-24 1:36 ` Masami Hiramatsu
1 sibling, 2 replies; 24+ messages in thread
From: Xiang Gao @ 2026-09-21 11:30 UTC (permalink / raw)
To: Steven Rostedt, Vincent Donnefort, Donggeun Yoo
Cc: Masami Hiramatsu, Mathieu Desnoyers, Lorenzo Stoakes, gao xu,
yinchuang1, linux-trace-kernel, linux-kernel, Xiang Gao
Provide a per-CPU view of the tracing ring-buffer memory usage under
trace_stats/per_cpu/cpuN/memory_usage_kb, using the same format as the
aggregate file. Each file reports only the buffers belonging to that CPU
across the global trace array and all tracing instances.
Signed-off-by: Xiang Gao <gaoxiang17@xiaomi.com>
---
Documentation/trace/ftrace.rst | 3 ++
kernel/trace/trace.c | 67 +++++++++++++++++++++++++++++++++-
2 files changed, 69 insertions(+), 1 deletion(-)
diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst
index 99ddfe26b7cd..e53cdd8d6702 100644
--- a/Documentation/trace/ftrace.rst
+++ b/Documentation/trace/ftrace.rst
@@ -230,6 +230,9 @@ of ftrace. Here is a list of some of the key files:
buffers: ...
snapshot_buffers: ...
+ The same file is provided under trace_stats/per_cpu/cpuN/, reporting
+ only the buffers belonging to that CPU.
+
buffer_subbuf_size_kb:
This sets or displays the sub buffer size. The ring buffer is broken up
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index d4a913ff8a69..4010f28f3ebf 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -5844,6 +5844,52 @@ static const struct file_operations trace_mem_fops = {
.release = single_release,
};
+static struct trace_mem_stats trace_buffers_memory_cpu(int cpu)
+{
+ struct trace_mem_stats stats = {};
+ struct trace_array *tr;
+
+ guard(mutex)(&trace_types_lock);
+
+ list_for_each_entry(tr, &ftrace_trace_arrays, list)
+ trace_array_buffer_memory(tr, cpu, &stats.buffers,
+ &stats.snapshot);
+
+ /* Account for the bootstrapping temp_buffer as well. */
+ if (temp_buffer)
+ stats.buffers += ring_buffer_memory_size(temp_buffer, cpu);
+
+ return stats;
+}
+
+static int trace_mem_per_cpu_show(struct seq_file *m, void *v)
+{
+ struct trace_mem_stats stats = trace_buffers_memory_cpu((long)m->private);
+
+ seq_printf(m, "buffers: %lu\n", stats.buffers >> 10);
+ seq_printf(m, "snapshot_buffers: %lu\n", stats.snapshot >> 10);
+
+ return 0;
+}
+
+static int trace_mem_per_cpu_open(struct inode *inode, struct file *file)
+{
+ int ret;
+
+ ret = tracing_check_open_get_tr(NULL);
+ if (ret)
+ return ret;
+
+ return single_open(file, trace_mem_per_cpu_show, inode->i_private);
+}
+
+static const struct file_operations trace_mem_per_cpu_fops = {
+ .open = trace_mem_per_cpu_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
#define LAST_BOOT_HEADER ((void *)1)
static void *l_next(struct seq_file *m, void *v, loff_t *pos)
@@ -9360,7 +9406,9 @@ static struct notifier_block trace_module_nb = {
static __init void init_trace_stats_tracefs(void)
{
- struct dentry *stats_dir;
+ struct dentry *stats_dir, *per_cpu_dir, *cpu_dir;
+ char cpu_dir_name[30];
+ int cpu;
/*
* tracer_alloc_buffers() frees tracing_buffer_mask and temp_buffer
@@ -9376,6 +9424,23 @@ static __init void init_trace_stats_tracefs(void)
trace_create_file("memory_usage_kb", TRACE_MODE_READ, stats_dir,
NULL, &trace_mem_fops);
+
+ per_cpu_dir = tracefs_create_dir("per_cpu", stats_dir);
+ if (!per_cpu_dir)
+ return;
+
+ for_each_tracing_cpu(cpu) {
+ snprintf(cpu_dir_name, 30, "cpu%d", cpu);
+ cpu_dir = tracefs_create_dir(cpu_dir_name, per_cpu_dir);
+ if (!cpu_dir) {
+ pr_warn("Could not create tracefs '%s' entry\n",
+ cpu_dir_name);
+ continue;
+ }
+
+ trace_create_file("memory_usage_kb", TRACE_MODE_READ, cpu_dir,
+ (void *)(long)cpu, &trace_mem_per_cpu_fops);
+ }
}
static __init void tracer_init_tracefs_work_func(struct work_struct *work)
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [PATCH v4 1/2] tracing: add ring-buffer memory usage statistics in tracefs
2026-09-21 11:30 ` [PATCH v4 1/2] tracing: add ring-buffer memory usage statistics in tracefs Xiang Gao
@ 2026-09-22 9:41 ` Vincent Donnefort
2026-09-24 1:27 ` Masami Hiramatsu
0 siblings, 1 reply; 24+ messages in thread
From: Vincent Donnefort @ 2026-09-22 9:41 UTC (permalink / raw)
To: Xiang Gao
Cc: Steven Rostedt, Donggeun Yoo, Masami Hiramatsu, Mathieu Desnoyers,
Lorenzo Stoakes, gao xu, yinchuang1, linux-trace-kernel,
linux-kernel, Xiang Gao
On Mon, Sep 21, 2026 at 07:30:45PM +0800, Xiang Gao wrote:
> Report the memory consumed by the tracing ring buffers, rather than the
> usable data capacity exposed by buffer_size_kb. Android low-memory
> diagnostics need this to attribute the memory used by tracing when
> calculating lost RAM.
>
> The buffers can be spread across the global trace array, dynamically
> created instances, and snapshot buffers. Userspace currently has to
> discover and sum every instance, and snapshot memory is not exposed by
> the per-instance totals.
>
> Add a trace_stats directory with memory_usage_kb reporting:
>
> buffers:
> snapshot_buffers:
>
> covering the global trace array, all instances, and the bootstrapping
> temp_buffer across all CPUs.
>
> The values account for the full pages backing the data sub-buffers and
> reader page, plus the cached read page and mmap metadata page when
> present. Slab-allocated ring-buffer metadata is not included, as it is
> already reported through Slab and would be double-counted when
> subtracting tracing memory from lost RAM. Remote buffers, whose pages
> are externally owned, report zero.
For the next version, it is good practice to __not__ in-reply-to with previous
version.
>
> Signed-off-by: Xiang Gao <gaoxiang17@xiaomi.com>
> ---
> Documentation/trace/ftrace.rst | 12 +++++
> include/linux/ring_buffer.h | 1 +
> kernel/trace/ring_buffer.c | 41 +++++++++++++++
> kernel/trace/trace.c | 95 ++++++++++++++++++++++++++++++++++
> 4 files changed, 149 insertions(+)
>
> diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst
> index 7261f25f8b4b..99ddfe26b7cd 100644
> --- a/Documentation/trace/ftrace.rst
> +++ b/Documentation/trace/ftrace.rst
> @@ -218,6 +218,18 @@ of ftrace. Here is a list of some of the key files:
>
> This displays the total combined size of all the trace buffers.
>
> + trace_stats/memory_usage_kb:
> +
> + This reports the memory consumed by the ring buffers, as opposed to
> + the usable data capacity shown by buffer_size_kb. The value covers the
> + main and snapshot buffers of the global trace array and all tracing
> + instances. It does not include slab-allocated ring-buffer metadata.
> +
> + Output::
> +
> + buffers: ...
> + snapshot_buffers: ...
> +
> buffer_subbuf_size_kb:
>
> This sets or displays the sub buffer size. The ring buffer is broken up
> diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
> index eac3e9080c3c..96b99e6757d4 100644
> --- a/include/linux/ring_buffer.h
> +++ b/include/linux/ring_buffer.h
> @@ -167,6 +167,7 @@ int ring_buffer_iter_empty(struct ring_buffer_iter *iter);
> bool ring_buffer_iter_dropped(struct ring_buffer_iter *iter);
>
> unsigned long ring_buffer_size(struct trace_buffer *buffer, int cpu);
> +unsigned long ring_buffer_memory_size(struct trace_buffer *buffer, int cpu);
> unsigned long ring_buffer_max_event_size(struct trace_buffer *buffer);
>
> void ring_buffer_reset_cpu(struct trace_buffer *buffer, int cpu);
> diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
> index 04bb94c29f58..efb88bf8970c 100644
> --- a/kernel/trace/ring_buffer.c
> +++ b/kernel/trace/ring_buffer.c
> @@ -6559,6 +6559,47 @@ unsigned long ring_buffer_size(struct trace_buffer *buffer, int cpu)
> }
> EXPORT_SYMBOL_GPL(ring_buffer_size);
>
> +/**
> + * ring_buffer_memory_size - return the memory used by the buffer (in bytes)
> + * @buffer: The ring buffer.
> + * @cpu: The CPU to get ring buffer memory from.
> + *
> + * Returns the page-allocator memory consumed by @cpu, including the data
> + * sub-buffers, the reader page, the cached read page, and the mmap
> + * metadata page. Unlike ring_buffer_size(), which reports the usable data
> + * capacity, this accounts for the full pages allocated to the buffer.
> + * Remote buffers do not own page-allocator memory and report zero.
> + */
> +unsigned long ring_buffer_memory_size(struct trace_buffer *buffer, int cpu)
> +{
> + struct ring_buffer_per_cpu *cpu_buffer;
> + unsigned long subbuf_size;
> + unsigned long size;
> +
> + if (!cpumask_test_cpu(cpu, buffer->cpumask))
> + return 0;
> +
> + /* Remote buffers use externally owned memory. */
> + if (buffer->remote)
> + return 0;
This is a generic interface. If you want to call this function on a remote
buffer, you should be able to.
Moreover, remote buffer in-production current use is for Android... So not only
ring_buffer_memory_size() should support them, but they should probably be
actively reported somewhere...
> +
> + cpu_buffer = buffer->buffers[cpu];
> + subbuf_size = PAGE_SIZE << READ_ONCE(buffer->subbuf_order);
> +
> + /* Data sub-buffers plus the reader page. */
> + size = (READ_ONCE(cpu_buffer->nr_pages) + 1) * subbuf_size;
> +
> + /* The cached read page, if present, is a full sub-buffer page. */
> + if (READ_ONCE(cpu_buffer->free_page.data))
> + size += subbuf_size;
> +
> + /* The mmap metadata page is a single system page. */
> + if (READ_ONCE(cpu_buffer->meta_page))
> + size += PAGE_SIZE;
> +
> + return size;
> +}
> +
> /**
> * ring_buffer_max_event_size - return the max data size of an event
> * @buffer: The ring buffer.
> diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
> index e4a490d3d08c..d4a913ff8a69 100644
> --- a/kernel/trace/trace.c
> +++ b/kernel/trace/trace.c
> @@ -5771,6 +5771,79 @@ tracing_total_entries_read(struct file *filp, char __user *ubuf,
> return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
> }
>
> +struct trace_mem_stats {
> + unsigned long buffers;
> + unsigned long snapshot;
> +};
> +
> +static void
> +trace_array_buffer_memory(struct trace_array *tr, int cpu,
> + unsigned long *buffers, unsigned long *snapshot)
> +{
> + if (tr->array_buffer.buffer)
> + *buffers += ring_buffer_memory_size(tr->array_buffer.buffer, cpu);
> +
> +#ifdef CONFIG_TRACER_SNAPSHOT
> + if (tr->snapshot_buffer.buffer)
> + *snapshot += ring_buffer_memory_size(tr->snapshot_buffer.buffer, cpu);
> +#endif
> +}
> +
> +static struct trace_mem_stats trace_buffers_memory(void)
> +{
> + struct trace_mem_stats stats = {};
> + struct trace_array *tr;
> + int cpu;
> +
> + guard(mutex)(&trace_types_lock);
> +
> + list_for_each_entry(tr, &ftrace_trace_arrays, list) {
> + for_each_tracing_cpu(cpu)
> + trace_array_buffer_memory(tr, cpu, &stats.buffers,
> + &stats.snapshot);
> + }
> +
> + /*
> + * temp_buffer is allocated in tracer_alloc_buffers() and is never
> + * attached to a trace array. It temporarily holds event data for
> + * triggers when tracing is off. Account for its pages too.
> + */
> + if (temp_buffer) {
> + for_each_tracing_cpu(cpu)
> + stats.buffers += ring_buffer_memory_size(temp_buffer, cpu);
> + }
> +
> + return stats;
> +}
> +
> +static int trace_mem_show(struct seq_file *m, void *v)
> +{
> + struct trace_mem_stats stats = trace_buffers_memory();
> +
> + seq_printf(m, "buffers: %lu\n", stats.buffers >> 10);
> + seq_printf(m, "snapshot_buffers: %lu\n", stats.snapshot >> 10);
> +
> + return 0;
> +}
> +
> +static int trace_mem_open(struct inode *inode, struct file *file)
> +{
> + int ret;
> +
> + ret = tracing_check_open_get_tr(NULL);
> + if (ret)
> + return ret;
> +
> + return single_open(file, trace_mem_show, inode->i_private);
> +}
> +
> +static const struct file_operations trace_mem_fops = {
> + .open = trace_mem_open,
> + .read = seq_read,
> + .llseek = seq_lseek,
> + .release = single_release,
> +};
> +
> #define LAST_BOOT_HEADER ((void *)1)
>
> static void *l_next(struct seq_file *m, void *v, loff_t *pos)
> @@ -9285,6 +9358,26 @@ static struct notifier_block trace_module_nb = {
> };
> #endif /* CONFIG_MODULES */
>
> +static __init void init_trace_stats_tracefs(void)
> +{
> + struct dentry *stats_dir;
> +
> + /*
> + * tracer_alloc_buffers() frees tracing_buffer_mask and temp_buffer
> + * on failure without NULLing them, so do not iterate tracing CPUs
> + * here when tracing failed to initialize.
> + */
> + if (tracing_disabled)
> + return;
> +
> + stats_dir = tracefs_create_dir("trace_stats", NULL);
> + if (!stats_dir)
> + return;
> +
> + trace_create_file("memory_usage_kb", TRACE_MODE_READ, stats_dir,
> + NULL, &trace_mem_fops);
> +}
> +
> static __init void tracer_init_tracefs_work_func(struct work_struct *work)
> {
>
> @@ -9293,6 +9386,8 @@ static __init void tracer_init_tracefs_work_func(struct work_struct *work)
> init_tracer_tracefs(&global_trace, NULL);
> ftrace_init_tracefs_toplevel(&global_trace, NULL);
>
> + init_trace_stats_tracefs();
> +
> trace_create_file("tracing_thresh", TRACE_MODE_WRITE, NULL,
> &global_trace, &tracing_thresh_fops);
>
> --
> 2.34.1
>
--
Vincent
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v4 2/2] tracing: add per-CPU memory usage statistics in tracefs
2026-09-21 11:30 ` [PATCH v4 2/2] tracing: add per-CPU " Xiang Gao
@ 2026-09-22 9:42 ` Vincent Donnefort
2026-09-24 1:36 ` Masami Hiramatsu
1 sibling, 0 replies; 24+ messages in thread
From: Vincent Donnefort @ 2026-09-22 9:42 UTC (permalink / raw)
To: Xiang Gao
Cc: Steven Rostedt, Donggeun Yoo, Masami Hiramatsu, Mathieu Desnoyers,
Lorenzo Stoakes, gao xu, yinchuang1, linux-trace-kernel,
linux-kernel, Xiang Gao
On Mon, Sep 21, 2026 at 07:30:46PM +0800, Xiang Gao wrote:
> Provide a per-CPU view of the tracing ring-buffer memory usage under
> trace_stats/per_cpu/cpuN/memory_usage_kb, using the same format as the
> aggregate file. Each file reports only the buffers belonging to that CPU
> across the global trace array and all tracing instances.
>
> Signed-off-by: Xiang Gao <gaoxiang17@xiaomi.com>
> ---
> Documentation/trace/ftrace.rst | 3 ++
> kernel/trace/trace.c | 67 +++++++++++++++++++++++++++++++++-
> 2 files changed, 69 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst
> index 99ddfe26b7cd..e53cdd8d6702 100644
> --- a/Documentation/trace/ftrace.rst
> +++ b/Documentation/trace/ftrace.rst
> @@ -230,6 +230,9 @@ of ftrace. Here is a list of some of the key files:
> buffers: ...
> snapshot_buffers: ...
>
> + The same file is provided under trace_stats/per_cpu/cpuN/, reporting
> + only the buffers belonging to that CPU.
> +
> buffer_subbuf_size_kb:
Could you split the documentation part into a different commit?
>
> This sets or displays the sub buffer size. The ring buffer is broken up
> diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
> index d4a913ff8a69..4010f28f3ebf 100644
> --- a/kernel/trace/trace.c
> +++ b/kernel/trace/trace.c
> @@ -5844,6 +5844,52 @@ static const struct file_operations trace_mem_fops = {
> .release = single_release,
> };
>
> +static struct trace_mem_stats trace_buffers_memory_cpu(int cpu)
> +{
> + struct trace_mem_stats stats = {};
> + struct trace_array *tr;
> +
> + guard(mutex)(&trace_types_lock);
> +
> + list_for_each_entry(tr, &ftrace_trace_arrays, list)
> + trace_array_buffer_memory(tr, cpu, &stats.buffers,
> + &stats.snapshot);
> +
> + /* Account for the bootstrapping temp_buffer as well. */
> + if (temp_buffer)
> + stats.buffers += ring_buffer_memory_size(temp_buffer, cpu);
> +
> + return stats;
> +}
> +
> +static int trace_mem_per_cpu_show(struct seq_file *m, void *v)
> +{
> + struct trace_mem_stats stats = trace_buffers_memory_cpu((long)m->private);
> +
> + seq_printf(m, "buffers: %lu\n", stats.buffers >> 10);
> + seq_printf(m, "snapshot_buffers: %lu\n", stats.snapshot >> 10);
> +
> + return 0;
> +}
> +
> +static int trace_mem_per_cpu_open(struct inode *inode, struct file *file)
> +{
> + int ret;
> +
> + ret = tracing_check_open_get_tr(NULL);
> + if (ret)
> + return ret;
> +
> + return single_open(file, trace_mem_per_cpu_show, inode->i_private);
> +}
> +
> +static const struct file_operations trace_mem_per_cpu_fops = {
> + .open = trace_mem_per_cpu_open,
> + .read = seq_read,
> + .llseek = seq_lseek,
> + .release = single_release,
> +};
> +
> #define LAST_BOOT_HEADER ((void *)1)
>
> static void *l_next(struct seq_file *m, void *v, loff_t *pos)
> @@ -9360,7 +9406,9 @@ static struct notifier_block trace_module_nb = {
>
> static __init void init_trace_stats_tracefs(void)
> {
> - struct dentry *stats_dir;
> + struct dentry *stats_dir, *per_cpu_dir, *cpu_dir;
> + char cpu_dir_name[30];
> + int cpu;
>
> /*
> * tracer_alloc_buffers() frees tracing_buffer_mask and temp_buffer
> @@ -9376,6 +9424,23 @@ static __init void init_trace_stats_tracefs(void)
>
> trace_create_file("memory_usage_kb", TRACE_MODE_READ, stats_dir,
> NULL, &trace_mem_fops);
> +
> + per_cpu_dir = tracefs_create_dir("per_cpu", stats_dir);
> + if (!per_cpu_dir)
> + return;
> +
> + for_each_tracing_cpu(cpu) {
> + snprintf(cpu_dir_name, 30, "cpu%d", cpu);
> + cpu_dir = tracefs_create_dir(cpu_dir_name, per_cpu_dir);
> + if (!cpu_dir) {
> + pr_warn("Could not create tracefs '%s' entry\n",
> + cpu_dir_name);
> + continue;
> + }
> +
> + trace_create_file("memory_usage_kb", TRACE_MODE_READ, cpu_dir,
> + (void *)(long)cpu, &trace_mem_per_cpu_fops);
> + }
> }
>
> static __init void tracer_init_tracefs_work_func(struct work_struct *work)
> --
> 2.34.1
>
--
Vincent
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v4 1/2] tracing: add ring-buffer memory usage statistics in tracefs
2026-09-22 9:41 ` Vincent Donnefort
@ 2026-09-24 1:27 ` Masami Hiramatsu
2026-09-24 8:54 ` Vincent Donnefort
0 siblings, 1 reply; 24+ messages in thread
From: Masami Hiramatsu @ 2026-09-24 1:27 UTC (permalink / raw)
To: Vincent Donnefort
Cc: Xiang Gao, Steven Rostedt, Donggeun Yoo, Masami Hiramatsu,
Mathieu Desnoyers, Lorenzo Stoakes, gao xu, yinchuang1,
linux-trace-kernel, linux-kernel, Xiang Gao
On Tue, 22 Sep 2026 10:41:30 +0100
Vincent Donnefort <vdonnefort@google.com> wrote:
> On Mon, Sep 21, 2026 at 07:30:45PM +0800, Xiang Gao wrote:
> > Report the memory consumed by the tracing ring buffers, rather than the
> > usable data capacity exposed by buffer_size_kb. Android low-memory
> > diagnostics need this to attribute the memory used by tracing when
> > calculating lost RAM.
> >
> > The buffers can be spread across the global trace array, dynamically
> > created instances, and snapshot buffers. Userspace currently has to
> > discover and sum every instance, and snapshot memory is not exposed by
> > the per-instance totals.
> >
> > Add a trace_stats directory with memory_usage_kb reporting:
> >
> > buffers:
> > snapshot_buffers:
> >
> > covering the global trace array, all instances, and the bootstrapping
> > temp_buffer across all CPUs.
> >
> > The values account for the full pages backing the data sub-buffers and
> > reader page, plus the cached read page and mmap metadata page when
> > present. Slab-allocated ring-buffer metadata is not included, as it is
> > already reported through Slab and would be double-counted when
> > subtracting tracing memory from lost RAM. Remote buffers, whose pages
> > are externally owned, report zero.
>
> For the next version, it is good practice to __not__ in-reply-to with previous
> version.
>
Indeed. This is hard to find which is the latest version.
> >
> > Signed-off-by: Xiang Gao <gaoxiang17@xiaomi.com>
> > ---
> > Documentation/trace/ftrace.rst | 12 +++++
> > include/linux/ring_buffer.h | 1 +
> > kernel/trace/ring_buffer.c | 41 +++++++++++++++
> > kernel/trace/trace.c | 95 ++++++++++++++++++++++++++++++++++
> > 4 files changed, 149 insertions(+)
> >
> > diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst
> > index 7261f25f8b4b..99ddfe26b7cd 100644
> > --- a/Documentation/trace/ftrace.rst
> > +++ b/Documentation/trace/ftrace.rst
> > @@ -218,6 +218,18 @@ of ftrace. Here is a list of some of the key files:
> >
> > This displays the total combined size of all the trace buffers.
> >
> > + trace_stats/memory_usage_kb:
> > +
> > + This reports the memory consumed by the ring buffers, as opposed to
> > + the usable data capacity shown by buffer_size_kb. The value covers the
> > + main and snapshot buffers of the global trace array and all tracing
> > + instances. It does not include slab-allocated ring-buffer metadata.
> > +
> > + Output::
> > +
> > + buffers: ...
> > + snapshot_buffers: ...
> > +
> > buffer_subbuf_size_kb:
> >
> > This sets or displays the sub buffer size. The ring buffer is broken up
> > diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
> > index eac3e9080c3c..96b99e6757d4 100644
> > --- a/include/linux/ring_buffer.h
> > +++ b/include/linux/ring_buffer.h
> > @@ -167,6 +167,7 @@ int ring_buffer_iter_empty(struct ring_buffer_iter *iter);
> > bool ring_buffer_iter_dropped(struct ring_buffer_iter *iter);
> >
> > unsigned long ring_buffer_size(struct trace_buffer *buffer, int cpu);
> > +unsigned long ring_buffer_memory_size(struct trace_buffer *buffer, int cpu);
> > unsigned long ring_buffer_max_event_size(struct trace_buffer *buffer);
> >
> > void ring_buffer_reset_cpu(struct trace_buffer *buffer, int cpu);
> > diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
> > index 04bb94c29f58..efb88bf8970c 100644
> > --- a/kernel/trace/ring_buffer.c
> > +++ b/kernel/trace/ring_buffer.c
> > @@ -6559,6 +6559,47 @@ unsigned long ring_buffer_size(struct trace_buffer *buffer, int cpu)
> > }
> > EXPORT_SYMBOL_GPL(ring_buffer_size);
> >
> > +/**
> > + * ring_buffer_memory_size - return the memory used by the buffer (in bytes)
> > + * @buffer: The ring buffer.
> > + * @cpu: The CPU to get ring buffer memory from.
> > + *
> > + * Returns the page-allocator memory consumed by @cpu, including the data
> > + * sub-buffers, the reader page, the cached read page, and the mmap
> > + * metadata page. Unlike ring_buffer_size(), which reports the usable data
> > + * capacity, this accounts for the full pages allocated to the buffer.
> > + * Remote buffers do not own page-allocator memory and report zero.
> > + */
> > +unsigned long ring_buffer_memory_size(struct trace_buffer *buffer, int cpu)
> > +{
> > + struct ring_buffer_per_cpu *cpu_buffer;
> > + unsigned long subbuf_size;
> > + unsigned long size;
> > +
> > + if (!cpumask_test_cpu(cpu, buffer->cpumask))
> > + return 0;
> > +
> > + /* Remote buffers use externally owned memory. */
> > + if (buffer->remote)
> > + return 0;
For the persistent ring buffer, you also need to check `buffer->range_addr_start`.
That is a reserved memory, which is outside of page allocator.
>
> This is a generic interface. If you want to call this function on a remote
> buffer, you should be able to.
But as the comment said, this function returns the size of page-allocator
memory. Is remote ring buffer allocated from host?
>
> Moreover, remote buffer in-production current use is for Android... So not only
> ring_buffer_memory_size() should support them, but they should probably be
> actively reported somewhere...
Maybe we should have different size accounting interface for remote buffer
and persistent buffer.
Thanks,
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v4 2/2] tracing: add per-CPU memory usage statistics in tracefs
2026-09-21 11:30 ` [PATCH v4 2/2] tracing: add per-CPU " Xiang Gao
2026-09-22 9:42 ` Vincent Donnefort
@ 2026-09-24 1:36 ` Masami Hiramatsu
1 sibling, 0 replies; 24+ messages in thread
From: Masami Hiramatsu @ 2026-09-24 1:36 UTC (permalink / raw)
To: Xiang Gao
Cc: Steven Rostedt, Vincent Donnefort, Donggeun Yoo, Masami Hiramatsu,
Mathieu Desnoyers, Lorenzo Stoakes, gao xu, yinchuang1,
linux-trace-kernel, linux-kernel, Xiang Gao
On Mon, 21 Sep 2026 19:30:46 +0800
Xiang Gao <gxxa03070307@gmail.com> wrote:
> +static struct trace_mem_stats trace_buffers_memory_cpu(int cpu)
> +{
> + struct trace_mem_stats stats = {};
> + struct trace_array *tr;
> +
> + guard(mutex)(&trace_types_lock);
> +
> + list_for_each_entry(tr, &ftrace_trace_arrays, list)
> + trace_array_buffer_memory(tr, cpu, &stats.buffers,
> + &stats.snapshot);
> +
> + /* Account for the bootstrapping temp_buffer as well. */
> + if (temp_buffer)
> + stats.buffers += ring_buffer_memory_size(temp_buffer, cpu);
> +
> + return stats;
> +}
> +
> +static int trace_mem_per_cpu_show(struct seq_file *m, void *v)
> +{
> + struct trace_mem_stats stats = trace_buffers_memory_cpu((long)m->private);
> +
> + seq_printf(m, "buffers: %lu\n", stats.buffers >> 10);
> + seq_printf(m, "snapshot_buffers: %lu\n", stats.snapshot >> 10);
> +
> + return 0;
> +}
> +
> +static int trace_mem_per_cpu_open(struct inode *inode, struct file *file)
> +{
> + int ret;
> +
> + ret = tracing_check_open_get_tr(NULL);
> + if (ret)
> + return ret;
> +
> + return single_open(file, trace_mem_per_cpu_show, inode->i_private);
> +}
> +
> +static const struct file_operations trace_mem_per_cpu_fops = {
> + .open = trace_mem_per_cpu_open,
> + .read = seq_read,
> + .llseek = seq_lseek,
> + .release = single_release,
> +};
> +
These functions seems like a dead copy of non-per-cpu version. Can you
reuse the same code?
Thank you,
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v4 1/2] tracing: add ring-buffer memory usage statistics in tracefs
2026-09-24 1:27 ` Masami Hiramatsu
@ 2026-09-24 8:54 ` Vincent Donnefort
2026-09-25 1:09 ` Masami Hiramatsu
0 siblings, 1 reply; 24+ messages in thread
From: Vincent Donnefort @ 2026-09-24 8:54 UTC (permalink / raw)
To: Masami Hiramatsu
Cc: Xiang Gao, Steven Rostedt, Donggeun Yoo, Mathieu Desnoyers,
Lorenzo Stoakes, gao xu, yinchuang1, linux-trace-kernel,
linux-kernel, Xiang Gao
On Thu, Sep 24, 2026 at 10:27:55AM +0900, Masami Hiramatsu wrote:
> On Tue, 22 Sep 2026 10:41:30 +0100
> Vincent Donnefort <vdonnefort@google.com> wrote:
>
> > On Mon, Sep 21, 2026 at 07:30:45PM +0800, Xiang Gao wrote:
> > > Report the memory consumed by the tracing ring buffers, rather than the
> > > usable data capacity exposed by buffer_size_kb. Android low-memory
> > > diagnostics need this to attribute the memory used by tracing when
> > > calculating lost RAM.
> > >
> > > The buffers can be spread across the global trace array, dynamically
> > > created instances, and snapshot buffers. Userspace currently has to
> > > discover and sum every instance, and snapshot memory is not exposed by
> > > the per-instance totals.
> > >
> > > Add a trace_stats directory with memory_usage_kb reporting:
> > >
> > > buffers:
> > > snapshot_buffers:
> > >
> > > covering the global trace array, all instances, and the bootstrapping
> > > temp_buffer across all CPUs.
> > >
> > > The values account for the full pages backing the data sub-buffers and
> > > reader page, plus the cached read page and mmap metadata page when
> > > present. Slab-allocated ring-buffer metadata is not included, as it is
> > > already reported through Slab and would be double-counted when
> > > subtracting tracing memory from lost RAM. Remote buffers, whose pages
> > > are externally owned, report zero.
> >
> > For the next version, it is good practice to __not__ in-reply-to with previous
> > version.
> >
>
> Indeed. This is hard to find which is the latest version.
>
> > >
> > > Signed-off-by: Xiang Gao <gaoxiang17@xiaomi.com>
> > > ---
> > > Documentation/trace/ftrace.rst | 12 +++++
> > > include/linux/ring_buffer.h | 1 +
> > > kernel/trace/ring_buffer.c | 41 +++++++++++++++
> > > kernel/trace/trace.c | 95 ++++++++++++++++++++++++++++++++++
> > > 4 files changed, 149 insertions(+)
> > >
> > > diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst
> > > index 7261f25f8b4b..99ddfe26b7cd 100644
> > > --- a/Documentation/trace/ftrace.rst
> > > +++ b/Documentation/trace/ftrace.rst
> > > @@ -218,6 +218,18 @@ of ftrace. Here is a list of some of the key files:
> > >
> > > This displays the total combined size of all the trace buffers.
> > >
> > > + trace_stats/memory_usage_kb:
> > > +
> > > + This reports the memory consumed by the ring buffers, as opposed to
> > > + the usable data capacity shown by buffer_size_kb. The value covers the
> > > + main and snapshot buffers of the global trace array and all tracing
> > > + instances. It does not include slab-allocated ring-buffer metadata.
> > > +
> > > + Output::
> > > +
> > > + buffers: ...
> > > + snapshot_buffers: ...
> > > +
> > > buffer_subbuf_size_kb:
> > >
> > > This sets or displays the sub buffer size. The ring buffer is broken up
> > > diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
> > > index eac3e9080c3c..96b99e6757d4 100644
> > > --- a/include/linux/ring_buffer.h
> > > +++ b/include/linux/ring_buffer.h
> > > @@ -167,6 +167,7 @@ int ring_buffer_iter_empty(struct ring_buffer_iter *iter);
> > > bool ring_buffer_iter_dropped(struct ring_buffer_iter *iter);
> > >
> > > unsigned long ring_buffer_size(struct trace_buffer *buffer, int cpu);
> > > +unsigned long ring_buffer_memory_size(struct trace_buffer *buffer, int cpu);
> > > unsigned long ring_buffer_max_event_size(struct trace_buffer *buffer);
> > >
> > > void ring_buffer_reset_cpu(struct trace_buffer *buffer, int cpu);
> > > diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
> > > index 04bb94c29f58..efb88bf8970c 100644
> > > --- a/kernel/trace/ring_buffer.c
> > > +++ b/kernel/trace/ring_buffer.c
> > > @@ -6559,6 +6559,47 @@ unsigned long ring_buffer_size(struct trace_buffer *buffer, int cpu)
> > > }
> > > EXPORT_SYMBOL_GPL(ring_buffer_size);
> > >
> > > +/**
> > > + * ring_buffer_memory_size - return the memory used by the buffer (in bytes)
> > > + * @buffer: The ring buffer.
> > > + * @cpu: The CPU to get ring buffer memory from.
> > > + *
> > > + * Returns the page-allocator memory consumed by @cpu, including the data
> > > + * sub-buffers, the reader page, the cached read page, and the mmap
> > > + * metadata page. Unlike ring_buffer_size(), which reports the usable data
> > > + * capacity, this accounts for the full pages allocated to the buffer.
> > > + * Remote buffers do not own page-allocator memory and report zero.
> > > + */
> > > +unsigned long ring_buffer_memory_size(struct trace_buffer *buffer, int cpu)
> > > +{
> > > + struct ring_buffer_per_cpu *cpu_buffer;
> > > + unsigned long subbuf_size;
> > > + unsigned long size;
> > > +
> > > + if (!cpumask_test_cpu(cpu, buffer->cpumask))
> > > + return 0;
> > > +
> > > + /* Remote buffers use externally owned memory. */
> > > + if (buffer->remote)
> > > + return 0;
>
> For the persistent ring buffer, you also need to check `buffer->range_addr_start`.
> That is a reserved memory, which is outside of page allocator.
>
> >
> > This is a generic interface. If you want to call this function on a remote
> > buffer, you should be able to.
>
> But as the comment said, this function returns the size of page-allocator
> memory. Is remote ring buffer allocated from host?
It is down to the trace_remote implementer where the memory comes from, but
right now, all remote ring buffer are allocated from the buddy allocator.
Although, even coming from a carveout, the low-level function should probably
return something in any case, as it has all the informations it needs and to
stay as generic as possible.
Then, the caller (trace_stat) should know if the information is relevant or not,
or where to account for it. (probably with TRACE_ARRAY_FL_ flags ?). trace_stat
shouldn't report only what's relevant for Android. It can however split the
report between persistent ring-buffers and the others.
Overall, we could have
cat trace_mem
main:
instances:
snapshots:
persistents:
remotes:
total_system:
total_carveout:
Which I believe would be a more accurate picture: First the memory sorted by
"type" of buffers and then by "type of memory".
>
> >
> > Moreover, remote buffer in-production current use is for Android... So not only
> > ring_buffer_memory_size() should support them, but they should probably be
> > actively reported somewhere...
>
> Maybe we should have different size accounting interface for remote buffer
> and persistent buffer.
For the remote, it should probably sit in trace_remote.c, which can call
ring_buffer_memory_size(). trace_stat can then query the memory size from
trace_remote.
And actually I have a pending series where I keep the list of trace_remote [1]
which would be a prerequisite.
[1] https://lore.kernel.org/all/20260817135517.3919534-2-vdonnefort@google.com/
>
> Thanks,
>
> --
> Masami Hiramatsu (Google) <mhiramat@kernel.org>
--
Vincent
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v4 1/2] tracing: add ring-buffer memory usage statistics in tracefs
2026-09-24 8:54 ` Vincent Donnefort
@ 2026-09-25 1:09 ` Masami Hiramatsu
0 siblings, 0 replies; 24+ messages in thread
From: Masami Hiramatsu @ 2026-09-25 1:09 UTC (permalink / raw)
To: Vincent Donnefort
Cc: Xiang Gao, Steven Rostedt, Donggeun Yoo, Mathieu Desnoyers,
Lorenzo Stoakes, gao xu, yinchuang1, linux-trace-kernel,
linux-kernel, Xiang Gao
On Thu, 24 Sep 2026 09:54:28 +0100
Vincent Donnefort <vdonnefort@google.com> wrote:
> On Thu, Sep 24, 2026 at 10:27:55AM +0900, Masami Hiramatsu wrote:
> > On Tue, 22 Sep 2026 10:41:30 +0100
> > Vincent Donnefort <vdonnefort@google.com> wrote:
> >
> > > On Mon, Sep 21, 2026 at 07:30:45PM +0800, Xiang Gao wrote:
> > > > Report the memory consumed by the tracing ring buffers, rather than the
> > > > usable data capacity exposed by buffer_size_kb. Android low-memory
> > > > diagnostics need this to attribute the memory used by tracing when
> > > > calculating lost RAM.
> > > >
> > > > The buffers can be spread across the global trace array, dynamically
> > > > created instances, and snapshot buffers. Userspace currently has to
> > > > discover and sum every instance, and snapshot memory is not exposed by
> > > > the per-instance totals.
> > > >
> > > > Add a trace_stats directory with memory_usage_kb reporting:
> > > >
> > > > buffers:
> > > > snapshot_buffers:
> > > >
> > > > covering the global trace array, all instances, and the bootstrapping
> > > > temp_buffer across all CPUs.
> > > >
> > > > The values account for the full pages backing the data sub-buffers and
> > > > reader page, plus the cached read page and mmap metadata page when
> > > > present. Slab-allocated ring-buffer metadata is not included, as it is
> > > > already reported through Slab and would be double-counted when
> > > > subtracting tracing memory from lost RAM. Remote buffers, whose pages
> > > > are externally owned, report zero.
> > >
> > > For the next version, it is good practice to __not__ in-reply-to with previous
> > > version.
> > >
> >
> > Indeed. This is hard to find which is the latest version.
> >
> > > >
> > > > Signed-off-by: Xiang Gao <gaoxiang17@xiaomi.com>
> > > > ---
> > > > Documentation/trace/ftrace.rst | 12 +++++
> > > > include/linux/ring_buffer.h | 1 +
> > > > kernel/trace/ring_buffer.c | 41 +++++++++++++++
> > > > kernel/trace/trace.c | 95 ++++++++++++++++++++++++++++++++++
> > > > 4 files changed, 149 insertions(+)
> > > >
> > > > diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst
> > > > index 7261f25f8b4b..99ddfe26b7cd 100644
> > > > --- a/Documentation/trace/ftrace.rst
> > > > +++ b/Documentation/trace/ftrace.rst
> > > > @@ -218,6 +218,18 @@ of ftrace. Here is a list of some of the key files:
> > > >
> > > > This displays the total combined size of all the trace buffers.
> > > >
> > > > + trace_stats/memory_usage_kb:
> > > > +
> > > > + This reports the memory consumed by the ring buffers, as opposed to
> > > > + the usable data capacity shown by buffer_size_kb. The value covers the
> > > > + main and snapshot buffers of the global trace array and all tracing
> > > > + instances. It does not include slab-allocated ring-buffer metadata.
> > > > +
> > > > + Output::
> > > > +
> > > > + buffers: ...
> > > > + snapshot_buffers: ...
> > > > +
> > > > buffer_subbuf_size_kb:
> > > >
> > > > This sets or displays the sub buffer size. The ring buffer is broken up
> > > > diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
> > > > index eac3e9080c3c..96b99e6757d4 100644
> > > > --- a/include/linux/ring_buffer.h
> > > > +++ b/include/linux/ring_buffer.h
> > > > @@ -167,6 +167,7 @@ int ring_buffer_iter_empty(struct ring_buffer_iter *iter);
> > > > bool ring_buffer_iter_dropped(struct ring_buffer_iter *iter);
> > > >
> > > > unsigned long ring_buffer_size(struct trace_buffer *buffer, int cpu);
> > > > +unsigned long ring_buffer_memory_size(struct trace_buffer *buffer, int cpu);
> > > > unsigned long ring_buffer_max_event_size(struct trace_buffer *buffer);
> > > >
> > > > void ring_buffer_reset_cpu(struct trace_buffer *buffer, int cpu);
> > > > diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
> > > > index 04bb94c29f58..efb88bf8970c 100644
> > > > --- a/kernel/trace/ring_buffer.c
> > > > +++ b/kernel/trace/ring_buffer.c
> > > > @@ -6559,6 +6559,47 @@ unsigned long ring_buffer_size(struct trace_buffer *buffer, int cpu)
> > > > }
> > > > EXPORT_SYMBOL_GPL(ring_buffer_size);
> > > >
> > > > +/**
> > > > + * ring_buffer_memory_size - return the memory used by the buffer (in bytes)
> > > > + * @buffer: The ring buffer.
> > > > + * @cpu: The CPU to get ring buffer memory from.
> > > > + *
> > > > + * Returns the page-allocator memory consumed by @cpu, including the data
> > > > + * sub-buffers, the reader page, the cached read page, and the mmap
> > > > + * metadata page. Unlike ring_buffer_size(), which reports the usable data
> > > > + * capacity, this accounts for the full pages allocated to the buffer.
> > > > + * Remote buffers do not own page-allocator memory and report zero.
> > > > + */
> > > > +unsigned long ring_buffer_memory_size(struct trace_buffer *buffer, int cpu)
> > > > +{
> > > > + struct ring_buffer_per_cpu *cpu_buffer;
> > > > + unsigned long subbuf_size;
> > > > + unsigned long size;
> > > > +
> > > > + if (!cpumask_test_cpu(cpu, buffer->cpumask))
> > > > + return 0;
> > > > +
> > > > + /* Remote buffers use externally owned memory. */
> > > > + if (buffer->remote)
> > > > + return 0;
> >
> > For the persistent ring buffer, you also need to check `buffer->range_addr_start`.
> > That is a reserved memory, which is outside of page allocator.
> >
> > >
> > > This is a generic interface. If you want to call this function on a remote
> > > buffer, you should be able to.
> >
> > But as the comment said, this function returns the size of page-allocator
> > memory. Is remote ring buffer allocated from host?
>
> It is down to the trace_remote implementer where the memory comes from, but
> right now, all remote ring buffer are allocated from the buddy allocator.
Ah, I got it, its size should be reported via ring_buffer_memory_size().
Hmm, maybe we should add a callback for each trace instance so that it
can return the actual size and the attribute (host memory, guest memory,
reserved memory, or device memory (e.g. GPU memory?))
>
> Although, even coming from a carveout, the low-level function should probably
> return something in any case, as it has all the informations it needs and to
> stay as generic as possible.
>
> Then, the caller (trace_stat) should know if the information is relevant or not,
> or where to account for it. (probably with TRACE_ARRAY_FL_ flags ?). trace_stat
> shouldn't report only what's relevant for Android. It can however split the
> report between persistent ring-buffers and the others.
Yeah, this should return the attribute flag with the memory size.
>
> Overall, we could have
>
> cat trace_mem
>
> main:
> instances:
> snapshots:
> persistents:
> remotes:
>
> total_system:
> total_carveout:
>
> Which I believe would be a more accurate picture: First the memory sorted by
> "type" of buffers and then by "type of memory".
Agreed.
>
>
> >
> > >
> > > Moreover, remote buffer in-production current use is for Android... So not only
> > > ring_buffer_memory_size() should support them, but they should probably be
> > > actively reported somewhere...
> >
> > Maybe we should have different size accounting interface for remote buffer
> > and persistent buffer.
>
> For the remote, it should probably sit in trace_remote.c, which can call
> ring_buffer_memory_size(). trace_stat can then query the memory size from
> trace_remote.
I think the copy of the persistent ring buffer (backup instance) could be
implemented as remote, but the persistent ring buffer itself is not remote
because it is writable. (copy ring buffer is actually like remote, it is
read only, and it should be auto unloaded.)
Thank you,
>
> And actually I have a pending series where I keep the list of trace_remote [1]
> which would be a prerequisite.
>
> [1] https://lore.kernel.org/all/20260817135517.3919534-2-vdonnefort@google.com/
>
> >
> > Thanks,
> >
> > --
> > Masami Hiramatsu (Google) <mhiramat@kernel.org>
>
> --
> Vincent
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
^ permalink raw reply [flat|nested] 24+ messages in thread
end of thread, other threads:[~2026-09-25 1:09 UTC | newest]
Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-05 11:27 [PATCH 0/2] tracing: add ring-buffer memory usage statistics Xiang Gao
2026-09-05 11:27 ` [PATCH 1/2] tracing: add ring-buffer memory usage statistics in tracefs Xiang Gao
2026-09-05 11:38 ` sashiko-bot
2026-09-07 9:26 ` Vincent Donnefort
2026-09-05 11:27 ` [PATCH 2/2] tracing: add per-CPU " Xiang Gao
2026-09-11 15:50 ` [PATCH v2 0/2] tracing: add ring-buffer memory usage statistics Xiang Gao
2026-09-11 15:50 ` [PATCH v2 1/2] tracing: add ring-buffer memory usage statistics in tracefs Xiang Gao
2026-09-11 16:04 ` sashiko-bot
2026-09-13 16:37 ` Donggeun Yoo
2026-09-11 15:50 ` [PATCH v2 2/2] tracing: add per-CPU " Xiang Gao
2026-09-16 6:33 ` [PATCH v3 0/2] tracing: add ring-buffer memory usage statistics Xiang Gao
2026-09-16 6:33 ` [PATCH v3 1/2] tracing: add ring-buffer memory usage statistics in tracefs Xiang Gao
2026-09-16 6:50 ` sashiko-bot
2026-09-16 6:33 ` [PATCH v3 2/2] tracing: add per-CPU " Xiang Gao
2026-09-21 11:30 ` [PATCH v4 0/2] tracing: add ring-buffer memory usage statistics Xiang Gao
2026-09-21 11:30 ` [PATCH v4 1/2] tracing: add ring-buffer memory usage statistics in tracefs Xiang Gao
2026-09-22 9:41 ` Vincent Donnefort
2026-09-24 1:27 ` Masami Hiramatsu
2026-09-24 8:54 ` Vincent Donnefort
2026-09-25 1:09 ` Masami Hiramatsu
2026-09-21 11:30 ` [PATCH v4 2/2] tracing: add per-CPU " Xiang Gao
2026-09-22 9:42 ` Vincent Donnefort
2026-09-24 1:36 ` Masami Hiramatsu
2026-09-11 17:22 ` [PATCH 0/2] tracing: add ring-buffer memory usage statistics Vincent Donnefort
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).