* [PATCH 09/11] media: hantro: Add v4l2_hw run/done traces
From: Detlev Casanova @ 2026-02-12 16:23 UTC (permalink / raw)
To: linux-kernel
Cc: Nicolas Dufresne, Benjamin Gaignard, Philipp Zabel,
Mauro Carvalho Chehab, Heiko Stuebner, Daniel Almeida,
Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers, Hans Verkuil,
Laurent Pinchart, Ricardo Ribalda, Yunke Cao, Detlev Casanova,
Sakari Ailus, Pavan Bobba, James Cowgill, Ma Ke, Jacopo Mondi,
Daniel Scally, linux-media, linux-rockchip, linux-arm-kernel,
linux-trace-kernel, kernel
In-Reply-To: <20260212162328.192217-1-detlev.casanova@collabora.com>
Add the trace calls as well as retrieving the number of clock cycles for
the rockchip_vpu core.
Signed-off-by: Detlev Casanova <detlev.casanova@collabora.com>
---
drivers/media/platform/verisilicon/hantro.h | 1 +
drivers/media/platform/verisilicon/hantro_drv.c | 10 ++++++++++
.../media/platform/verisilicon/rockchip_vpu981_regs.h | 1 +
drivers/media/platform/verisilicon/rockchip_vpu_hw.c | 4 ++++
4 files changed, 16 insertions(+)
diff --git a/drivers/media/platform/verisilicon/hantro.h b/drivers/media/platform/verisilicon/hantro.h
index 0353de154a1e..d5cddc783688 100644
--- a/drivers/media/platform/verisilicon/hantro.h
+++ b/drivers/media/platform/verisilicon/hantro.h
@@ -253,6 +253,7 @@ struct hantro_ctx {
u32 sequence_cap;
u32 sequence_out;
+ u32 hw_cycles;
const struct hantro_fmt *vpu_src_fmt;
struct v4l2_pix_format_mplane src_fmt;
diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c
index 94f58f4e4a4e..8dd26ca32459 100644
--- a/drivers/media/platform/verisilicon/hantro_drv.c
+++ b/drivers/media/platform/verisilicon/hantro_drv.c
@@ -25,6 +25,8 @@
#include <media/videobuf2-core.h>
#include <media/videobuf2-vmalloc.h>
+#include <trace/events/v4l2.h>
+
#include "hantro_v4l2.h"
#include "hantro.h"
#include "hantro_hw.h"
@@ -103,6 +105,9 @@ void hantro_irq_done(struct hantro_dev *vpu,
struct hantro_ctx *ctx =
v4l2_m2m_get_curr_priv(vpu->m2m_dev);
+ if (ctx)
+ trace_v4l2_hw_done(ctx->fh.tgid, ctx->fh.fd, ctx->hw_cycles);
+
/*
* If cancel_delayed_work returns false
* the timeout expired. The watchdog is running,
@@ -125,6 +130,9 @@ void hantro_watchdog(struct work_struct *work)
ctx = v4l2_m2m_get_curr_priv(vpu->m2m_dev);
if (ctx) {
vpu_err("frame processing timed out!\n");
+
+ trace_v4l2_hw_done(ctx->fh.tgid, ctx->fh.fd, ctx->hw_cycles);
+
if (ctx->codec_ops->reset)
ctx->codec_ops->reset(ctx);
hantro_job_finish(vpu, ctx, VB2_BUF_STATE_ERROR);
@@ -189,6 +197,8 @@ static void device_run(void *priv)
if (ctx->codec_ops->run(ctx))
goto err_cancel_job;
+ trace_v4l2_hw_run(ctx->fh.tgid, ctx->fh.fd);
+
return;
err_cancel_job:
diff --git a/drivers/media/platform/verisilicon/rockchip_vpu981_regs.h b/drivers/media/platform/verisilicon/rockchip_vpu981_regs.h
index e4008da64f19..96b85470208b 100644
--- a/drivers/media/platform/verisilicon/rockchip_vpu981_regs.h
+++ b/drivers/media/platform/verisilicon/rockchip_vpu981_regs.h
@@ -451,6 +451,7 @@
#define av1_pp0_dup_ver AV1_DEC_REG(394, 16, 0xff)
#define av1_pp0_dup_hor AV1_DEC_REG(394, 24, 0xff)
+#define AV1_CYCLE_COUNT (AV1_SWREG(63))
#define AV1_TILE_OUT_LU (AV1_SWREG(65))
#define AV1_REFERENCE_Y(i) (AV1_SWREG(67) + ((i) * 0x8))
#define AV1_SEGMENTATION (AV1_SWREG(81))
diff --git a/drivers/media/platform/verisilicon/rockchip_vpu_hw.c b/drivers/media/platform/verisilicon/rockchip_vpu_hw.c
index 02673be9878e..f959151b6645 100644
--- a/drivers/media/platform/verisilicon/rockchip_vpu_hw.c
+++ b/drivers/media/platform/verisilicon/rockchip_vpu_hw.c
@@ -424,6 +424,8 @@ static irqreturn_t rk3588_vpu981_irq(int irq, void *dev_id)
{
struct hantro_dev *vpu = dev_id;
enum vb2_buffer_state state;
+ struct hantro_ctx *ctx =
+ v4l2_m2m_get_curr_priv(vpu->m2m_dev);
u32 status;
status = vdpu_read(vpu, AV1_REG_INTERRUPT);
@@ -433,6 +435,8 @@ static irqreturn_t rk3588_vpu981_irq(int irq, void *dev_id)
vdpu_write(vpu, 0, AV1_REG_INTERRUPT);
vdpu_write(vpu, AV1_REG_CONFIG_DEC_CLK_GATE_E, AV1_REG_CONFIG);
+ ctx->hw_cycles = vdpu_read(vpu, AV1_CYCLE_COUNT);
+
hantro_irq_done(vpu, state);
return IRQ_HANDLED;
--
2.53.0
^ permalink raw reply related
* [PATCH 10/11] media: v4l2: Add callback for show_fdinfo
From: Detlev Casanova @ 2026-02-12 16:23 UTC (permalink / raw)
To: linux-kernel
Cc: Nicolas Dufresne, Benjamin Gaignard, Philipp Zabel,
Mauro Carvalho Chehab, Heiko Stuebner, Daniel Almeida,
Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers, Hans Verkuil,
Laurent Pinchart, Ricardo Ribalda, Yunke Cao, Detlev Casanova,
Sakari Ailus, Pavan Bobba, James Cowgill, Ma Ke, Jacopo Mondi,
Daniel Scally, linux-media, linux-rockchip, linux-arm-kernel,
linux-trace-kernel, kernel
In-Reply-To: <20260212162328.192217-1-detlev.casanova@collabora.com>
Allow v4l2 drivers to add information in the fdinfo file matching the
opened /dev/videoX file.
Signed-off-by: Detlev Casanova <detlev.casanova@collabora.com>
---
drivers/media/v4l2-core/v4l2-dev.c | 10 ++++++++++
include/media/v4l2-dev.h | 1 +
2 files changed, 11 insertions(+)
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index 10a126e50c1c..29c04f5f4c59 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -481,6 +481,15 @@ static int v4l2_release(struct inode *inode, struct file *filp)
return ret;
}
+/* Override for the show_fdinfo function */
+static void v4l2_show_fdinfo(struct seq_file *m, struct file *filp)
+{
+ struct video_device *vdev = video_devdata(filp);
+
+ if (vdev->fops->show_fdinfo)
+ vdev->fops->show_fdinfo(m, filp);
+}
+
static const struct file_operations v4l2_fops = {
.owner = THIS_MODULE,
.read = v4l2_read,
@@ -494,6 +503,7 @@ static const struct file_operations v4l2_fops = {
#endif
.release = v4l2_release,
.poll = v4l2_poll,
+ .show_fdinfo = v4l2_show_fdinfo,
};
/**
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index 2e0f6d2e6a78..1635ab186f21 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -212,6 +212,7 @@ struct v4l2_file_operations {
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct file *);
int (*release) (struct file *);
+ void (*show_fdinfo)(struct seq_file *, struct file *);
};
/*
--
2.53.0
^ permalink raw reply related
* [PATCH 11/11] media: hantro: Add fdinfo callback
From: Detlev Casanova @ 2026-02-12 16:23 UTC (permalink / raw)
To: linux-kernel
Cc: Nicolas Dufresne, Benjamin Gaignard, Philipp Zabel,
Mauro Carvalho Chehab, Heiko Stuebner, Daniel Almeida,
Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers, Hans Verkuil,
Laurent Pinchart, Ricardo Ribalda, Yunke Cao, Detlev Casanova,
Sakari Ailus, Pavan Bobba, James Cowgill, Ma Ke, Jacopo Mondi,
Daniel Scally, linux-media, linux-rockchip, linux-arm-kernel,
linux-trace-kernel, kernel
In-Reply-To: <20260212162328.192217-1-detlev.casanova@collabora.com>
The fdinfo shows the number of buffers in each queue and the total amount
of video buffer memory.
Signed-off-by: Detlev Casanova <detlev.casanova@collabora.com>
---
drivers/media/platform/verisilicon/hantro.h | 1 +
drivers/media/platform/verisilicon/hantro_drv.c | 15 +++++++++++++++
drivers/media/platform/verisilicon/hantro_v4l2.c | 10 +++++++++-
3 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/verisilicon/hantro.h b/drivers/media/platform/verisilicon/hantro.h
index d5cddc783688..9e9fc0658586 100644
--- a/drivers/media/platform/verisilicon/hantro.h
+++ b/drivers/media/platform/verisilicon/hantro.h
@@ -268,6 +268,7 @@ struct hantro_ctx {
const struct hantro_codec_ops *codec_ops;
struct hantro_postproc_ctx postproc;
bool need_postproc;
+ u64 stats_buf_memory;
/* Specific for particular codec modes. */
union {
diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c
index 8dd26ca32459..86d316a8a3e8 100644
--- a/drivers/media/platform/verisilicon/hantro_drv.c
+++ b/drivers/media/platform/verisilicon/hantro_drv.c
@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
+#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <linux/workqueue.h>
@@ -711,6 +712,19 @@ static int hantro_release(struct file *filp)
return 0;
}
+static void hantro_show_fdinfo(struct seq_file *m, struct file *filp)
+{
+ struct hantro_ctx *ctx =
+ container_of(filp->private_data, struct hantro_ctx, fh);
+
+ struct vb2_queue *src_q = v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx);
+ struct vb2_queue *dst_q = v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx);
+
+ seq_printf(m, "src-queued-count: %04u\n", src_q->queued_count);
+ seq_printf(m, "dst-queued-count: %04u\n", dst_q->queued_count);
+ seq_printf(m, "buf-size: %llu\n", ctx->stats_buf_memory);
+}
+
static const struct v4l2_file_operations hantro_fops = {
.owner = THIS_MODULE,
.open = hantro_open,
@@ -718,6 +732,7 @@ static const struct v4l2_file_operations hantro_fops = {
.poll = v4l2_m2m_fop_poll,
.unlocked_ioctl = video_ioctl2,
.mmap = v4l2_m2m_fop_mmap,
+ .show_fdinfo = hantro_show_fdinfo,
};
static const struct of_device_id of_hantro_match[] = {
diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c
index fcf3bd9bcda2..6d129613ea3d 100644
--- a/drivers/media/platform/verisilicon/hantro_v4l2.c
+++ b/drivers/media/platform/verisilicon/hantro_v4l2.c
@@ -820,18 +820,26 @@ hantro_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers,
return -EINVAL;
}
+ ctx->stats_buf_memory = 0;
+
if (*num_planes) {
if (*num_planes != pixfmt->num_planes)
return -EINVAL;
- for (i = 0; i < pixfmt->num_planes; ++i)
+ for (i = 0; i < pixfmt->num_planes; ++i) {
if (sizes[i] < pixfmt->plane_fmt[i].sizeimage)
return -EINVAL;
+ ctx->stats_buf_memory += pixfmt->plane_fmt[i].sizeimage;
+ }
+
+ ctx->stats_buf_memory *= *num_buffers;
+
return 0;
}
*num_planes = pixfmt->num_planes;
for (i = 0; i < pixfmt->num_planes; ++i)
sizes[i] = pixfmt->plane_fmt[i].sizeimage;
+
return 0;
}
--
2.53.0
^ permalink raw reply related
* Re: [PATCH V4] blktrace: log dropped REQ_OP_ZONE_XXX events ver1
From: Damien Le Moal @ 2026-02-12 23:37 UTC (permalink / raw)
To: Chaitanya Kulkarni, axboe
Cc: rostedt, mhiramat, linux-block, linux-trace-kernel
In-Reply-To: <20260211204752.23061-1-kch@nvidia.com>
On 2/12/26 05:47, Chaitanya Kulkarni wrote:
> Add informational messages during blktrace setup when version 1 tools
> are used on kernels with CONFIG_BLK_DEV_ZONED enabled. This alerts users
> that REQ_OP_ZONE_* events will be dropped and suggests upgrading to
> blktrace tools version 2 or later.
>
> The warning is printed once during trace setup to inform users about
> the limitation without spamming the logs during tracing operations.
> Version 2 blktrace tools properly handle zone management operations
> (zone reset, zone open, zone close, zone finish, zone append) that
> were added for zoned block devices.
>
> * With old blktrace tool and this patch :-
>
> blktests (master) # ./check blktrace/
> blktrace/001 (blktrace zone management command tracing) [passed]
> runtime 3.706s ... 3.735s
> blktrace/002 (blktrace ftrace corruption with sysfs trace) [passed]
> runtime 0.479s ... 0.456s
> blktests (master) # dmesg -c
> [ 9455.610899] null_blk: disk nullb0 created
> [ 9455.610916] null_blk: module loaded
> [ 9455.634103] run blktests blktrace/001 at 2026-02-02 15:02:23
> [ 9455.651710] null_blk: nullb1: using native zone append
> [ 9455.662852] null_blk: disk nullb1 created
> *[ 9455.714998] blktrace: nullb1: blktrace events for zone operations will be dropped*
> *[ 9455.715065] blktrace: use blktrace tools version >= 2 to track zone operations*
> [ 9459.480181] null_blk: disk nullb0 created
> [ 9459.480199] null_blk: module loaded
> [ 9459.514464] run blktests blktrace/002 at 2026-02-02 15:02:27
> [ 9459.541772] null_blk: disk nullb1 created
> blktests (master) #
>
> * With new blktrace tools and this patch :-
>
> blktests (master) # ./check blktrace/
> blktrace/001 (blktrace zone management command tracing) [passed]
> runtime 3.735s ... 3.734s
> blktrace/002 (blktrace ftrace corruption with sysfs trace) [passed]
> runtime 0.456s ... 0.496s
> blktests (master) # dmesg -c
> [ 9490.395572] null_blk: disk nullb0 created
> [ 9490.395591] null_blk: module loaded
> [ 9490.419467] run blktests blktrace/001 at 2026-02-02 15:02:58
> [ 9490.436416] null_blk: nullb1: using native zone append
> [ 9490.447806] null_blk: disk nullb1 created
> [ 9494.262176] null_blk: disk nullb0 created
> [ 9494.262195] null_blk: module loaded
> [ 9494.296653] run blktests blktrace/002 at 2026-02-02 15:03:02
> [ 9494.322261] null_blk: disk nullb1 created
> blktests (master) #
>
> This helps users understand why zone operation traces may be missing
> when using older blktrace tool versions with modern kernels that
> support REQ_OP_ZONE_XXX in blktrace.
>
> Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
> Signed-off-by: Chaitanya Kulkarni <kch@nvidia.com>
> ---
>
> V3->V4:-
>
> Replace REQ_OP_ZONE_XXX with "zone operations". (Damien, Jens)
>
> ---
> kernel/trace/blktrace.c | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
> index d031c8d80be4..04b41c698127 100644
> --- a/kernel/trace/blktrace.c
> +++ b/kernel/trace/blktrace.c
> @@ -741,6 +741,12 @@ static void blk_trace_setup_finalize(struct request_queue *q,
> * to underscores for this to work as expected
> */
> strreplace(buts->name, '/', '_');
> + if (version == 1 && IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
> + pr_info("%s: blktrace events for zone operations will be dropped\n",
> + name);
> + pr_info("use blktrace tools version >= 2 to track zone operations\n");
Since this message is split, please keep the same format for the second line. I.e.:
pr_info("%s: use blktrace tools version >= 2 to track zone operations\n",
name);
That will avoid incomprehensible interleaved output of if multiple traces are
started together.
> +
> + }
>
> bt->version = version;
> bt->act_mask = buts->act_mask;
--
Damien Le Moal
Western Digital Research
^ permalink raw reply
* Re: [PATCH] objpool: fix minimum alignment of 'struct objpool_slot'
From: wuqiang.matt @ 2026-02-13 2:15 UTC (permalink / raw)
To: Arnd Bergmann, Masami Hiramatsu
Cc: Arnd Bergmann, Yury Norov, linux-kernel, linux-trace-kernel
In-Reply-To: <20260210103530.3028454-1-arnd@kernel.org>
On 2026/2/10 18:35, Arnd Bergmann wrote:
> From: Arnd Bergmann <arnd@arndb.de>
>
> Members of objpool_slot get passed into try_cmpxchg_release(),
> which does not work on most architectures unless they are
> naturally aligned. Marking the structure as packed makes it
> only byte-aligned, as shown by this (normally disabled) warning:
>
> include/linux/objpool.h:156:56: warning: taking address of packed member of 'struct objpool_slot' may result in an unaligned pointer value [-Waddress-of-packed-member]
> 156 | if (try_cmpxchg_release(&slot->head, &head, head + 1))
> | ~^~~~~~~~~~~~
>
> As the struct members are all tightly packed on all architectures,
> Just remove the '__packed annotation to give it the required
> alignment of the native word size.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> include/linux/objpool.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/include/linux/objpool.h b/include/linux/objpool.h
> index b713a1fe7521..f678b35b20b1 100644
> --- a/include/linux/objpool.h
> +++ b/include/linux/objpool.h
> @@ -56,7 +56,7 @@ struct objpool_slot {
> uint32_t last;
> uint32_t mask;
> void *entries[];
> -} __packed;
> +};
>
> struct objpool_head;
>
Reviewed-by: wuqiang.matt <wuqiang.matt@bytedance.com>
Regards,
Matt Wu
^ permalink raw reply
* [PATCH] function_graph: restore direct mode when callbacks drop to one
From: hu.shengming @ 2026-02-13 2:34 UTC (permalink / raw)
To: rostedt, mhiramat
Cc: mark.rutland, mathieu.desnoyers, linux-kernel, linux-trace-kernel,
zhang.run, yang.tao172, yang.yang29
From: Shengming Hu <hu.shengming@zte.com.cn>
When registering a second fgraph callback, direct path is disabled
and array loop is used instead.
When ftrace_graph_active falls back to one, we try to re-enable direct
mode via ftrace_graph_enable_direct(true, ...).
But ftrace_graph_enable_direct() incorrectly disables the static key
rather than enabling it.
This leaves fgraph_do_direct permanently off after first multi-callback
transition, so direct fast mode is never restored.
Fixes: cc60ee813b503 ("function_graph: Use static_call and branch to optimize entry function")
Signed-off-by: Shengming Hu <hu.shengming@zte.com.cn>
---
kernel/trace/fgraph.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/trace/fgraph.c b/kernel/trace/fgraph.c
index cc48d16be43e..4df766c690f9 100644
--- a/kernel/trace/fgraph.c
+++ b/kernel/trace/fgraph.c
@@ -1303,7 +1303,7 @@ static void ftrace_graph_enable_direct(bool enable_branch, struct fgraph_ops *go
static_call_update(fgraph_func, func);
static_call_update(fgraph_retfunc, retfunc);
if (enable_branch)
- static_branch_disable(&fgraph_do_direct);
+ static_branch_enable(&fgraph_do_direct);
}
static void ftrace_graph_disable_direct(bool disable_branch)
--
2.25.1
^ permalink raw reply related
* Re: [PATCH] function_graph: restore direct mode when callbacks drop to one
From: Steven Rostedt @ 2026-02-13 3:47 UTC (permalink / raw)
To: hu.shengming
Cc: mhiramat, mark.rutland, mathieu.desnoyers, linux-kernel,
linux-trace-kernel, zhang.run, yang.tao172, yang.yang29
In-Reply-To: <202602131034245558BcmEI95X7Sr39QGM8YLl@zte.com.cn>
On Fri, 13 Feb 2026 10:34:24 +0800 (CST)
<hu.shengming@zte.com.cn> wrote:
> From: Shengming Hu <hu.shengming@zte.com.cn>
>
> When registering a second fgraph callback, direct path is disabled
> and array loop is used instead.
> When ftrace_graph_active falls back to one, we try to re-enable direct
> mode via ftrace_graph_enable_direct(true, ...).
> But ftrace_graph_enable_direct() incorrectly disables the static key
> rather than enabling it.
> This leaves fgraph_do_direct permanently off after first multi-callback
> transition, so direct fast mode is never restored.
Good catch!
>
> Fixes: cc60ee813b503 ("function_graph: Use static_call and branch to optimize entry function")
> Signed-off-by: Shengming Hu <hu.shengming@zte.com.cn>
> ---
> kernel/trace/fgraph.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/kernel/trace/fgraph.c b/kernel/trace/fgraph.c
> index cc48d16be43e..4df766c690f9 100644
> --- a/kernel/trace/fgraph.c
> +++ b/kernel/trace/fgraph.c
> @@ -1303,7 +1303,7 @@ static void ftrace_graph_enable_direct(bool enable_branch, struct fgraph_ops *go
> static_call_update(fgraph_func, func);
> static_call_update(fgraph_retfunc, retfunc);
> if (enable_branch)
> - static_branch_disable(&fgraph_do_direct);
> + static_branch_enable(&fgraph_do_direct);
> }
Your email client killed your patch. it has huge white-space damage.
But because it's such a trivial change, I'll fix it up for you. But
next time please make sure your email client doesn't corrupt your
patches.
Thanks,
-- Steve
>
> static void ftrace_graph_disable_direct(bool disable_branch)
> --
> 2.25.1
^ permalink raw reply
* Re: [PATCH] blk-mq: use NOIO context to prevent deadlock during debugfs creation
From: Yu Kuai @ 2026-02-13 4:08 UTC (permalink / raw)
To: Nilay Shroff, Jens Axboe, ming.lei, hch, Steven Rostedt,
Masami Hiramatsu
Cc: Mathieu Desnoyers, Yi Zhang, Shinichiro Kawasaki, Keith Busch,
Sagi Grimberg, linux-block, linux-nvme, linux-trace-kernel,
linux-kernel, yukuai
In-Reply-To: <88a12e1c-05b6-44de-806e-06a8e2ff7c0a@linux.ibm.com>
Hi
在 2026/2/12 16:46, Nilay Shroff 写道:
>
> On 2/12/26 1:31 PM, Yu Kuai wrote:
>> Creating debugfs entries can trigger fs reclaim, which can enter back
>> into the block layer request_queue. This can cause deadlock if the
>> queue is frozen.
>>
>> Previously, a WARN_ON_ONCE check was used in debugfs_create_files()
>> to detect this condition, but it was racy since the queue can be frozen
>> from another context at any time.
>>
>> Introduce blk_debugfs_mutex_lock()/blk_debugfs_mutex_unlock() helpers
>> that combine the debugfs_mutex with memalloc_noio_save()/restore() to
>> prevent fs reclaim from triggering block I/O. Replace all raw
>> debugfs_mutex lock/unlock pairs with these helpers.
> It looks like there are still a few places where ->debugfs_mutex is
> taken but the code paths do not enter fs-reclaim. For those cases,
> it may not be necessary to wrap the critical section in a NOIO context.
I agree it's not necessary, however I also feel it doesn't matter.
>
> Perhaps it would make sense to provide two separate helper APIs: one
> that acquires ->debugfs_mutex and also saves/restores the NOIO context
> (using memalloc_noio_save()/restore()), and another that simply acquires
> and releases ->debugfs_mutex without entering NOIO. Callers could then
> choose the appropriate helper depending on whether the code path may
> trigger fs-reclaim.
I don't have preference here, I can do this in the next version.
>
> For reference,
> blk_mq_freeze_queue()/blk_mq_unfreeze_queue() vs
> blk_mq_freeze_queue_nomemsave()/blk_mq_unfreeze_queue_nomemrestore()
>
> Thanks,
> --Nilay
--
Thansk,
Kuai
^ permalink raw reply
* Re: [PATCH] blk-mq: use NOIO context to prevent deadlock during debugfs creation
From: Ming Lei @ 2026-02-13 4:43 UTC (permalink / raw)
To: Yu Kuai
Cc: Jens Axboe, nilay, hch, Steven Rostedt, Masami Hiramatsu,
Mathieu Desnoyers, Yi Zhang, Shinichiro Kawasaki, Keith Busch,
Sagi Grimberg, linux-block, linux-nvme, linux-trace-kernel,
linux-kernel
In-Reply-To: <20260212080135.1673063-1-yukuai@fnnas.com>
On Thu, Feb 12, 2026 at 04:01:35PM +0800, Yu Kuai wrote:
> Creating debugfs entries can trigger fs reclaim, which can enter back
> into the block layer request_queue. This can cause deadlock if the
> queue is frozen.
>
> Previously, a WARN_ON_ONCE check was used in debugfs_create_files()
> to detect this condition, but it was racy since the queue can be frozen
> from another context at any time.
debugfs lock doesn't depend on queue freeze, so the implied deadlock isn't
obvious.
Can you explain a bit why freeze from another context may cause dead lock?
Thanks,
Ming
^ permalink raw reply
* Re: [PATCH] blk-mq: use NOIO context to prevent deadlock during debugfs creation
From: Yu Kuai @ 2026-02-13 5:39 UTC (permalink / raw)
To: Ming Lei
Cc: Jens Axboe, nilay, hch, Steven Rostedt, Masami Hiramatsu,
Mathieu Desnoyers, Yi Zhang, Shinichiro Kawasaki, Keith Busch,
Sagi Grimberg, linux-block, linux-nvme, linux-trace-kernel,
linux-kernel, yukuai
In-Reply-To: <aY6sDstii_R_zOfs@fedora>
Hi,
在 2026/2/13 12:43, Ming Lei 写道:
> On Thu, Feb 12, 2026 at 04:01:35PM +0800, Yu Kuai wrote:
>> Creating debugfs entries can trigger fs reclaim, which can enter back
>> into the block layer request_queue. This can cause deadlock if the
>> queue is frozen.
>>
>> Previously, a WARN_ON_ONCE check was used in debugfs_create_files()
>> to detect this condition, but it was racy since the queue can be frozen
>> from another context at any time.
> debugfs lock doesn't depend on queue freeze, so the implied deadlock isn't
> obvious.
>
> Can you explain a bit why freeze from another context may cause dead lock?
It's probably fine to freeze from another context concurrently, I mean the
checking will cause the false warning like:
Re: [bug report] WARNING: block/blk-mq-debugfs.c:620 at
debugfs_create_files.isra.0+0x54/0x60, CPU#220: kworker/u1036:7/70421 -
Shinichiro Kawasaki <https://lore.kernel.org/all/aYWQR7CtYdk3K39g@shinmob/>
So checking itself is racy and should be removed, meanwhile there are two options:
1) use noio for debugfs creation;
2) move debugfs creation out of queue frozen from nvme target;
BTW, I added the blk_queue_enter/exit() protection for 2 because I think it's
safe, and can prevent deadlock if there are any implied deadlock related to
queue frozen.
>
>
> Thanks,
> Ming
>
>
--
Thansk,
Kuai
^ permalink raw reply
* [PATCH RESEND] function_graph: restore direct mode when callbacks drop to one
From: hu.shengming @ 2026-02-13 6:29 UTC (permalink / raw)
To: rostedt, mhiramat
Cc: mark.rutland, mathieu.desnoyers, linux-kernel, linux-trace-kernel,
zhang.run, yang.tao172, yang.yang29
From: Shengming Hu <hu.shengming@zte.com.cn>
When registering a second fgraph callback, direct path is disabled
and array loop is used instead.
When ftrace_graph_active falls back to one, we try to re-enable direct
mode via ftrace_graph_enable_direct(true, ...).
But ftrace_graph_enable_direct() incorrectly disables the static key
rather than enabling it.
This leaves fgraph_do_direct permanently off after first multi-callback
transition, so direct fast mode is never restored.
Fixes: cc60ee813b503 ("function_graph: Use static_call and branch to optimize entry function")
Signed-off-by: Shengming Hu <hu.shengming@zte.com.cn>
---
kernel/trace/fgraph.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/trace/fgraph.c b/kernel/trace/fgraph.c
index cc48d16be43e..4df766c690f9 100644
--- a/kernel/trace/fgraph.c
+++ b/kernel/trace/fgraph.c
@@ -1303,7 +1303,7 @@ static void ftrace_graph_enable_direct(bool enable_branch, struct fgraph_ops *go
static_call_update(fgraph_func, func);
static_call_update(fgraph_retfunc, retfunc);
if (enable_branch)
- static_branch_disable(&fgraph_do_direct);
+ static_branch_enable(&fgraph_do_direct);
}
static void ftrace_graph_disable_direct(bool disable_branch)
--
2.25.1
^ permalink raw reply related
* Re: [PATCH] function_graph: restore direct mode when callbacks drop to one
From: hu.shengming @ 2026-02-13 6:34 UTC (permalink / raw)
To: rostedt
Cc: mhiramat, mark.rutland, mathieu.desnoyers, linux-kernel,
linux-trace-kernel, zhang.run, yang.tao172, yang.yang29
In-Reply-To: <20260212224752.4311a58d@fedora>
> On Fri, 13 Feb 2026 10:34:24 +0800 (CST)
> <hu.shengming@zte.com.cn> wrote:
>
> > From: Shengming Hu <hu.shengming@zte.com.cn>
> >
> > When registering a second fgraph callback, direct path is disabled
> > and array loop is used instead.
> > When ftrace_graph_active falls back to one, we try to re-enable direct
> > mode via ftrace_graph_enable_direct(true, ...).
> > But ftrace_graph_enable_direct() incorrectly disables the static key
> > rather than enabling it.
> > This leaves fgraph_do_direct permanently off after first multi-callback
> > transition, so direct fast mode is never restored.
>
> Good catch!
>
> >
> > Fixes: cc60ee813b503 ("function_graph: Use static_call and branch to optimize entry function")
> > Signed-off-by: Shengming Hu <hu.shengming@zte.com.cn>
> > ---
> > kernel/trace/fgraph.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/kernel/trace/fgraph.c b/kernel/trace/fgraph.c
> > index cc48d16be43e..4df766c690f9 100644
> > --- a/kernel/trace/fgraph.c
> > +++ b/kernel/trace/fgraph.c
> > @@ -1303,7 +1303,7 @@ static void ftrace_graph_enable_direct(bool enable_branch, struct fgraph_ops *go
> > static_call_update(fgraph_func, func);
> > static_call_update(fgraph_retfunc, retfunc);
> > if (enable_branch)
> > - static_branch_disable(&fgraph_do_direct);
> > + static_branch_enable(&fgraph_do_direct);
> > }
>
> Your email client killed your patch. it has huge white-space damage.
> But because it's such a trivial change, I'll fix it up for you. But
> next time please make sure your email client doesn't corrupt your
> patches.
>
> Thanks,
>
> -- Steve
Hi Steve,
I’ve identified the cause of the email formatting issue and have resent the patch.
https://lore.kernel.org/linux-trace-kernel/20260213142932519cuWSpEXeS4-UnCvNXnK2P@zte.com.cn/T/#u
Thank you very much for the reminder.
--
With Best Regards,
Shengming
>
> >
> > static void ftrace_graph_disable_direct(bool disable_branch)
> > --
> > 2.25.1
>
^ permalink raw reply
* [PATCH] ring-buffer: Fix possible dereference of uninitialized pointer
From: Daniil Dulov @ 2026-02-13 10:01 UTC (permalink / raw)
To: Steven Rostedt
Cc: Daniil Dulov, Masami Hiramatsu, Mathieu Desnoyers,
open list:TRACING, open list:TRACING, lvc-project,
kernel test robot, Dan Carpenter
There is a pointer head_page in rb_meta_validate_events() which is not
initialized at the beginning of a function. This pointer can be dereferenced
if there is a failure during reader page validation. In this case the control
is passed to "invalid" label where the pointer is dereferenced in a loop.
To fix the issue initialize orig_head and head_page before calling
rb_validate_buffer.
Found by Linux Verification Center (linuxtesting.org) with SVACE.
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
Closes: https://lore.kernel.org/r/202406130130.JtTGRf7W-lkp@intel.com/
Fixes: 5f3b6e839f3c ("ring-buffer: Validate boot range memory events")
Signed-off-by: Daniil Dulov <d.dulov@aladdin.ru>
---
kernel/trace/ring_buffer.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 630221b00838..ad08430347b0 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -1918,6 +1918,8 @@ static void rb_meta_validate_events(struct ring_buffer_per_cpu *cpu_buffer)
if (!meta || !meta->head_buffer)
return;
+ orig_head = head_page = cpu_buffer->head_page;
+
/* Do the reader page first */
ret = rb_validate_buffer(cpu_buffer->reader_page->page, cpu_buffer->cpu);
if (ret < 0) {
@@ -1928,7 +1930,6 @@ static void rb_meta_validate_events(struct ring_buffer_per_cpu *cpu_buffer)
entry_bytes += local_read(&cpu_buffer->reader_page->page->commit);
local_set(&cpu_buffer->reader_page->entries, ret);
- orig_head = head_page = cpu_buffer->head_page;
ts = head_page->page->time_stamp;
/*
--
2.34.1
^ permalink raw reply related
* [PATCH v3 0/5] tools/rtla: Consolidate nr_cpus usage
From: Costa Shulyupin @ 2026-02-13 11:52 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Costa Shulyupin, Crystal Wood,
Wander Lairson Costa, Ivan Pravdin, John Kacur, Tiezhu Yang,
linux-trace-kernel, linux-kernel, bpf
sysconf(_SC_NPROCESSORS_CONF) (via get_nprocs_conf) reflects
cpu_possible_mask, which is fixed at boot time, so querying it
repeatedly is unnecessary.
Replace multiple calls to sysconf(_SC_NPROCESSORS_CONF) with a single
global nr_cpus variable initialized once at startup.
V3:
- Remove unneeded cpus parameter from timerlat BPF functions as
requested by Wander Costa.
v2:
- Add `#pragma once` in timerlat_u.h to avoid redefinition errors with
pre-C23 compilers.
Costa Shulyupin (5):
tools/rtla: Consolidate nr_cpus usage across all tools
tools/rtla: Remove unneeded nr_cpus arguments
tools/rtla: Remove unneeded nr_cpus members
tools/rtla: Remove unneeded nr_cpus from for_each_monitored_cpu
tools/rtla: Remove unneeded cpus parameter from timerlat BPF functions
tools/tracing/rtla/src/common.c | 7 ++-
tools/tracing/rtla/src/common.h | 4 +-
tools/tracing/rtla/src/osnoise_hist.c | 26 +++++------
tools/tracing/rtla/src/osnoise_top.c | 16 ++-----
tools/tracing/rtla/src/timerlat.c | 9 ++--
tools/tracing/rtla/src/timerlat_aa.c | 11 ++---
tools/tracing/rtla/src/timerlat_bpf.c | 19 ++++----
tools/tracing/rtla/src/timerlat_bpf.h | 12 ++---
tools/tracing/rtla/src/timerlat_hist.c | 62 +++++++++++---------------
tools/tracing/rtla/src/timerlat_top.c | 47 +++++++------------
tools/tracing/rtla/src/timerlat_u.c | 9 ++--
tools/tracing/rtla/src/timerlat_u.h | 1 +
tools/tracing/rtla/src/utils.c | 10 +----
13 files changed, 88 insertions(+), 145 deletions(-)
--
2.52.0
^ permalink raw reply
* [PATCH v3 1/5] tools/rtla: Consolidate nr_cpus usage across all tools
From: Costa Shulyupin @ 2026-02-13 11:52 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Costa Shulyupin, Crystal Wood,
Wander Lairson Costa, Ivan Pravdin, John Kacur, Tiezhu Yang,
linux-trace-kernel, linux-kernel, bpf
In-Reply-To: <20260213115234.430232-1-costa.shul@redhat.com>
sysconf(_SC_NPROCESSORS_CONF) (via get_nprocs_conf) reflects
cpu_possible_mask, which is fixed at boot time, so querying it
repeatedly is unnecessary.
Replace multiple calls to sysconf(_SC_NPROCESSORS_CONF) with a single
global nr_cpus variable initialized once at startup.
`#pragma once` in timerlat_u.h is needed for pre-C23 compilers to avoid
redefinition errors.
Signed-off-by: Costa Shulyupin <costa.shul@redhat.com>
---
tools/tracing/rtla/src/common.c | 7 +++++--
tools/tracing/rtla/src/common.h | 2 ++
tools/tracing/rtla/src/osnoise_hist.c | 3 ---
tools/tracing/rtla/src/osnoise_top.c | 7 -------
tools/tracing/rtla/src/timerlat.c | 5 +----
tools/tracing/rtla/src/timerlat_aa.c | 1 -
tools/tracing/rtla/src/timerlat_hist.c | 3 ---
tools/tracing/rtla/src/timerlat_top.c | 7 -------
tools/tracing/rtla/src/timerlat_u.c | 3 +--
tools/tracing/rtla/src/timerlat_u.h | 1 +
tools/tracing/rtla/src/utils.c | 10 +---------
11 files changed, 11 insertions(+), 38 deletions(-)
diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c
index ceff76a62a30..e4cf30a65e82 100644
--- a/tools/tracing/rtla/src/common.c
+++ b/tools/tracing/rtla/src/common.c
@@ -5,12 +5,14 @@
#include <signal.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
#include <getopt.h>
+#include <sys/sysinfo.h>
+
#include "common.h"
struct trace_instance *trace_inst;
volatile int stop_tracing;
+int nr_cpus;
static void stop_trace(int sig)
{
@@ -135,7 +137,7 @@ common_apply_config(struct osnoise_tool *tool, struct common_params *params)
}
if (!params->cpus) {
- for (i = 0; i < sysconf(_SC_NPROCESSORS_CONF); i++)
+ for (i = 0; i < nr_cpus; i++)
CPU_SET(i, ¶ms->monitored_cpus);
}
@@ -183,6 +185,7 @@ int run_tool(struct tool_ops *ops, int argc, char *argv[])
bool stopped;
int retval;
+ nr_cpus = get_nprocs_conf();
params = ops->parse_args(argc, argv);
if (!params)
exit(1);
diff --git a/tools/tracing/rtla/src/common.h b/tools/tracing/rtla/src/common.h
index 7602c5593ef5..32f9c1351209 100644
--- a/tools/tracing/rtla/src/common.h
+++ b/tools/tracing/rtla/src/common.h
@@ -107,6 +107,8 @@ struct common_params {
struct timerlat_u_params user;
};
+extern int nr_cpus;
+
#define for_each_monitored_cpu(cpu, nr_cpus, common) \
for (cpu = 0; cpu < nr_cpus; cpu++) \
if (!(common)->cpus || CPU_ISSET(cpu, &(common)->monitored_cpus))
diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c
index 9d70ea34807f..03ebff34fff4 100644
--- a/tools/tracing/rtla/src/osnoise_hist.c
+++ b/tools/tracing/rtla/src/osnoise_hist.c
@@ -647,9 +647,6 @@ static struct osnoise_tool
*osnoise_init_hist(struct common_params *params)
{
struct osnoise_tool *tool;
- int nr_cpus;
-
- nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
tool = osnoise_init_tool("osnoise_hist");
if (!tool)
diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c
index d54d47947fb4..7dcd2e318205 100644
--- a/tools/tracing/rtla/src/osnoise_top.c
+++ b/tools/tracing/rtla/src/osnoise_top.c
@@ -232,12 +232,8 @@ osnoise_print_stats(struct osnoise_tool *top)
{
struct osnoise_params *params = to_osnoise_params(top->params);
struct trace_instance *trace = &top->trace;
- static int nr_cpus = -1;
int i;
- if (nr_cpus == -1)
- nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
-
if (!params->common.quiet)
clear_terminal(trace->seq);
@@ -495,9 +491,6 @@ osnoise_top_apply_config(struct osnoise_tool *tool)
struct osnoise_tool *osnoise_init_top(struct common_params *params)
{
struct osnoise_tool *tool;
- int nr_cpus;
-
- nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
tool = osnoise_init_tool("osnoise_top");
if (!tool)
diff --git a/tools/tracing/rtla/src/timerlat.c b/tools/tracing/rtla/src/timerlat.c
index 8f8811f7a13b..69856f677fce 100644
--- a/tools/tracing/rtla/src/timerlat.c
+++ b/tools/tracing/rtla/src/timerlat.c
@@ -99,7 +99,7 @@ timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params)
int timerlat_enable(struct osnoise_tool *tool)
{
struct timerlat_params *params = to_timerlat_params(tool->params);
- int retval, nr_cpus, i;
+ int retval, i;
if (params->dma_latency >= 0) {
dma_latency_fd = set_cpu_dma_latency(params->dma_latency);
@@ -115,8 +115,6 @@ int timerlat_enable(struct osnoise_tool *tool)
return -1;
}
- nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
-
for_each_monitored_cpu(i, nr_cpus, ¶ms->common) {
if (save_cpu_idle_disable_state(i) < 0) {
err_msg("Could not save cpu idle state.\n");
@@ -214,7 +212,6 @@ void timerlat_analyze(struct osnoise_tool *tool, bool stopped)
void timerlat_free(struct osnoise_tool *tool)
{
struct timerlat_params *params = to_timerlat_params(tool->params);
- int nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
int i;
timerlat_aa_destroy();
diff --git a/tools/tracing/rtla/src/timerlat_aa.c b/tools/tracing/rtla/src/timerlat_aa.c
index 31e66ea2b144..5766d58709eb 100644
--- a/tools/tracing/rtla/src/timerlat_aa.c
+++ b/tools/tracing/rtla/src/timerlat_aa.c
@@ -1022,7 +1022,6 @@ void timerlat_aa_destroy(void)
*/
int timerlat_aa_init(struct osnoise_tool *tool, int dump_tasks)
{
- int nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
struct timerlat_aa_context *taa_ctx;
int retval;
diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c
index 4e8c38a61197..841118ed84f2 100644
--- a/tools/tracing/rtla/src/timerlat_hist.c
+++ b/tools/tracing/rtla/src/timerlat_hist.c
@@ -1031,9 +1031,6 @@ static struct osnoise_tool
*timerlat_init_hist(struct common_params *params)
{
struct osnoise_tool *tool;
- int nr_cpus;
-
- nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
tool = osnoise_init_tool("timerlat_hist");
if (!tool)
diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c
index 284b74773c2b..3e395ce4fa9f 100644
--- a/tools/tracing/rtla/src/timerlat_top.c
+++ b/tools/tracing/rtla/src/timerlat_top.c
@@ -442,15 +442,11 @@ timerlat_print_stats(struct osnoise_tool *top)
struct timerlat_params *params = to_timerlat_params(top->params);
struct trace_instance *trace = &top->trace;
struct timerlat_top_cpu summary;
- static int nr_cpus = -1;
int i;
if (params->common.aa_only)
return;
- if (nr_cpus == -1)
- nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
-
if (!params->common.quiet)
clear_terminal(trace->seq);
@@ -781,9 +777,6 @@ static struct osnoise_tool
*timerlat_init_top(struct common_params *params)
{
struct osnoise_tool *top;
- int nr_cpus;
-
- nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
top = osnoise_init_tool("timerlat_top");
if (!top)
diff --git a/tools/tracing/rtla/src/timerlat_u.c b/tools/tracing/rtla/src/timerlat_u.c
index ce68e39d25fd..a569fe7f93aa 100644
--- a/tools/tracing/rtla/src/timerlat_u.c
+++ b/tools/tracing/rtla/src/timerlat_u.c
@@ -16,7 +16,7 @@
#include <sys/wait.h>
#include <sys/prctl.h>
-#include "utils.h"
+#include "common.h"
#include "timerlat_u.h"
/*
@@ -131,7 +131,6 @@ static int timerlat_u_send_kill(pid_t *procs, int nr_cpus)
*/
void *timerlat_u_dispatcher(void *data)
{
- int nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
struct timerlat_u_params *params = data;
char proc_name[128];
int procs_count = 0;
diff --git a/tools/tracing/rtla/src/timerlat_u.h b/tools/tracing/rtla/src/timerlat_u.h
index 661511908957..a692331bd1c7 100644
--- a/tools/tracing/rtla/src/timerlat_u.h
+++ b/tools/tracing/rtla/src/timerlat_u.h
@@ -1,4 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
+#pragma once
/*
* Copyright (C) 2023 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org>
*/
diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c
index 0da3b2470c31..8cd1b374b035 100644
--- a/tools/tracing/rtla/src/utils.c
+++ b/tools/tracing/rtla/src/utils.c
@@ -19,7 +19,7 @@
#include <stdio.h>
#include <limits.h>
-#include "utils.h"
+#include "common.h"
#define MAX_MSG_LENGTH 1024
int config_debug;
@@ -119,14 +119,11 @@ int parse_cpu_set(char *cpu_list, cpu_set_t *set)
{
const char *p;
int end_cpu;
- int nr_cpus;
int cpu;
int i;
CPU_ZERO(set);
- nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
-
for (p = cpu_list; *p; ) {
cpu = atoi(p);
if (cpu < 0 || (!cpu && *p != '0') || cpu >= nr_cpus)
@@ -559,7 +556,6 @@ int save_cpu_idle_disable_state(unsigned int cpu)
unsigned int nr_states;
unsigned int state;
int disabled;
- int nr_cpus;
nr_states = cpuidle_state_count(cpu);
@@ -567,7 +563,6 @@ int save_cpu_idle_disable_state(unsigned int cpu)
return 0;
if (saved_cpu_idle_disable_state == NULL) {
- nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
saved_cpu_idle_disable_state = calloc(nr_cpus, sizeof(unsigned int *));
if (!saved_cpu_idle_disable_state)
return -1;
@@ -644,13 +639,10 @@ int restore_cpu_idle_disable_state(unsigned int cpu)
void free_cpu_idle_disable_states(void)
{
int cpu;
- int nr_cpus;
if (!saved_cpu_idle_disable_state)
return;
- nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
-
for (cpu = 0; cpu < nr_cpus; cpu++) {
free(saved_cpu_idle_disable_state[cpu]);
saved_cpu_idle_disable_state[cpu] = NULL;
--
2.52.0
^ permalink raw reply related
* [PATCH v3 2/5] tools/rtla: Remove unneeded nr_cpus arguments
From: Costa Shulyupin @ 2026-02-13 11:52 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Costa Shulyupin, Crystal Wood,
Wander Lairson Costa, Ivan Pravdin, John Kacur, Tiezhu Yang,
linux-trace-kernel, linux-kernel, bpf
In-Reply-To: <20260213115234.430232-1-costa.shul@redhat.com>
nr_cpus does not change at runtime, so passing it through function
arguments is unnecessary.
Use the global nr_cpus instead of propagating it via parameters.
Signed-off-by: Costa Shulyupin <costa.shul@redhat.com>
---
tools/tracing/rtla/src/osnoise_hist.c | 4 ++--
tools/tracing/rtla/src/osnoise_top.c | 4 ++--
tools/tracing/rtla/src/timerlat_bpf.c | 5 ++---
tools/tracing/rtla/src/timerlat_bpf.h | 6 ++----
tools/tracing/rtla/src/timerlat_hist.c | 19 +++++++------------
tools/tracing/rtla/src/timerlat_top.c | 19 +++++++------------
tools/tracing/rtla/src/timerlat_u.c | 6 +++---
7 files changed, 25 insertions(+), 38 deletions(-)
diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c
index 03ebff34fff4..d83ee047a5f5 100644
--- a/tools/tracing/rtla/src/osnoise_hist.c
+++ b/tools/tracing/rtla/src/osnoise_hist.c
@@ -62,7 +62,7 @@ static void osnoise_free_hist_tool(struct osnoise_tool *tool)
* osnoise_alloc_histogram - alloc runtime data
*/
static struct osnoise_hist_data
-*osnoise_alloc_histogram(int nr_cpus, int entries, int bucket_size)
+*osnoise_alloc_histogram(int entries, int bucket_size)
{
struct osnoise_hist_data *data;
int cpu;
@@ -652,7 +652,7 @@ static struct osnoise_tool
if (!tool)
return NULL;
- tool->data = osnoise_alloc_histogram(nr_cpus, params->hist.entries,
+ tool->data = osnoise_alloc_histogram(params->hist.entries,
params->hist.bucket_size);
if (!tool->data)
goto out_err;
diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c
index 7dcd2e318205..73b3ac0dd43b 100644
--- a/tools/tracing/rtla/src/osnoise_top.c
+++ b/tools/tracing/rtla/src/osnoise_top.c
@@ -51,7 +51,7 @@ static void osnoise_free_top_tool(struct osnoise_tool *tool)
/*
* osnoise_alloc_histogram - alloc runtime data
*/
-static struct osnoise_top_data *osnoise_alloc_top(int nr_cpus)
+static struct osnoise_top_data *osnoise_alloc_top(void)
{
struct osnoise_top_data *data;
@@ -496,7 +496,7 @@ struct osnoise_tool *osnoise_init_top(struct common_params *params)
if (!tool)
return NULL;
- tool->data = osnoise_alloc_top(nr_cpus);
+ tool->data = osnoise_alloc_top();
if (!tool->data) {
osnoise_destroy_tool(tool);
return NULL;
diff --git a/tools/tracing/rtla/src/timerlat_bpf.c b/tools/tracing/rtla/src/timerlat_bpf.c
index 05adf18303df..8d5c3a095e41 100644
--- a/tools/tracing/rtla/src/timerlat_bpf.c
+++ b/tools/tracing/rtla/src/timerlat_bpf.c
@@ -191,13 +191,12 @@ int timerlat_bpf_get_hist_value(int key,
int timerlat_bpf_get_summary_value(enum summary_field key,
long long *value_irq,
long long *value_thread,
- long long *value_user,
- int cpus)
+ long long *value_user)
{
return get_value(bpf->maps.summary_irq,
bpf->maps.summary_thread,
bpf->maps.summary_user,
- key, value_irq, value_thread, value_user, cpus);
+ key, value_irq, value_thread, value_user, nr_cpus);
}
/*
diff --git a/tools/tracing/rtla/src/timerlat_bpf.h b/tools/tracing/rtla/src/timerlat_bpf.h
index 169abeaf4363..f4a5476f2abb 100644
--- a/tools/tracing/rtla/src/timerlat_bpf.h
+++ b/tools/tracing/rtla/src/timerlat_bpf.h
@@ -28,8 +28,7 @@ int timerlat_bpf_get_hist_value(int key,
int timerlat_bpf_get_summary_value(enum summary_field key,
long long *value_irq,
long long *value_thread,
- long long *value_user,
- int cpus);
+ long long *value_user);
int timerlat_load_bpf_action_program(const char *program_path);
static inline int have_libbpf_support(void) { return 1; }
#else
@@ -53,8 +52,7 @@ static inline int timerlat_bpf_get_hist_value(int key,
static inline int timerlat_bpf_get_summary_value(enum summary_field key,
long long *value_irq,
long long *value_thread,
- long long *value_user,
- int cpus)
+ long long *value_user)
{
return -1;
}
diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c
index 841118ed84f2..dee5fbf622c3 100644
--- a/tools/tracing/rtla/src/timerlat_hist.c
+++ b/tools/tracing/rtla/src/timerlat_hist.c
@@ -83,7 +83,7 @@ static void timerlat_free_histogram_tool(struct osnoise_tool *tool)
* timerlat_alloc_histogram - alloc runtime data
*/
static struct timerlat_hist_data
-*timerlat_alloc_histogram(int nr_cpus, int entries, int bucket_size)
+*timerlat_alloc_histogram(int entries, int bucket_size)
{
struct timerlat_hist_data *data;
int cpu;
@@ -223,8 +223,7 @@ static int timerlat_hist_bpf_pull_data(struct osnoise_tool *tool)
/* Pull summary */
err = timerlat_bpf_get_summary_value(SUMMARY_COUNT,
- value_irq, value_thread, value_user,
- data->nr_cpus);
+ value_irq, value_thread, value_user);
if (err)
return err;
for (i = 0; i < data->nr_cpus; i++) {
@@ -234,8 +233,7 @@ static int timerlat_hist_bpf_pull_data(struct osnoise_tool *tool)
}
err = timerlat_bpf_get_summary_value(SUMMARY_MIN,
- value_irq, value_thread, value_user,
- data->nr_cpus);
+ value_irq, value_thread, value_user);
if (err)
return err;
for (i = 0; i < data->nr_cpus; i++) {
@@ -245,8 +243,7 @@ static int timerlat_hist_bpf_pull_data(struct osnoise_tool *tool)
}
err = timerlat_bpf_get_summary_value(SUMMARY_MAX,
- value_irq, value_thread, value_user,
- data->nr_cpus);
+ value_irq, value_thread, value_user);
if (err)
return err;
for (i = 0; i < data->nr_cpus; i++) {
@@ -256,8 +253,7 @@ static int timerlat_hist_bpf_pull_data(struct osnoise_tool *tool)
}
err = timerlat_bpf_get_summary_value(SUMMARY_SUM,
- value_irq, value_thread, value_user,
- data->nr_cpus);
+ value_irq, value_thread, value_user);
if (err)
return err;
for (i = 0; i < data->nr_cpus; i++) {
@@ -267,8 +263,7 @@ static int timerlat_hist_bpf_pull_data(struct osnoise_tool *tool)
}
err = timerlat_bpf_get_summary_value(SUMMARY_OVERFLOW,
- value_irq, value_thread, value_user,
- data->nr_cpus);
+ value_irq, value_thread, value_user);
if (err)
return err;
for (i = 0; i < data->nr_cpus; i++) {
@@ -1036,7 +1031,7 @@ static struct osnoise_tool
if (!tool)
return NULL;
- tool->data = timerlat_alloc_histogram(nr_cpus, params->hist.entries,
+ tool->data = timerlat_alloc_histogram(params->hist.entries,
params->hist.bucket_size);
if (!tool->data)
goto out_err;
diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c
index 3e395ce4fa9f..25b4d81b4fe0 100644
--- a/tools/tracing/rtla/src/timerlat_top.c
+++ b/tools/tracing/rtla/src/timerlat_top.c
@@ -62,7 +62,7 @@ static void timerlat_free_top_tool(struct osnoise_tool *tool)
/*
* timerlat_alloc_histogram - alloc runtime data
*/
-static struct timerlat_top_data *timerlat_alloc_top(int nr_cpus)
+static struct timerlat_top_data *timerlat_alloc_top(void)
{
struct timerlat_top_data *data;
int cpu;
@@ -196,8 +196,7 @@ static int timerlat_top_bpf_pull_data(struct osnoise_tool *tool)
/* Pull summary */
err = timerlat_bpf_get_summary_value(SUMMARY_CURRENT,
- value_irq, value_thread, value_user,
- data->nr_cpus);
+ value_irq, value_thread, value_user);
if (err)
return err;
for (i = 0; i < data->nr_cpus; i++) {
@@ -207,8 +206,7 @@ static int timerlat_top_bpf_pull_data(struct osnoise_tool *tool)
}
err = timerlat_bpf_get_summary_value(SUMMARY_COUNT,
- value_irq, value_thread, value_user,
- data->nr_cpus);
+ value_irq, value_thread, value_user);
if (err)
return err;
for (i = 0; i < data->nr_cpus; i++) {
@@ -218,8 +216,7 @@ static int timerlat_top_bpf_pull_data(struct osnoise_tool *tool)
}
err = timerlat_bpf_get_summary_value(SUMMARY_MIN,
- value_irq, value_thread, value_user,
- data->nr_cpus);
+ value_irq, value_thread, value_user);
if (err)
return err;
for (i = 0; i < data->nr_cpus; i++) {
@@ -229,8 +226,7 @@ static int timerlat_top_bpf_pull_data(struct osnoise_tool *tool)
}
err = timerlat_bpf_get_summary_value(SUMMARY_MAX,
- value_irq, value_thread, value_user,
- data->nr_cpus);
+ value_irq, value_thread, value_user);
if (err)
return err;
for (i = 0; i < data->nr_cpus; i++) {
@@ -240,8 +236,7 @@ static int timerlat_top_bpf_pull_data(struct osnoise_tool *tool)
}
err = timerlat_bpf_get_summary_value(SUMMARY_SUM,
- value_irq, value_thread, value_user,
- data->nr_cpus);
+ value_irq, value_thread, value_user);
if (err)
return err;
for (i = 0; i < data->nr_cpus; i++) {
@@ -782,7 +777,7 @@ static struct osnoise_tool
if (!top)
return NULL;
- top->data = timerlat_alloc_top(nr_cpus);
+ top->data = timerlat_alloc_top();
if (!top->data)
goto out_err;
diff --git a/tools/tracing/rtla/src/timerlat_u.c b/tools/tracing/rtla/src/timerlat_u.c
index a569fe7f93aa..03b4e68e8b1e 100644
--- a/tools/tracing/rtla/src/timerlat_u.c
+++ b/tools/tracing/rtla/src/timerlat_u.c
@@ -99,7 +99,7 @@ static int timerlat_u_main(int cpu, struct timerlat_u_params *params)
*
* Return the number of processes that received the kill.
*/
-static int timerlat_u_send_kill(pid_t *procs, int nr_cpus)
+static int timerlat_u_send_kill(pid_t *procs)
{
int killed = 0;
int i, retval;
@@ -169,7 +169,7 @@ void *timerlat_u_dispatcher(void *data)
/* parent */
if (pid == -1) {
- timerlat_u_send_kill(procs, nr_cpus);
+ timerlat_u_send_kill(procs);
debug_msg("Failed to create child processes");
pthread_exit(&retval);
}
@@ -196,7 +196,7 @@ void *timerlat_u_dispatcher(void *data)
sleep(1);
}
- timerlat_u_send_kill(procs, nr_cpus);
+ timerlat_u_send_kill(procs);
while (procs_count) {
pid = waitpid(-1, &wstatus, 0);
--
2.52.0
^ permalink raw reply related
* [PATCH v3 3/5] tools/rtla: Remove unneeded nr_cpus members
From: Costa Shulyupin @ 2026-02-13 11:52 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Costa Shulyupin, Crystal Wood,
Wander Lairson Costa, Ivan Pravdin, John Kacur, Tiezhu Yang,
linux-trace-kernel, linux-kernel, bpf
In-Reply-To: <20260213115234.430232-1-costa.shul@redhat.com>
nr_cpus does not change at runtime, so keeping it in struct members is
unnecessary.
Use the global nr_cpus instead of struct members.
Signed-off-by: Costa Shulyupin <costa.shul@redhat.com>
---
tools/tracing/rtla/src/osnoise_hist.c | 18 ++++++------
tools/tracing/rtla/src/osnoise_top.c | 3 --
tools/tracing/rtla/src/timerlat_aa.c | 10 +++----
tools/tracing/rtla/src/timerlat_hist.c | 40 ++++++++++++--------------
tools/tracing/rtla/src/timerlat_top.c | 19 ++++++------
5 files changed, 39 insertions(+), 51 deletions(-)
diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c
index d83ee047a5f5..90291504a1aa 100644
--- a/tools/tracing/rtla/src/osnoise_hist.c
+++ b/tools/tracing/rtla/src/osnoise_hist.c
@@ -29,7 +29,6 @@ struct osnoise_hist_data {
struct osnoise_hist_cpu *hist;
int entries;
int bucket_size;
- int nr_cpus;
};
/*
@@ -41,7 +40,7 @@ osnoise_free_histogram(struct osnoise_hist_data *data)
int cpu;
/* one histogram for IRQ and one for thread, per CPU */
- for (cpu = 0; cpu < data->nr_cpus; cpu++) {
+ for (cpu = 0; cpu < nr_cpus; cpu++) {
if (data->hist[cpu].samples)
free(data->hist[cpu].samples);
}
@@ -73,7 +72,6 @@ static struct osnoise_hist_data
data->entries = entries;
data->bucket_size = bucket_size;
- data->nr_cpus = nr_cpus;
data->hist = calloc(1, sizeof(*data->hist) * nr_cpus);
if (!data->hist)
@@ -246,7 +244,7 @@ static void osnoise_hist_header(struct osnoise_tool *tool)
if (!params->common.hist.no_index)
trace_seq_printf(s, "Index");
- for_each_monitored_cpu(cpu, data->nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
if (!data->hist[cpu].count)
continue;
@@ -275,7 +273,7 @@ osnoise_print_summary(struct osnoise_params *params,
if (!params->common.hist.no_index)
trace_seq_printf(trace->seq, "count:");
- for_each_monitored_cpu(cpu, data->nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
if (!data->hist[cpu].count)
continue;
@@ -287,7 +285,7 @@ osnoise_print_summary(struct osnoise_params *params,
if (!params->common.hist.no_index)
trace_seq_printf(trace->seq, "min: ");
- for_each_monitored_cpu(cpu, data->nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
if (!data->hist[cpu].count)
continue;
@@ -300,7 +298,7 @@ osnoise_print_summary(struct osnoise_params *params,
if (!params->common.hist.no_index)
trace_seq_printf(trace->seq, "avg: ");
- for_each_monitored_cpu(cpu, data->nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
if (!data->hist[cpu].count)
continue;
@@ -316,7 +314,7 @@ osnoise_print_summary(struct osnoise_params *params,
if (!params->common.hist.no_index)
trace_seq_printf(trace->seq, "max: ");
- for_each_monitored_cpu(cpu, data->nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
if (!data->hist[cpu].count)
continue;
@@ -351,7 +349,7 @@ osnoise_print_stats(struct osnoise_tool *tool)
trace_seq_printf(trace->seq, "%-6d",
bucket * data->bucket_size);
- for_each_monitored_cpu(cpu, data->nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
if (!data->hist[cpu].count)
continue;
@@ -387,7 +385,7 @@ osnoise_print_stats(struct osnoise_tool *tool)
if (!params->common.hist.no_index)
trace_seq_printf(trace->seq, "over: ");
- for_each_monitored_cpu(cpu, data->nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
if (!data->hist[cpu].count)
continue;
diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c
index 73b3ac0dd43b..6fb3e72d74f2 100644
--- a/tools/tracing/rtla/src/osnoise_top.c
+++ b/tools/tracing/rtla/src/osnoise_top.c
@@ -31,7 +31,6 @@ struct osnoise_top_cpu {
struct osnoise_top_data {
struct osnoise_top_cpu *cpu_data;
- int nr_cpus;
};
/*
@@ -59,8 +58,6 @@ static struct osnoise_top_data *osnoise_alloc_top(void)
if (!data)
return NULL;
- data->nr_cpus = nr_cpus;
-
/* one set of histograms per CPU */
data->cpu_data = calloc(1, sizeof(*data->cpu_data) * nr_cpus);
if (!data->cpu_data)
diff --git a/tools/tracing/rtla/src/timerlat_aa.c b/tools/tracing/rtla/src/timerlat_aa.c
index 5766d58709eb..59b219a1503e 100644
--- a/tools/tracing/rtla/src/timerlat_aa.c
+++ b/tools/tracing/rtla/src/timerlat_aa.c
@@ -102,7 +102,6 @@ struct timerlat_aa_data {
* The analysis context and system wide view
*/
struct timerlat_aa_context {
- int nr_cpus;
int dump_tasks;
/* per CPU data */
@@ -738,7 +737,7 @@ void timerlat_auto_analysis(int irq_thresh, int thread_thresh)
irq_thresh = irq_thresh * 1000;
thread_thresh = thread_thresh * 1000;
- for (cpu = 0; cpu < taa_ctx->nr_cpus; cpu++) {
+ for (cpu = 0; cpu < nr_cpus; cpu++) {
taa_data = timerlat_aa_get_data(taa_ctx, cpu);
if (irq_thresh && taa_data->tlat_irq_latency >= irq_thresh) {
@@ -766,7 +765,7 @@ void timerlat_auto_analysis(int irq_thresh, int thread_thresh)
printf("\n");
printf("Printing CPU tasks:\n");
- for (cpu = 0; cpu < taa_ctx->nr_cpus; cpu++) {
+ for (cpu = 0; cpu < nr_cpus; cpu++) {
taa_data = timerlat_aa_get_data(taa_ctx, cpu);
tep = taa_ctx->tool->trace.tep;
@@ -792,7 +791,7 @@ static void timerlat_aa_destroy_seqs(struct timerlat_aa_context *taa_ctx)
if (!taa_ctx->taa_data)
return;
- for (i = 0; i < taa_ctx->nr_cpus; i++) {
+ for (i = 0; i < nr_cpus; i++) {
taa_data = timerlat_aa_get_data(taa_ctx, i);
if (taa_data->prev_irqs_seq) {
@@ -842,7 +841,7 @@ static int timerlat_aa_init_seqs(struct timerlat_aa_context *taa_ctx)
struct timerlat_aa_data *taa_data;
int i;
- for (i = 0; i < taa_ctx->nr_cpus; i++) {
+ for (i = 0; i < nr_cpus; i++) {
taa_data = timerlat_aa_get_data(taa_ctx, i);
@@ -1031,7 +1030,6 @@ int timerlat_aa_init(struct osnoise_tool *tool, int dump_tasks)
__timerlat_aa_ctx = taa_ctx;
- taa_ctx->nr_cpus = nr_cpus;
taa_ctx->tool = tool;
taa_ctx->dump_tasks = dump_tasks;
diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c
index dee5fbf622c3..4bf1489cad23 100644
--- a/tools/tracing/rtla/src/timerlat_hist.c
+++ b/tools/tracing/rtla/src/timerlat_hist.c
@@ -44,7 +44,6 @@ struct timerlat_hist_data {
struct timerlat_hist_cpu *hist;
int entries;
int bucket_size;
- int nr_cpus;
};
/*
@@ -56,7 +55,7 @@ timerlat_free_histogram(struct timerlat_hist_data *data)
int cpu;
/* one histogram for IRQ and one for thread, per CPU */
- for (cpu = 0; cpu < data->nr_cpus; cpu++) {
+ for (cpu = 0; cpu < nr_cpus; cpu++) {
if (data->hist[cpu].irq)
free(data->hist[cpu].irq);
@@ -94,7 +93,6 @@ static struct timerlat_hist_data
data->entries = entries;
data->bucket_size = bucket_size;
- data->nr_cpus = nr_cpus;
/* one set of histograms per CPU */
data->hist = calloc(1, sizeof(*data->hist) * nr_cpus);
@@ -204,17 +202,17 @@ static int timerlat_hist_bpf_pull_data(struct osnoise_tool *tool)
{
struct timerlat_hist_data *data = tool->data;
int i, j, err;
- long long value_irq[data->nr_cpus],
- value_thread[data->nr_cpus],
- value_user[data->nr_cpus];
+ long long value_irq[nr_cpus],
+ value_thread[nr_cpus],
+ value_user[nr_cpus];
/* Pull histogram */
for (i = 0; i < data->entries; i++) {
err = timerlat_bpf_get_hist_value(i, value_irq, value_thread,
- value_user, data->nr_cpus);
+ value_user, nr_cpus);
if (err)
return err;
- for (j = 0; j < data->nr_cpus; j++) {
+ for (j = 0; j < nr_cpus; j++) {
data->hist[j].irq[i] = value_irq[j];
data->hist[j].thread[i] = value_thread[j];
data->hist[j].user[i] = value_user[j];
@@ -226,7 +224,7 @@ static int timerlat_hist_bpf_pull_data(struct osnoise_tool *tool)
value_irq, value_thread, value_user);
if (err)
return err;
- for (i = 0; i < data->nr_cpus; i++) {
+ for (i = 0; i < nr_cpus; i++) {
data->hist[i].irq_count = value_irq[i];
data->hist[i].thread_count = value_thread[i];
data->hist[i].user_count = value_user[i];
@@ -236,7 +234,7 @@ static int timerlat_hist_bpf_pull_data(struct osnoise_tool *tool)
value_irq, value_thread, value_user);
if (err)
return err;
- for (i = 0; i < data->nr_cpus; i++) {
+ for (i = 0; i < nr_cpus; i++) {
data->hist[i].min_irq = value_irq[i];
data->hist[i].min_thread = value_thread[i];
data->hist[i].min_user = value_user[i];
@@ -246,7 +244,7 @@ static int timerlat_hist_bpf_pull_data(struct osnoise_tool *tool)
value_irq, value_thread, value_user);
if (err)
return err;
- for (i = 0; i < data->nr_cpus; i++) {
+ for (i = 0; i < nr_cpus; i++) {
data->hist[i].max_irq = value_irq[i];
data->hist[i].max_thread = value_thread[i];
data->hist[i].max_user = value_user[i];
@@ -256,7 +254,7 @@ static int timerlat_hist_bpf_pull_data(struct osnoise_tool *tool)
value_irq, value_thread, value_user);
if (err)
return err;
- for (i = 0; i < data->nr_cpus; i++) {
+ for (i = 0; i < nr_cpus; i++) {
data->hist[i].sum_irq = value_irq[i];
data->hist[i].sum_thread = value_thread[i];
data->hist[i].sum_user = value_user[i];
@@ -266,7 +264,7 @@ static int timerlat_hist_bpf_pull_data(struct osnoise_tool *tool)
value_irq, value_thread, value_user);
if (err)
return err;
- for (i = 0; i < data->nr_cpus; i++) {
+ for (i = 0; i < nr_cpus; i++) {
data->hist[i].irq[data->entries] = value_irq[i];
data->hist[i].thread[data->entries] = value_thread[i];
data->hist[i].user[data->entries] = value_user[i];
@@ -300,7 +298,7 @@ static void timerlat_hist_header(struct osnoise_tool *tool)
if (!params->common.hist.no_index)
trace_seq_printf(s, "Index");
- for_each_monitored_cpu(cpu, data->nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
continue;
@@ -352,7 +350,7 @@ timerlat_print_summary(struct timerlat_params *params,
if (!params->common.hist.no_index)
trace_seq_printf(trace->seq, "count:");
- for_each_monitored_cpu(cpu, data->nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
continue;
@@ -374,7 +372,7 @@ timerlat_print_summary(struct timerlat_params *params,
if (!params->common.hist.no_index)
trace_seq_printf(trace->seq, "min: ");
- for_each_monitored_cpu(cpu, data->nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
continue;
@@ -402,7 +400,7 @@ timerlat_print_summary(struct timerlat_params *params,
if (!params->common.hist.no_index)
trace_seq_printf(trace->seq, "avg: ");
- for_each_monitored_cpu(cpu, data->nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
continue;
@@ -430,7 +428,7 @@ timerlat_print_summary(struct timerlat_params *params,
if (!params->common.hist.no_index)
trace_seq_printf(trace->seq, "max: ");
- for_each_monitored_cpu(cpu, data->nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
continue;
@@ -475,7 +473,7 @@ timerlat_print_stats_all(struct timerlat_params *params,
sum.min_thread = ~0;
sum.min_user = ~0;
- for_each_monitored_cpu(cpu, data->nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
continue;
@@ -622,7 +620,7 @@ timerlat_print_stats(struct osnoise_tool *tool)
trace_seq_printf(trace->seq, "%-6d",
bucket * data->bucket_size);
- for_each_monitored_cpu(cpu, data->nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
continue;
@@ -660,7 +658,7 @@ timerlat_print_stats(struct osnoise_tool *tool)
if (!params->common.hist.no_index)
trace_seq_printf(trace->seq, "over: ");
- for_each_monitored_cpu(cpu, data->nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
continue;
diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c
index 25b4d81b4fe0..4eb820fe1f21 100644
--- a/tools/tracing/rtla/src/timerlat_top.c
+++ b/tools/tracing/rtla/src/timerlat_top.c
@@ -41,7 +41,6 @@ struct timerlat_top_cpu {
struct timerlat_top_data {
struct timerlat_top_cpu *cpu_data;
- int nr_cpus;
};
/*
@@ -71,8 +70,6 @@ static struct timerlat_top_data *timerlat_alloc_top(void)
if (!data)
return NULL;
- data->nr_cpus = nr_cpus;
-
/* one set of histograms per CPU */
data->cpu_data = calloc(1, sizeof(*data->cpu_data) * nr_cpus);
if (!data->cpu_data)
@@ -190,16 +187,16 @@ static int timerlat_top_bpf_pull_data(struct osnoise_tool *tool)
{
struct timerlat_top_data *data = tool->data;
int i, err;
- long long value_irq[data->nr_cpus],
- value_thread[data->nr_cpus],
- value_user[data->nr_cpus];
+ long long value_irq[nr_cpus],
+ value_thread[nr_cpus],
+ value_user[nr_cpus];
/* Pull summary */
err = timerlat_bpf_get_summary_value(SUMMARY_CURRENT,
value_irq, value_thread, value_user);
if (err)
return err;
- for (i = 0; i < data->nr_cpus; i++) {
+ for (i = 0; i < nr_cpus; i++) {
data->cpu_data[i].cur_irq = value_irq[i];
data->cpu_data[i].cur_thread = value_thread[i];
data->cpu_data[i].cur_user = value_user[i];
@@ -209,7 +206,7 @@ static int timerlat_top_bpf_pull_data(struct osnoise_tool *tool)
value_irq, value_thread, value_user);
if (err)
return err;
- for (i = 0; i < data->nr_cpus; i++) {
+ for (i = 0; i < nr_cpus; i++) {
data->cpu_data[i].irq_count = value_irq[i];
data->cpu_data[i].thread_count = value_thread[i];
data->cpu_data[i].user_count = value_user[i];
@@ -219,7 +216,7 @@ static int timerlat_top_bpf_pull_data(struct osnoise_tool *tool)
value_irq, value_thread, value_user);
if (err)
return err;
- for (i = 0; i < data->nr_cpus; i++) {
+ for (i = 0; i < nr_cpus; i++) {
data->cpu_data[i].min_irq = value_irq[i];
data->cpu_data[i].min_thread = value_thread[i];
data->cpu_data[i].min_user = value_user[i];
@@ -229,7 +226,7 @@ static int timerlat_top_bpf_pull_data(struct osnoise_tool *tool)
value_irq, value_thread, value_user);
if (err)
return err;
- for (i = 0; i < data->nr_cpus; i++) {
+ for (i = 0; i < nr_cpus; i++) {
data->cpu_data[i].max_irq = value_irq[i];
data->cpu_data[i].max_thread = value_thread[i];
data->cpu_data[i].max_user = value_user[i];
@@ -239,7 +236,7 @@ static int timerlat_top_bpf_pull_data(struct osnoise_tool *tool)
value_irq, value_thread, value_user);
if (err)
return err;
- for (i = 0; i < data->nr_cpus; i++) {
+ for (i = 0; i < nr_cpus; i++) {
data->cpu_data[i].sum_irq = value_irq[i];
data->cpu_data[i].sum_thread = value_thread[i];
data->cpu_data[i].sum_user = value_user[i];
--
2.52.0
^ permalink raw reply related
* [PATCH v3 4/5] tools/rtla: Remove unneeded nr_cpus from for_each_monitored_cpu
From: Costa Shulyupin @ 2026-02-13 11:52 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Costa Shulyupin, Crystal Wood,
Wander Lairson Costa, Ivan Pravdin, John Kacur, Tiezhu Yang,
linux-trace-kernel, linux-kernel, bpf
In-Reply-To: <20260213115234.430232-1-costa.shul@redhat.com>
nr_cpus does not change at runtime, so passing it through the macro
argument is unnecessary.
Remove the argument and use the global nr_cpus instead.
Signed-off-by: Costa Shulyupin <costa.shul@redhat.com>
---
tools/tracing/rtla/src/common.h | 2 +-
tools/tracing/rtla/src/osnoise_hist.c | 15 +++++++--------
tools/tracing/rtla/src/osnoise_top.c | 2 +-
tools/tracing/rtla/src/timerlat.c | 4 ++--
tools/tracing/rtla/src/timerlat_hist.c | 16 ++++++++--------
tools/tracing/rtla/src/timerlat_top.c | 2 +-
6 files changed, 20 insertions(+), 21 deletions(-)
diff --git a/tools/tracing/rtla/src/common.h b/tools/tracing/rtla/src/common.h
index 32f9c1351209..28d258d6d178 100644
--- a/tools/tracing/rtla/src/common.h
+++ b/tools/tracing/rtla/src/common.h
@@ -109,7 +109,7 @@ struct common_params {
extern int nr_cpus;
-#define for_each_monitored_cpu(cpu, nr_cpus, common) \
+#define for_each_monitored_cpu(cpu, common) \
for (cpu = 0; cpu < nr_cpus; cpu++) \
if (!(common)->cpus || CPU_ISSET(cpu, &(common)->monitored_cpus))
diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c
index 90291504a1aa..e8f07108d39a 100644
--- a/tools/tracing/rtla/src/osnoise_hist.c
+++ b/tools/tracing/rtla/src/osnoise_hist.c
@@ -244,7 +244,7 @@ static void osnoise_hist_header(struct osnoise_tool *tool)
if (!params->common.hist.no_index)
trace_seq_printf(s, "Index");
- for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, ¶ms->common) {
if (!data->hist[cpu].count)
continue;
@@ -273,8 +273,7 @@ osnoise_print_summary(struct osnoise_params *params,
if (!params->common.hist.no_index)
trace_seq_printf(trace->seq, "count:");
- for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
-
+ for_each_monitored_cpu(cpu, ¶ms->common) {
if (!data->hist[cpu].count)
continue;
@@ -285,7 +284,7 @@ osnoise_print_summary(struct osnoise_params *params,
if (!params->common.hist.no_index)
trace_seq_printf(trace->seq, "min: ");
- for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, ¶ms->common) {
if (!data->hist[cpu].count)
continue;
@@ -298,7 +297,7 @@ osnoise_print_summary(struct osnoise_params *params,
if (!params->common.hist.no_index)
trace_seq_printf(trace->seq, "avg: ");
- for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, ¶ms->common) {
if (!data->hist[cpu].count)
continue;
@@ -314,7 +313,7 @@ osnoise_print_summary(struct osnoise_params *params,
if (!params->common.hist.no_index)
trace_seq_printf(trace->seq, "max: ");
- for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, ¶ms->common) {
if (!data->hist[cpu].count)
continue;
@@ -349,7 +348,7 @@ osnoise_print_stats(struct osnoise_tool *tool)
trace_seq_printf(trace->seq, "%-6d",
bucket * data->bucket_size);
- for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, ¶ms->common) {
if (!data->hist[cpu].count)
continue;
@@ -385,7 +384,7 @@ osnoise_print_stats(struct osnoise_tool *tool)
if (!params->common.hist.no_index)
trace_seq_printf(trace->seq, "over: ");
- for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, ¶ms->common) {
if (!data->hist[cpu].count)
continue;
diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c
index 6fb3e72d74f2..ab5db35f21ae 100644
--- a/tools/tracing/rtla/src/osnoise_top.c
+++ b/tools/tracing/rtla/src/osnoise_top.c
@@ -236,7 +236,7 @@ osnoise_print_stats(struct osnoise_tool *top)
osnoise_top_header(top);
- for_each_monitored_cpu(i, nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(i, ¶ms->common) {
osnoise_top_print(top, i);
}
diff --git a/tools/tracing/rtla/src/timerlat.c b/tools/tracing/rtla/src/timerlat.c
index 69856f677fce..ec14abd45fff 100644
--- a/tools/tracing/rtla/src/timerlat.c
+++ b/tools/tracing/rtla/src/timerlat.c
@@ -115,7 +115,7 @@ int timerlat_enable(struct osnoise_tool *tool)
return -1;
}
- for_each_monitored_cpu(i, nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(i, ¶ms->common) {
if (save_cpu_idle_disable_state(i) < 0) {
err_msg("Could not save cpu idle state.\n");
return -1;
@@ -218,7 +218,7 @@ void timerlat_free(struct osnoise_tool *tool)
if (dma_latency_fd >= 0)
close(dma_latency_fd);
if (params->deepest_idle_state >= -1) {
- for_each_monitored_cpu(i, nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(i, ¶ms->common) {
restore_cpu_idle_disable_state(i);
}
}
diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c
index 4bf1489cad23..db66312ec966 100644
--- a/tools/tracing/rtla/src/timerlat_hist.c
+++ b/tools/tracing/rtla/src/timerlat_hist.c
@@ -298,7 +298,7 @@ static void timerlat_hist_header(struct osnoise_tool *tool)
if (!params->common.hist.no_index)
trace_seq_printf(s, "Index");
- for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, ¶ms->common) {
if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
continue;
@@ -350,7 +350,7 @@ timerlat_print_summary(struct timerlat_params *params,
if (!params->common.hist.no_index)
trace_seq_printf(trace->seq, "count:");
- for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, ¶ms->common) {
if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
continue;
@@ -372,7 +372,7 @@ timerlat_print_summary(struct timerlat_params *params,
if (!params->common.hist.no_index)
trace_seq_printf(trace->seq, "min: ");
- for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, ¶ms->common) {
if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
continue;
@@ -400,7 +400,7 @@ timerlat_print_summary(struct timerlat_params *params,
if (!params->common.hist.no_index)
trace_seq_printf(trace->seq, "avg: ");
- for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, ¶ms->common) {
if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
continue;
@@ -428,7 +428,7 @@ timerlat_print_summary(struct timerlat_params *params,
if (!params->common.hist.no_index)
trace_seq_printf(trace->seq, "max: ");
- for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, ¶ms->common) {
if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
continue;
@@ -473,7 +473,7 @@ timerlat_print_stats_all(struct timerlat_params *params,
sum.min_thread = ~0;
sum.min_user = ~0;
- for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, ¶ms->common) {
if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
continue;
@@ -620,7 +620,7 @@ timerlat_print_stats(struct osnoise_tool *tool)
trace_seq_printf(trace->seq, "%-6d",
bucket * data->bucket_size);
- for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, ¶ms->common) {
if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
continue;
@@ -658,7 +658,7 @@ timerlat_print_stats(struct osnoise_tool *tool)
if (!params->common.hist.no_index)
trace_seq_printf(trace->seq, "over: ");
- for_each_monitored_cpu(cpu, nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(cpu, ¶ms->common) {
if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
continue;
diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c
index 4eb820fe1f21..ed3d3d1c8956 100644
--- a/tools/tracing/rtla/src/timerlat_top.c
+++ b/tools/tracing/rtla/src/timerlat_top.c
@@ -446,7 +446,7 @@ timerlat_print_stats(struct osnoise_tool *top)
timerlat_top_header(params, top);
- for_each_monitored_cpu(i, nr_cpus, ¶ms->common) {
+ for_each_monitored_cpu(i, ¶ms->common) {
timerlat_top_print(top, i);
timerlat_top_update_sum(top, i, &summary);
}
--
2.52.0
^ permalink raw reply related
* [PATCH v3 5/5] tools/rtla: Remove unneeded cpus parameter from timerlat BPF functions
From: Costa Shulyupin @ 2026-02-13 11:52 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Costa Shulyupin, Crystal Wood,
Wander Lairson Costa, Ivan Pravdin, John Kacur, Tiezhu Yang,
linux-trace-kernel, linux-kernel, bpf
In-Reply-To: <20260213115234.430232-1-costa.shul@redhat.com>
nr_cpus is a global variable available throughout the codebase, so
passing it as a function parameter is unnecessary.
Remove the cpus parameter from timerlat_bpf_get_hist_value() and
get_value(), using the global nr_cpus directly.
Signed-off-by: Costa Shulyupin <costa.shul@redhat.com>
---
tools/tracing/rtla/src/timerlat_bpf.c | 16 +++++++---------
tools/tracing/rtla/src/timerlat_bpf.h | 6 ++----
tools/tracing/rtla/src/timerlat_hist.c | 2 +-
3 files changed, 10 insertions(+), 14 deletions(-)
diff --git a/tools/tracing/rtla/src/timerlat_bpf.c b/tools/tracing/rtla/src/timerlat_bpf.c
index 8d5c3a095e41..dd3cf71d74e5 100644
--- a/tools/tracing/rtla/src/timerlat_bpf.c
+++ b/tools/tracing/rtla/src/timerlat_bpf.c
@@ -147,24 +147,23 @@ static int get_value(struct bpf_map *map_irq,
int key,
long long *value_irq,
long long *value_thread,
- long long *value_user,
- int cpus)
+ long long *value_user)
{
int err;
err = bpf_map__lookup_elem(map_irq, &key,
sizeof(unsigned int), value_irq,
- sizeof(long long) * cpus, 0);
+ sizeof(long long) * nr_cpus, 0);
if (err)
return err;
err = bpf_map__lookup_elem(map_thread, &key,
sizeof(unsigned int), value_thread,
- sizeof(long long) * cpus, 0);
+ sizeof(long long) * nr_cpus, 0);
if (err)
return err;
err = bpf_map__lookup_elem(map_user, &key,
sizeof(unsigned int), value_user,
- sizeof(long long) * cpus, 0);
+ sizeof(long long) * nr_cpus, 0);
if (err)
return err;
return 0;
@@ -176,13 +175,12 @@ static int get_value(struct bpf_map *map_irq,
int timerlat_bpf_get_hist_value(int key,
long long *value_irq,
long long *value_thread,
- long long *value_user,
- int cpus)
+ long long *value_user)
{
return get_value(bpf->maps.hist_irq,
bpf->maps.hist_thread,
bpf->maps.hist_user,
- key, value_irq, value_thread, value_user, cpus);
+ key, value_irq, value_thread, value_user);
}
/*
@@ -196,7 +194,7 @@ int timerlat_bpf_get_summary_value(enum summary_field key,
return get_value(bpf->maps.summary_irq,
bpf->maps.summary_thread,
bpf->maps.summary_user,
- key, value_irq, value_thread, value_user, nr_cpus);
+ key, value_irq, value_thread, value_user);
}
/*
diff --git a/tools/tracing/rtla/src/timerlat_bpf.h b/tools/tracing/rtla/src/timerlat_bpf.h
index f4a5476f2abb..531c9ef16f51 100644
--- a/tools/tracing/rtla/src/timerlat_bpf.h
+++ b/tools/tracing/rtla/src/timerlat_bpf.h
@@ -23,8 +23,7 @@ int timerlat_bpf_restart_tracing(void);
int timerlat_bpf_get_hist_value(int key,
long long *value_irq,
long long *value_thread,
- long long *value_user,
- int cpus);
+ long long *value_user);
int timerlat_bpf_get_summary_value(enum summary_field key,
long long *value_irq,
long long *value_thread,
@@ -44,8 +43,7 @@ static inline int timerlat_bpf_restart_tracing(void) { return -1; };
static inline int timerlat_bpf_get_hist_value(int key,
long long *value_irq,
long long *value_thread,
- long long *value_user,
- int cpus)
+ long long *value_user)
{
return -1;
}
diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c
index db66312ec966..1c4702948532 100644
--- a/tools/tracing/rtla/src/timerlat_hist.c
+++ b/tools/tracing/rtla/src/timerlat_hist.c
@@ -209,7 +209,7 @@ static int timerlat_hist_bpf_pull_data(struct osnoise_tool *tool)
/* Pull histogram */
for (i = 0; i < data->entries; i++) {
err = timerlat_bpf_get_hist_value(i, value_irq, value_thread,
- value_user, nr_cpus);
+ value_user);
if (err)
return err;
for (j = 0; j < nr_cpus; j++) {
--
2.52.0
^ permalink raw reply related
* Re: [PATCH v3 0/5] tools/rtla: Consolidate nr_cpus usage
From: Wander Lairson Costa @ 2026-02-13 13:54 UTC (permalink / raw)
To: Costa Shulyupin
Cc: Steven Rostedt, Tomas Glozar, Crystal Wood, Ivan Pravdin,
John Kacur, Tiezhu Yang, linux-trace-kernel, linux-kernel, bpf
In-Reply-To: <20260213115234.430232-1-costa.shul@redhat.com>
On Fri, Feb 13, 2026 at 01:52:29PM +0200, Costa Shulyupin wrote:
> sysconf(_SC_NPROCESSORS_CONF) (via get_nprocs_conf) reflects
> cpu_possible_mask, which is fixed at boot time, so querying it
> repeatedly is unnecessary.
>
> Replace multiple calls to sysconf(_SC_NPROCESSORS_CONF) with a single
> global nr_cpus variable initialized once at startup.
Reviewed-by: Wander Lairson Costa <wander@redhat.com>
>
> V3:
> - Remove unneeded cpus parameter from timerlat BPF functions as
> requested by Wander Costa.
> v2:
> - Add `#pragma once` in timerlat_u.h to avoid redefinition errors with
> pre-C23 compilers.
>
> Costa Shulyupin (5):
> tools/rtla: Consolidate nr_cpus usage across all tools
> tools/rtla: Remove unneeded nr_cpus arguments
> tools/rtla: Remove unneeded nr_cpus members
> tools/rtla: Remove unneeded nr_cpus from for_each_monitored_cpu
> tools/rtla: Remove unneeded cpus parameter from timerlat BPF functions
>
> tools/tracing/rtla/src/common.c | 7 ++-
> tools/tracing/rtla/src/common.h | 4 +-
> tools/tracing/rtla/src/osnoise_hist.c | 26 +++++------
> tools/tracing/rtla/src/osnoise_top.c | 16 ++-----
> tools/tracing/rtla/src/timerlat.c | 9 ++--
> tools/tracing/rtla/src/timerlat_aa.c | 11 ++---
> tools/tracing/rtla/src/timerlat_bpf.c | 19 ++++----
> tools/tracing/rtla/src/timerlat_bpf.h | 12 ++---
> tools/tracing/rtla/src/timerlat_hist.c | 62 +++++++++++---------------
> tools/tracing/rtla/src/timerlat_top.c | 47 +++++++------------
> tools/tracing/rtla/src/timerlat_u.c | 9 ++--
> tools/tracing/rtla/src/timerlat_u.h | 1 +
> tools/tracing/rtla/src/utils.c | 10 +----
> 13 files changed, 88 insertions(+), 145 deletions(-)
>
> --
> 2.52.0
>
^ permalink raw reply
* [PATCH v6 0/3] mm: vmscan: add PID and cgroup ID to vmscan tracepoints
From: Thomas Ballasi @ 2026-02-13 18:15 UTC (permalink / raw)
To: tballasi
Cc: akpm, axelrasmussen, david, hannes, linux-mm, linux-trace-kernel,
lorenzo.stoakes, mhiramat, mhocko, rostedt, shakeel.butt, weixugc,
yuanchu, zhengqi.arch
In-Reply-To: <20260122182510.2126-1-tballasi@linux.microsoft.com>
Changes in v6:
- Updated Steven's patch with sign-off
- Passed memcg pointers as arguments in tracepoints instead of memcg_id
Link to v5:
https://lore.kernel.org/linux-trace-kernel/20260122182510.2126-1-tballasi@linux.microsoft.com/
Signed-off-by: Thomas Ballasi <tballasi@linux.microsoft.com>
Steven Rostedt (1):
tracing: Add __event_in_*irq() helpers
Thomas Ballasi (2):
mm: vmscan: add cgroup IDs to vmscan tracepoints
mm: vmscan: add PIDs to vmscan tracepoints
include/trace/events/vmscan.h | 104 +++++++++++++--------
include/trace/stages/stage3_trace_output.h | 8 ++
include/trace/stages/stage7_class_define.h | 19 ++++
mm/shrinker.c | 6 +-
mm/vmscan.c | 17 ++--
5 files changed, 106 insertions(+), 48 deletions(-)
--
2.33.8
^ permalink raw reply
* [PATCH v6 1/3] tracing: Add __event_in_*irq() helpers
From: Thomas Ballasi @ 2026-02-13 18:15 UTC (permalink / raw)
To: tballasi
Cc: akpm, axelrasmussen, david, hannes, linux-mm, linux-trace-kernel,
lorenzo.stoakes, mhiramat, mhocko, rostedt, shakeel.butt, weixugc,
yuanchu, zhengqi.arch
In-Reply-To: <20260213181537.54350-1-tballasi@linux.microsoft.com>
From: Steven Rostedt <rostedt@goodmis.org>
Some trace events want to expose in their output if they were triggered in
an interrupt or softirq context. Instead of recording this in the event
structure itself, as this information is stored in the flags portion of
the event header, add helper macros that can be used in the print format:
TP_printk("val=%d %s", __entry->val, __entry_in_irq() ? "(in-irq)" : "")
This will output "(in-irq)" for the event in the trace data if the event
was triggered in hard or soft interrupt context.
Link: https://lore.kernel.org/all/20251229132942.31a2b583@gandalf.local.home/
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Thomas Ballasi <tballasi@linux.microsoft.com>
---
include/trace/stages/stage3_trace_output.h | 8 ++++++++
include/trace/stages/stage7_class_define.h | 19 +++++++++++++++++++
2 files changed, 27 insertions(+)
diff --git a/include/trace/stages/stage3_trace_output.h b/include/trace/stages/stage3_trace_output.h
index 1e7b0bef95f52..53a23988a3b8a 100644
--- a/include/trace/stages/stage3_trace_output.h
+++ b/include/trace/stages/stage3_trace_output.h
@@ -150,3 +150,11 @@
#undef __get_buf
#define __get_buf(len) trace_seq_acquire(p, (len))
+
+#undef __event_in_hardirq
+#undef __event_in_softirq
+#undef __event_in_irq
+
+#define __event_in_hardirq() (__entry->ent.flags & TRACE_FLAG_HARDIRQ)
+#define __event_in_softirq() (__entry->ent.flags & TRACE_FLAG_SOFTIRQ)
+#define __event_in_irq() (__entry->ent.flags & (TRACE_FLAG_HARDIRQ | TRACE_FLAG_SOFTIRQ))
diff --git a/include/trace/stages/stage7_class_define.h b/include/trace/stages/stage7_class_define.h
index fcd564a590f43..47008897a7956 100644
--- a/include/trace/stages/stage7_class_define.h
+++ b/include/trace/stages/stage7_class_define.h
@@ -26,6 +26,25 @@
#undef __print_hex_dump
#undef __get_buf
+#undef __event_in_hardirq
+#undef __event_in_softirq
+#undef __event_in_irq
+
+/*
+ * The TRACE_FLAG_* are enums. Instead of using TRACE_DEFINE_ENUM(),
+ * use their hardcoded values. These values are parsed by user space
+ * tooling elsewhere so they will never change.
+ *
+ * See "enum trace_flag_type" in linux/trace_events.h:
+ * TRACE_FLAG_HARDIRQ
+ * TRACE_FLAG_SOFTIRQ
+ */
+
+/* This is what is displayed in the format files */
+#define __event_in_hardirq() (REC->common_flags & 0x8)
+#define __event_in_softirq() (REC->common_flags & 0x10)
+#define __event_in_irq() (REC->common_flags & 0x18)
+
/*
* The below is not executed in the kernel. It is only what is
* displayed in the print format for userspace to parse.
--
2.33.8
^ permalink raw reply related
* [PATCH v6 2/3] mm: vmscan: add cgroup IDs to vmscan tracepoints
From: Thomas Ballasi @ 2026-02-13 18:15 UTC (permalink / raw)
To: tballasi
Cc: akpm, axelrasmussen, david, hannes, linux-mm, linux-trace-kernel,
lorenzo.stoakes, mhiramat, mhocko, rostedt, shakeel.butt, weixugc,
yuanchu, zhengqi.arch
In-Reply-To: <20260213181537.54350-1-tballasi@linux.microsoft.com>
Memory reclaim events are currently difficult to attribute to
specific cgroups, making debugging memory pressure issues
challenging. This patch adds memory cgroup ID (memcg_id) to key
vmscan tracepoints to enable better correlation and analysis.
For operations not associated with a specific cgroup, the field
is defaulted to 0.
Signed-off-by: Thomas Ballasi <tballasi@linux.microsoft.com>
---
include/trace/events/vmscan.h | 83 ++++++++++++++++++++---------------
mm/shrinker.c | 6 ++-
mm/vmscan.c | 17 +++----
3 files changed, 61 insertions(+), 45 deletions(-)
diff --git a/include/trace/events/vmscan.h b/include/trace/events/vmscan.h
index 490958fa10dee..1212f6a7c223e 100644
--- a/include/trace/events/vmscan.h
+++ b/include/trace/events/vmscan.h
@@ -114,85 +114,92 @@ TRACE_EVENT(mm_vmscan_wakeup_kswapd,
DECLARE_EVENT_CLASS(mm_vmscan_direct_reclaim_begin_template,
- TP_PROTO(int order, gfp_t gfp_flags),
+ TP_PROTO(gfp_t gfp_flags, int order, struct mem_cgroup *memcg),
- TP_ARGS(order, gfp_flags),
+ TP_ARGS(gfp_flags, order, memcg),
TP_STRUCT__entry(
- __field( int, order )
__field( unsigned long, gfp_flags )
+ __field( u64, memcg_id )
+ __field( int, order )
),
TP_fast_assign(
- __entry->order = order;
__entry->gfp_flags = (__force unsigned long)gfp_flags;
+ __entry->order = order;
+ __entry->memcg_id = mem_cgroup_id(memcg);
),
- TP_printk("order=%d gfp_flags=%s",
+ TP_printk("order=%d gfp_flags=%s memcg_id=%llu",
__entry->order,
- show_gfp_flags(__entry->gfp_flags))
+ show_gfp_flags(__entry->gfp_flags),
+ __entry->memcg_id)
);
DEFINE_EVENT(mm_vmscan_direct_reclaim_begin_template, mm_vmscan_direct_reclaim_begin,
- TP_PROTO(int order, gfp_t gfp_flags),
+ TP_PROTO(gfp_t gfp_flags, int order, struct mem_cgroup *memcg),
- TP_ARGS(order, gfp_flags)
+ TP_ARGS(gfp_flags, order, memcg)
);
#ifdef CONFIG_MEMCG
DEFINE_EVENT(mm_vmscan_direct_reclaim_begin_template, mm_vmscan_memcg_reclaim_begin,
- TP_PROTO(int order, gfp_t gfp_flags),
+ TP_PROTO(gfp_t gfp_flags, int order, struct mem_cgroup *memcg),
- TP_ARGS(order, gfp_flags)
+ TP_ARGS(gfp_flags, order, memcg)
);
DEFINE_EVENT(mm_vmscan_direct_reclaim_begin_template, mm_vmscan_memcg_softlimit_reclaim_begin,
- TP_PROTO(int order, gfp_t gfp_flags),
+ TP_PROTO(gfp_t gfp_flags, int order, struct mem_cgroup *memcg),
- TP_ARGS(order, gfp_flags)
+ TP_ARGS(gfp_flags, order, memcg)
);
#endif /* CONFIG_MEMCG */
DECLARE_EVENT_CLASS(mm_vmscan_direct_reclaim_end_template,
- TP_PROTO(unsigned long nr_reclaimed),
+ TP_PROTO(unsigned long nr_reclaimed, struct mem_cgroup *memcg),
- TP_ARGS(nr_reclaimed),
+ TP_ARGS(nr_reclaimed, memcg),
TP_STRUCT__entry(
__field( unsigned long, nr_reclaimed )
+ __field( u64, memcg_id )
),
TP_fast_assign(
__entry->nr_reclaimed = nr_reclaimed;
+ __entry->memcg_id = mem_cgroup_id(memcg);
),
- TP_printk("nr_reclaimed=%lu", __entry->nr_reclaimed)
+ TP_printk("nr_reclaimed=%lu memcg_id=%llu",
+ __entry->nr_reclaimed,
+ __entry->memcg_id)
);
DEFINE_EVENT(mm_vmscan_direct_reclaim_end_template, mm_vmscan_direct_reclaim_end,
- TP_PROTO(unsigned long nr_reclaimed),
+ TP_PROTO(unsigned long nr_reclaimed, struct mem_cgroup *memcg),
- TP_ARGS(nr_reclaimed)
+ TP_ARGS(nr_reclaimed, memcg)
);
#ifdef CONFIG_MEMCG
DEFINE_EVENT(mm_vmscan_direct_reclaim_end_template, mm_vmscan_memcg_reclaim_end,
- TP_PROTO(unsigned long nr_reclaimed),
+ TP_PROTO(unsigned long nr_reclaimed, struct mem_cgroup *memcg),
- TP_ARGS(nr_reclaimed)
+ TP_ARGS(nr_reclaimed, memcg)
);
DEFINE_EVENT(mm_vmscan_direct_reclaim_end_template, mm_vmscan_memcg_softlimit_reclaim_end,
- TP_PROTO(unsigned long nr_reclaimed),
+ TP_PROTO(unsigned long nr_reclaimed, struct mem_cgroup *memcg),
- TP_ARGS(nr_reclaimed)
+ TP_ARGS(nr_reclaimed, memcg)
);
#endif /* CONFIG_MEMCG */
@@ -200,39 +207,42 @@ TRACE_EVENT(mm_shrink_slab_start,
TP_PROTO(struct shrinker *shr, struct shrink_control *sc,
long nr_objects_to_shrink, unsigned long cache_items,
unsigned long long delta, unsigned long total_scan,
- int priority),
+ int priority, struct mem_cgroup *memcg),
TP_ARGS(shr, sc, nr_objects_to_shrink, cache_items, delta, total_scan,
- priority),
+ priority, memcg),
TP_STRUCT__entry(
__field(struct shrinker *, shr)
__field(void *, shrink)
- __field(int, nid)
__field(long, nr_objects_to_shrink)
__field(unsigned long, gfp_flags)
__field(unsigned long, cache_items)
__field(unsigned long long, delta)
__field(unsigned long, total_scan)
__field(int, priority)
+ __field(int, nid)
+ __field(u64, memcg_id)
),
TP_fast_assign(
__entry->shr = shr;
__entry->shrink = shr->scan_objects;
- __entry->nid = sc->nid;
__entry->nr_objects_to_shrink = nr_objects_to_shrink;
__entry->gfp_flags = (__force unsigned long)sc->gfp_mask;
__entry->cache_items = cache_items;
__entry->delta = delta;
__entry->total_scan = total_scan;
__entry->priority = priority;
+ __entry->nid = sc->nid;
+ __entry->memcg_id = mem_cgroup_id(memcg);
),
- TP_printk("%pS %p: nid: %d objects to shrink %ld gfp_flags %s cache items %ld delta %lld total_scan %ld priority %d",
+ TP_printk("%pS %p: nid: %d memcg_id: %llu objects to shrink %ld gfp_flags %s cache items %ld delta %lld total_scan %ld priority %d",
__entry->shrink,
__entry->shr,
__entry->nid,
+ __entry->memcg_id,
__entry->nr_objects_to_shrink,
show_gfp_flags(__entry->gfp_flags),
__entry->cache_items,
@@ -243,35 +253,38 @@ TRACE_EVENT(mm_shrink_slab_start,
TRACE_EVENT(mm_shrink_slab_end,
TP_PROTO(struct shrinker *shr, int nid, int shrinker_retval,
- long unused_scan_cnt, long new_scan_cnt, long total_scan),
+ long unused_scan_cnt, long new_scan_cnt, long total_scan, struct mem_cgroup *memcg),
TP_ARGS(shr, nid, shrinker_retval, unused_scan_cnt, new_scan_cnt,
- total_scan),
+ total_scan, memcg),
TP_STRUCT__entry(
__field(struct shrinker *, shr)
- __field(int, nid)
__field(void *, shrink)
__field(long, unused_scan)
__field(long, new_scan)
- __field(int, retval)
__field(long, total_scan)
+ __field(int, nid)
+ __field(int, retval)
+ __field(u64, memcg_id)
),
TP_fast_assign(
__entry->shr = shr;
- __entry->nid = nid;
__entry->shrink = shr->scan_objects;
__entry->unused_scan = unused_scan_cnt;
__entry->new_scan = new_scan_cnt;
- __entry->retval = shrinker_retval;
__entry->total_scan = total_scan;
+ __entry->nid = nid;
+ __entry->retval = shrinker_retval;
+ __entry->memcg_id = mem_cgroup_id(memcg);
),
- TP_printk("%pS %p: nid: %d unused scan count %ld new scan count %ld total_scan %ld last shrinker return val %d",
+ TP_printk("%pS %p: nid: %d memcg_id: %llu unused scan count %ld new scan count %ld total_scan %ld last shrinker return val %d",
__entry->shrink,
__entry->shr,
__entry->nid,
+ __entry->memcg_id,
__entry->unused_scan,
__entry->new_scan,
__entry->total_scan,
@@ -504,9 +517,9 @@ TRACE_EVENT(mm_vmscan_node_reclaim_begin,
DEFINE_EVENT(mm_vmscan_direct_reclaim_end_template, mm_vmscan_node_reclaim_end,
- TP_PROTO(unsigned long nr_reclaimed),
+ TP_PROTO(unsigned long nr_reclaimed, struct mem_cgroup *memcg),
- TP_ARGS(nr_reclaimed)
+ TP_ARGS(nr_reclaimed, memcg)
);
TRACE_EVENT(mm_vmscan_throttled,
diff --git a/mm/shrinker.c b/mm/shrinker.c
index 4a93fd433689a..ddf784f996a59 100644
--- a/mm/shrinker.c
+++ b/mm/shrinker.c
@@ -410,7 +410,8 @@ static unsigned long do_shrink_slab(struct shrink_control *shrinkctl,
total_scan = min(total_scan, (2 * freeable));
trace_mm_shrink_slab_start(shrinker, shrinkctl, nr,
- freeable, delta, total_scan, priority);
+ freeable, delta, total_scan, priority,
+ shrinkctl->memcg);
/*
* Normally, we should not scan less than batch_size objects in one
@@ -461,7 +462,8 @@ static unsigned long do_shrink_slab(struct shrink_control *shrinkctl,
*/
new_nr = add_nr_deferred(next_deferred, shrinker, shrinkctl);
- trace_mm_shrink_slab_end(shrinker, shrinkctl->nid, freed, nr, new_nr, total_scan);
+ trace_mm_shrink_slab_end(shrinker, shrinkctl->nid, freed, nr, new_nr, total_scan,
+ shrinkctl->memcg);
return freed;
}
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 614ccf39fe3fa..9d512fb354fcd 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -6603,11 +6603,11 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
return 1;
set_task_reclaim_state(current, &sc.reclaim_state);
- trace_mm_vmscan_direct_reclaim_begin(order, sc.gfp_mask);
+ trace_mm_vmscan_direct_reclaim_begin(sc.gfp_mask, order, 0);
nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
- trace_mm_vmscan_direct_reclaim_end(nr_reclaimed);
+ trace_mm_vmscan_direct_reclaim_end(nr_reclaimed, 0);
set_task_reclaim_state(current, NULL);
return nr_reclaimed;
@@ -6636,8 +6636,9 @@ unsigned long mem_cgroup_shrink_node(struct mem_cgroup *memcg,
sc.gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
(GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK);
- trace_mm_vmscan_memcg_softlimit_reclaim_begin(sc.order,
- sc.gfp_mask);
+ trace_mm_vmscan_memcg_softlimit_reclaim_begin(sc.gfp_mask,
+ sc.order,
+ memcg);
/*
* NOTE: Although we can get the priority field, using it
@@ -6648,7 +6649,7 @@ unsigned long mem_cgroup_shrink_node(struct mem_cgroup *memcg,
*/
shrink_lruvec(lruvec, &sc);
- trace_mm_vmscan_memcg_softlimit_reclaim_end(sc.nr_reclaimed);
+ trace_mm_vmscan_memcg_softlimit_reclaim_end(sc.nr_reclaimed, memcg);
*nr_scanned = sc.nr_scanned;
@@ -6684,13 +6685,13 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
struct zonelist *zonelist = node_zonelist(numa_node_id(), sc.gfp_mask);
set_task_reclaim_state(current, &sc.reclaim_state);
- trace_mm_vmscan_memcg_reclaim_begin(0, sc.gfp_mask);
+ trace_mm_vmscan_memcg_reclaim_begin(sc.gfp_mask, 0, memcg);
noreclaim_flag = memalloc_noreclaim_save();
nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
memalloc_noreclaim_restore(noreclaim_flag);
- trace_mm_vmscan_memcg_reclaim_end(nr_reclaimed);
+ trace_mm_vmscan_memcg_reclaim_end(nr_reclaimed, memcg);
set_task_reclaim_state(current, NULL);
return nr_reclaimed;
@@ -7642,7 +7643,7 @@ static unsigned long __node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask,
delayacct_freepages_end();
psi_memstall_leave(&pflags);
- trace_mm_vmscan_node_reclaim_end(sc->nr_reclaimed);
+ trace_mm_vmscan_node_reclaim_end(sc->nr_reclaimed, 0);
return sc->nr_reclaimed;
}
--
2.33.8
^ permalink raw reply related
* [PATCH v6 3/3] mm: vmscan: add PIDs to vmscan tracepoints
From: Thomas Ballasi @ 2026-02-13 18:15 UTC (permalink / raw)
To: tballasi
Cc: akpm, axelrasmussen, david, hannes, linux-mm, linux-trace-kernel,
lorenzo.stoakes, mhiramat, mhocko, rostedt, shakeel.butt, weixugc,
yuanchu, zhengqi.arch
In-Reply-To: <20260213181537.54350-1-tballasi@linux.microsoft.com>
The changes aims at adding additionnal tracepoints variables to help
debuggers attribute them to specific processes.
The PID field uses in_task() to reliably detect when we're in process
context and can safely access current->pid. When not in process
context (such as in interrupt or in an asynchronous RCU context), the
field is set to -1 as a sentinel value.
Signed-off-by: Thomas Ballasi <tballasi@linux.microsoft.com>
---
include/trace/events/vmscan.h | 35 +++++++++++++++++++++++++----------
1 file changed, 25 insertions(+), 10 deletions(-)
diff --git a/include/trace/events/vmscan.h b/include/trace/events/vmscan.h
index 1212f6a7c223e..a68b712ef757a 100644
--- a/include/trace/events/vmscan.h
+++ b/include/trace/events/vmscan.h
@@ -122,18 +122,22 @@ DECLARE_EVENT_CLASS(mm_vmscan_direct_reclaim_begin_template,
__field( unsigned long, gfp_flags )
__field( u64, memcg_id )
__field( int, order )
+ __field( int, pid )
),
TP_fast_assign(
__entry->gfp_flags = (__force unsigned long)gfp_flags;
__entry->order = order;
+ __entry->pid = current->pid;
__entry->memcg_id = mem_cgroup_id(memcg);
),
- TP_printk("order=%d gfp_flags=%s memcg_id=%llu",
+ TP_printk("order=%d gfp_flags=%s pid=%d memcg_id=%llu %s",
__entry->order,
show_gfp_flags(__entry->gfp_flags),
- __entry->memcg_id)
+ __entry->pid,
+ __entry->memcg_id,
+ __event_in_irq() ? "(in-irq)" : "")
);
DEFINE_EVENT(mm_vmscan_direct_reclaim_begin_template, mm_vmscan_direct_reclaim_begin,
@@ -168,16 +172,20 @@ DECLARE_EVENT_CLASS(mm_vmscan_direct_reclaim_end_template,
TP_STRUCT__entry(
__field( unsigned long, nr_reclaimed )
__field( u64, memcg_id )
+ __field( int, pid )
),
TP_fast_assign(
__entry->nr_reclaimed = nr_reclaimed;
__entry->memcg_id = mem_cgroup_id(memcg);
+ __entry->pid = current->pid;
),
- TP_printk("nr_reclaimed=%lu memcg_id=%llu",
+ TP_printk("nr_reclaimed=%lu pid=%d memcg_id=%llu %s",
__entry->nr_reclaimed,
- __entry->memcg_id)
+ __entry->pid,
+ __entry->memcg_id,
+ __event_in_irq() ? "(in-irq)" : "")
);
DEFINE_EVENT(mm_vmscan_direct_reclaim_end_template, mm_vmscan_direct_reclaim_end,
@@ -220,9 +228,10 @@ TRACE_EVENT(mm_shrink_slab_start,
__field(unsigned long, cache_items)
__field(unsigned long long, delta)
__field(unsigned long, total_scan)
+ __field(u64, memcg_id)
__field(int, priority)
__field(int, nid)
- __field(u64, memcg_id)
+ __field(int, pid)
),
TP_fast_assign(
@@ -236,19 +245,22 @@ TRACE_EVENT(mm_shrink_slab_start,
__entry->priority = priority;
__entry->nid = sc->nid;
__entry->memcg_id = mem_cgroup_id(memcg);
+ __entry->pid = current->pid;
),
- TP_printk("%pS %p: nid: %d memcg_id: %llu objects to shrink %ld gfp_flags %s cache items %ld delta %lld total_scan %ld priority %d",
+ TP_printk("%pS %p: nid: %d pid: %d memcg_id: %llu objects to shrink %ld gfp_flags %s cache items %ld delta %lld total_scan %ld priority %d %s",
__entry->shrink,
__entry->shr,
__entry->nid,
+ __entry->pid,
__entry->memcg_id,
__entry->nr_objects_to_shrink,
show_gfp_flags(__entry->gfp_flags),
__entry->cache_items,
__entry->delta,
__entry->total_scan,
- __entry->priority)
+ __entry->priority,
+ __event_in_irq() ? "(in-irq)" : "")
);
TRACE_EVENT(mm_shrink_slab_end,
@@ -266,29 +278,32 @@ TRACE_EVENT(mm_shrink_slab_end,
__field(long, total_scan)
__field(int, nid)
__field(int, retval)
+ __field(int, pid)
__field(u64, memcg_id)
),
TP_fast_assign(
__entry->shr = shr;
- __entry->shrink = shr->scan_objects;
__entry->unused_scan = unused_scan_cnt;
__entry->new_scan = new_scan_cnt;
__entry->total_scan = total_scan;
__entry->nid = nid;
__entry->retval = shrinker_retval;
+ __entry->pid = current->pid;
__entry->memcg_id = mem_cgroup_id(memcg);
),
- TP_printk("%pS %p: nid: %d memcg_id: %llu unused scan count %ld new scan count %ld total_scan %ld last shrinker return val %d",
+ TP_printk("%pS %p: nid: %d pid: %d memcg_id: %llu unused scan count %ld new scan count %ld total_scan %ld last shrinker return val %d %s",
__entry->shrink,
__entry->shr,
__entry->nid,
+ __entry->pid,
__entry->memcg_id,
__entry->unused_scan,
__entry->new_scan,
__entry->total_scan,
- __entry->retval)
+ __entry->retval,
+ __event_in_irq() ? "(in-irq)" : "")
);
TRACE_EVENT(mm_vmscan_lru_isolate,
--
2.33.8
^ permalink raw reply related
* [PATCH v2] blk-mq: use NOIO context to prevent deadlock during debugfs creation
From: Yu Kuai @ 2026-02-14 5:43 UTC (permalink / raw)
To: axboe, nilay, ming.lei, hch
Cc: yi.zhang, shinichiro.kawasaki, kbusch, rostedt, mhiramat,
mathieu.desnoyers, linux-block, linux-kernel, linux-trace-kernel
Creating debugfs entries can trigger fs reclaim, which can enter back
into the block layer request_queue. This can cause deadlock if the
queue is frozen.
Previously, a WARN_ON_ONCE check was used in debugfs_create_files()
to detect this condition, but it was racy since the queue can be frozen
from another context at any time.
Introduce blk_debugfs_lock()/blk_debugfs_unlock() helpers that combine
the debugfs_mutex with memalloc_noio_save()/restore() to prevent fs
reclaim from triggering block I/O. Also add blk_debugfs_lock_nomemsave()
and blk_debugfs_unlock_nomemrestore() variants for callers that don't
need NOIO protection (e.g., debugfs removal or read-only operations).
Replace all raw debugfs_mutex lock/unlock pairs with these helpers,
using the _nomemsave/_nomemrestore variants where appropriate.
Reported-by: Yi Zhang <yi.zhang@redhat.com>
Closes: https://lore.kernel.org/all/CAHj4cs9gNKEYAPagD9JADfO5UH+OiCr4P7OO2wjpfOYeM-RV=A@mail.gmail.com/
Reported-by: Shinichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Closes: https://lore.kernel.org/all/aYWQR7CtYdk3K39g@shinmob/
Suggested-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Yu Kuai <yukuai@fnnas.com>
---
block/blk-mq-debugfs.c | 10 +++-------
block/blk-mq-sched.c | 9 +++++----
block/blk-sysfs.c | 9 +++++----
block/blk-wbt.c | 10 ++++++----
block/blk.h | 31 +++++++++++++++++++++++++++++++
kernel/trace/blktrace.c | 38 +++++++++++++++++++++-----------------
6 files changed, 71 insertions(+), 36 deletions(-)
diff --git a/block/blk-mq-debugfs.c b/block/blk-mq-debugfs.c
index faeaa1fc86a7..28167c9baa55 100644
--- a/block/blk-mq-debugfs.c
+++ b/block/blk-mq-debugfs.c
@@ -613,11 +613,6 @@ static void debugfs_create_files(struct request_queue *q, struct dentry *parent,
const struct blk_mq_debugfs_attr *attr)
{
lockdep_assert_held(&q->debugfs_mutex);
- /*
- * Creating new debugfs entries with queue freezed has the risk of
- * deadlock.
- */
- WARN_ON_ONCE(q->mq_freeze_depth != 0);
/*
* debugfs_mutex should not be nested under other locks that can be
* grabbed while queue is frozen.
@@ -693,12 +688,13 @@ void blk_mq_debugfs_unregister_hctx(struct blk_mq_hw_ctx *hctx)
void blk_mq_debugfs_register_hctxs(struct request_queue *q)
{
struct blk_mq_hw_ctx *hctx;
+ unsigned int memflags;
unsigned long i;
- mutex_lock(&q->debugfs_mutex);
+ memflags = blk_debugfs_lock(q);
queue_for_each_hw_ctx(q, hctx, i)
blk_mq_debugfs_register_hctx(q, hctx);
- mutex_unlock(&q->debugfs_mutex);
+ blk_debugfs_unlock(q, memflags);
}
void blk_mq_debugfs_unregister_hctxs(struct request_queue *q)
diff --git a/block/blk-mq-sched.c b/block/blk-mq-sched.c
index e26898128a7e..97c3c8f45a9b 100644
--- a/block/blk-mq-sched.c
+++ b/block/blk-mq-sched.c
@@ -390,13 +390,14 @@ static void blk_mq_sched_tags_teardown(struct request_queue *q, unsigned int fla
void blk_mq_sched_reg_debugfs(struct request_queue *q)
{
struct blk_mq_hw_ctx *hctx;
+ unsigned int memflags;
unsigned long i;
- mutex_lock(&q->debugfs_mutex);
+ memflags = blk_debugfs_lock(q);
blk_mq_debugfs_register_sched(q);
queue_for_each_hw_ctx(q, hctx, i)
blk_mq_debugfs_register_sched_hctx(q, hctx);
- mutex_unlock(&q->debugfs_mutex);
+ blk_debugfs_unlock(q, memflags);
}
void blk_mq_sched_unreg_debugfs(struct request_queue *q)
@@ -404,11 +405,11 @@ void blk_mq_sched_unreg_debugfs(struct request_queue *q)
struct blk_mq_hw_ctx *hctx;
unsigned long i;
- mutex_lock(&q->debugfs_mutex);
+ blk_debugfs_lock_nomemsave(q);
queue_for_each_hw_ctx(q, hctx, i)
blk_mq_debugfs_unregister_sched_hctx(hctx);
blk_mq_debugfs_unregister_sched(q);
- mutex_unlock(&q->debugfs_mutex);
+ blk_debugfs_unlock_nomemrestore(q);
}
void blk_mq_free_sched_tags(struct elevator_tags *et,
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index 003aa684e854..f3b1968c80ce 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -892,13 +892,13 @@ static void blk_debugfs_remove(struct gendisk *disk)
{
struct request_queue *q = disk->queue;
- mutex_lock(&q->debugfs_mutex);
+ blk_debugfs_lock_nomemsave(q);
blk_trace_shutdown(q);
debugfs_remove_recursive(q->debugfs_dir);
q->debugfs_dir = NULL;
q->sched_debugfs_dir = NULL;
q->rqos_debugfs_dir = NULL;
- mutex_unlock(&q->debugfs_mutex);
+ blk_debugfs_unlock_nomemrestore(q);
}
/**
@@ -908,6 +908,7 @@ static void blk_debugfs_remove(struct gendisk *disk)
int blk_register_queue(struct gendisk *disk)
{
struct request_queue *q = disk->queue;
+ unsigned int memflags;
int ret;
ret = kobject_add(&disk->queue_kobj, &disk_to_dev(disk)->kobj, "queue");
@@ -921,11 +922,11 @@ int blk_register_queue(struct gendisk *disk)
}
mutex_lock(&q->sysfs_lock);
- mutex_lock(&q->debugfs_mutex);
+ memflags = blk_debugfs_lock(q);
q->debugfs_dir = debugfs_create_dir(disk->disk_name, blk_debugfs_root);
if (queue_is_mq(q))
blk_mq_debugfs_register(q);
- mutex_unlock(&q->debugfs_mutex);
+ blk_debugfs_unlock(q, memflags);
ret = disk_register_independent_access_ranges(disk);
if (ret)
diff --git a/block/blk-wbt.c b/block/blk-wbt.c
index 1415f2bf8611..6dba71e87387 100644
--- a/block/blk-wbt.c
+++ b/block/blk-wbt.c
@@ -776,6 +776,7 @@ void wbt_init_enable_default(struct gendisk *disk)
{
struct request_queue *q = disk->queue;
struct rq_wb *rwb;
+ unsigned int memflags;
if (!__wbt_enable_default(disk))
return;
@@ -789,9 +790,9 @@ void wbt_init_enable_default(struct gendisk *disk)
return;
}
- mutex_lock(&q->debugfs_mutex);
+ memflags = blk_debugfs_lock(q);
blk_mq_debugfs_register_rq_qos(q);
- mutex_unlock(&q->debugfs_mutex);
+ blk_debugfs_unlock(q, memflags);
}
static u64 wbt_default_latency_nsec(struct request_queue *q)
@@ -1015,9 +1016,10 @@ int wbt_set_lat(struct gendisk *disk, s64 val)
blk_mq_unquiesce_queue(q);
out:
blk_mq_unfreeze_queue(q, memflags);
- mutex_lock(&q->debugfs_mutex);
+
+ memflags = blk_debugfs_lock(q);
blk_mq_debugfs_register_rq_qos(q);
- mutex_unlock(&q->debugfs_mutex);
+ blk_debugfs_unlock(q, memflags);
return ret;
}
diff --git a/block/blk.h b/block/blk.h
index 401d19ed08a6..68cef70e84e6 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -740,4 +740,35 @@ static inline void blk_unfreeze_release_lock(struct request_queue *q)
}
#endif
+/*
+ * debugfs directory and file creation can trigger fs reclaim, which can enter
+ * back into the block layer request_queue. This can cause deadlock if the
+ * queue is frozen. Use NOIO context together with debugfs_mutex to prevent fs
+ * reclaim from triggering block I/O.
+ */
+static inline void blk_debugfs_lock_nomemsave(struct request_queue *q)
+{
+ mutex_lock(&q->debugfs_mutex);
+}
+
+static inline void blk_debugfs_unlock_nomemrestore(struct request_queue *q)
+{
+ mutex_unlock(&q->debugfs_mutex);
+}
+
+static inline unsigned int __must_check blk_debugfs_lock(struct request_queue *q)
+{
+ unsigned int memflags = memalloc_noio_save();
+
+ blk_debugfs_lock_nomemsave(q);
+ return memflags;
+}
+
+static inline void blk_debugfs_unlock(struct request_queue *q,
+ unsigned int memflags)
+{
+ blk_debugfs_unlock_nomemrestore(q);
+ memalloc_noio_restore(memflags);
+}
+
#endif /* BLK_INTERNAL_H */
diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
index c4db5c2e7103..a3d8a68f8683 100644
--- a/kernel/trace/blktrace.c
+++ b/kernel/trace/blktrace.c
@@ -559,9 +559,9 @@ int blk_trace_remove(struct request_queue *q)
{
int ret;
- mutex_lock(&q->debugfs_mutex);
+ blk_debugfs_lock_nomemsave(q);
ret = __blk_trace_remove(q);
- mutex_unlock(&q->debugfs_mutex);
+ blk_debugfs_unlock_nomemrestore(q);
return ret;
}
@@ -767,6 +767,7 @@ int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
struct blk_user_trace_setup2 buts2;
struct blk_user_trace_setup buts;
struct blk_trace *bt;
+ unsigned int memflags;
int ret;
ret = copy_from_user(&buts, arg, sizeof(buts));
@@ -785,16 +786,16 @@ int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
.pid = buts.pid,
};
- mutex_lock(&q->debugfs_mutex);
+ memflags = blk_debugfs_lock(q);
bt = blk_trace_setup_prepare(q, name, dev, buts.buf_size, buts.buf_nr,
bdev);
if (IS_ERR(bt)) {
- mutex_unlock(&q->debugfs_mutex);
+ blk_debugfs_unlock(q, memflags);
return PTR_ERR(bt);
}
blk_trace_setup_finalize(q, name, 1, bt, &buts2);
strscpy(buts.name, buts2.name, BLKTRACE_BDEV_SIZE);
- mutex_unlock(&q->debugfs_mutex);
+ blk_debugfs_unlock(q, memflags);
if (copy_to_user(arg, &buts, sizeof(buts))) {
blk_trace_remove(q);
@@ -809,6 +810,7 @@ static int blk_trace_setup2(struct request_queue *q, char *name, dev_t dev,
{
struct blk_user_trace_setup2 buts2;
struct blk_trace *bt;
+ unsigned int memflags;
if (copy_from_user(&buts2, arg, sizeof(buts2)))
return -EFAULT;
@@ -819,15 +821,15 @@ static int blk_trace_setup2(struct request_queue *q, char *name, dev_t dev,
if (buts2.flags != 0)
return -EINVAL;
- mutex_lock(&q->debugfs_mutex);
+ memflags = blk_debugfs_lock(q);
bt = blk_trace_setup_prepare(q, name, dev, buts2.buf_size, buts2.buf_nr,
bdev);
if (IS_ERR(bt)) {
- mutex_unlock(&q->debugfs_mutex);
+ blk_debugfs_unlock(q, memflags);
return PTR_ERR(bt);
}
blk_trace_setup_finalize(q, name, 2, bt, &buts2);
- mutex_unlock(&q->debugfs_mutex);
+ blk_debugfs_unlock(q, memflags);
if (copy_to_user(arg, &buts2, sizeof(buts2))) {
blk_trace_remove(q);
@@ -844,6 +846,7 @@ static int compat_blk_trace_setup(struct request_queue *q, char *name,
struct blk_user_trace_setup2 buts2;
struct compat_blk_user_trace_setup cbuts;
struct blk_trace *bt;
+ unsigned int memflags;
if (copy_from_user(&cbuts, arg, sizeof(cbuts)))
return -EFAULT;
@@ -860,15 +863,15 @@ static int compat_blk_trace_setup(struct request_queue *q, char *name,
.pid = cbuts.pid,
};
- mutex_lock(&q->debugfs_mutex);
+ memflags = blk_debugfs_lock(q);
bt = blk_trace_setup_prepare(q, name, dev, buts2.buf_size, buts2.buf_nr,
bdev);
if (IS_ERR(bt)) {
- mutex_unlock(&q->debugfs_mutex);
+ blk_debugfs_unlock(q, memflags);
return PTR_ERR(bt);
}
blk_trace_setup_finalize(q, name, 1, bt, &buts2);
- mutex_unlock(&q->debugfs_mutex);
+ blk_debugfs_unlock(q, memflags);
if (copy_to_user(arg, &buts2.name, ARRAY_SIZE(buts2.name))) {
blk_trace_remove(q);
@@ -898,9 +901,9 @@ int blk_trace_startstop(struct request_queue *q, int start)
{
int ret;
- mutex_lock(&q->debugfs_mutex);
+ blk_debugfs_lock_nomemsave(q);
ret = __blk_trace_startstop(q, start);
- mutex_unlock(&q->debugfs_mutex);
+ blk_debugfs_unlock_nomemrestore(q);
return ret;
}
@@ -2020,7 +2023,7 @@ static ssize_t sysfs_blk_trace_attr_show(struct device *dev,
struct blk_trace *bt;
ssize_t ret = -ENXIO;
- mutex_lock(&q->debugfs_mutex);
+ blk_debugfs_lock_nomemsave(q);
bt = rcu_dereference_protected(q->blk_trace,
lockdep_is_held(&q->debugfs_mutex));
@@ -2041,7 +2044,7 @@ static ssize_t sysfs_blk_trace_attr_show(struct device *dev,
ret = sprintf(buf, "%llu\n", bt->end_lba);
out_unlock_bdev:
- mutex_unlock(&q->debugfs_mutex);
+ blk_debugfs_unlock_nomemrestore(q);
return ret;
}
@@ -2052,6 +2055,7 @@ static ssize_t sysfs_blk_trace_attr_store(struct device *dev,
struct block_device *bdev = dev_to_bdev(dev);
struct request_queue *q = bdev_get_queue(bdev);
struct blk_trace *bt;
+ unsigned int memflags;
u64 value;
ssize_t ret = -EINVAL;
@@ -2071,7 +2075,7 @@ static ssize_t sysfs_blk_trace_attr_store(struct device *dev,
goto out;
}
- mutex_lock(&q->debugfs_mutex);
+ memflags = blk_debugfs_lock(q);
bt = rcu_dereference_protected(q->blk_trace,
lockdep_is_held(&q->debugfs_mutex));
@@ -2106,7 +2110,7 @@ static ssize_t sysfs_blk_trace_attr_store(struct device *dev,
}
out_unlock_bdev:
- mutex_unlock(&q->debugfs_mutex);
+ blk_debugfs_unlock(q, memflags);
out:
return ret ? ret : count;
}
--
2.51.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox