mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 00:53:34 +02:00
The da_monitor helper functions are generated from macros of the type:
DECLARE_DA_FUNCTION(name, type) \
static void da_func_x_##name(type arg) {} \
static void da_func_y_##name(type arg) {} \
This is good to minimise code duplication but the long macros made of
skipped end of lines is rather hard to parse. Since functions are
static, the advantage of naming them differently for each monitor is
minimal.
Refactor the da_monitor.h file to minimise macros, instead of declaring
functions from macros, we simply declare them with the same name for all
monitors (e.g. da_func_x) and for any remaining reference to the monitor
name (e.g. tracepoints, enums, global variables) we use the CONCATENATE
macro.
In this way the file is much easier to maintain while keeping the same
generality.
Functions depending on the monitor types are now conditionally compiled
according to the value of RV_MON_TYPE, which must be defined in the
monitor source.
The monitor type can be specified as in the original implementation,
although it's best to keep the default implementation (unsigned char) as
not all parts of code support larger data types, and likely there's no
need.
We keep the empty macro definitions to ease review of this change with
diff tools, but cleanup is required.
Also adapt existing monitors to keep the build working.
Reviewed-by: Nam Cao <namcao@linutronix.de>
Link: https://lore.kernel.org/r/20251126104241.291258-2-gmonaco@redhat.com
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
137 lines
3.7 KiB
C
137 lines
3.7 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
#include <linux/ftrace.h>
|
|
#include <linux/tracepoint.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/rv.h>
|
|
#include <rv/instrumentation.h>
|
|
|
|
#define MODULE_NAME "nrp"
|
|
|
|
#include <trace/events/irq.h>
|
|
#include <trace/events/sched.h>
|
|
#include <rv_trace.h>
|
|
#include <monitors/sched/sched.h>
|
|
|
|
#define RV_MON_TYPE RV_MON_PER_TASK
|
|
#include "nrp.h"
|
|
#include <rv/da_monitor.h>
|
|
|
|
#ifdef CONFIG_X86_LOCAL_APIC
|
|
#include <asm/trace/irq_vectors.h>
|
|
|
|
static void handle_vector_irq_entry(void *data, int vector)
|
|
{
|
|
da_handle_event(current, irq_entry_nrp);
|
|
}
|
|
|
|
static void attach_vector_irq(void)
|
|
{
|
|
rv_attach_trace_probe("nrp", local_timer_entry, handle_vector_irq_entry);
|
|
if (IS_ENABLED(CONFIG_IRQ_WORK))
|
|
rv_attach_trace_probe("nrp", irq_work_entry, handle_vector_irq_entry);
|
|
if (IS_ENABLED(CONFIG_SMP)) {
|
|
rv_attach_trace_probe("nrp", reschedule_entry, handle_vector_irq_entry);
|
|
rv_attach_trace_probe("nrp", call_function_entry, handle_vector_irq_entry);
|
|
rv_attach_trace_probe("nrp", call_function_single_entry, handle_vector_irq_entry);
|
|
}
|
|
}
|
|
|
|
static void detach_vector_irq(void)
|
|
{
|
|
rv_detach_trace_probe("nrp", local_timer_entry, handle_vector_irq_entry);
|
|
if (IS_ENABLED(CONFIG_IRQ_WORK))
|
|
rv_detach_trace_probe("nrp", irq_work_entry, handle_vector_irq_entry);
|
|
if (IS_ENABLED(CONFIG_SMP)) {
|
|
rv_detach_trace_probe("nrp", reschedule_entry, handle_vector_irq_entry);
|
|
rv_detach_trace_probe("nrp", call_function_entry, handle_vector_irq_entry);
|
|
rv_detach_trace_probe("nrp", call_function_single_entry, handle_vector_irq_entry);
|
|
}
|
|
}
|
|
|
|
#else
|
|
/* We assume irq_entry tracepoints are sufficient on other architectures */
|
|
static void attach_vector_irq(void) { }
|
|
static void detach_vector_irq(void) { }
|
|
#endif
|
|
|
|
static void handle_irq_entry(void *data, int irq, struct irqaction *action)
|
|
{
|
|
da_handle_event(current, irq_entry_nrp);
|
|
}
|
|
|
|
static void handle_sched_need_resched(void *data, struct task_struct *tsk,
|
|
int cpu, int tif)
|
|
{
|
|
/*
|
|
* Although need_resched leads to both the rescheduling and preempt_irq
|
|
* states, it is safer to start the monitor always in preempt_irq,
|
|
* which may not mirror the system state but makes the monitor simpler,
|
|
*/
|
|
if (tif == TIF_NEED_RESCHED)
|
|
da_handle_start_event(tsk, sched_need_resched_nrp);
|
|
}
|
|
|
|
static void handle_schedule_entry(void *data, bool preempt)
|
|
{
|
|
if (preempt)
|
|
da_handle_event(current, schedule_entry_preempt_nrp);
|
|
else
|
|
da_handle_event(current, schedule_entry_nrp);
|
|
}
|
|
|
|
static int enable_nrp(void)
|
|
{
|
|
int retval;
|
|
|
|
retval = da_monitor_init();
|
|
if (retval)
|
|
return retval;
|
|
|
|
rv_attach_trace_probe("nrp", irq_handler_entry, handle_irq_entry);
|
|
rv_attach_trace_probe("nrp", sched_set_need_resched_tp, handle_sched_need_resched);
|
|
rv_attach_trace_probe("nrp", sched_entry_tp, handle_schedule_entry);
|
|
attach_vector_irq();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void disable_nrp(void)
|
|
{
|
|
rv_this.enabled = 0;
|
|
|
|
rv_detach_trace_probe("nrp", irq_handler_entry, handle_irq_entry);
|
|
rv_detach_trace_probe("nrp", sched_set_need_resched_tp, handle_sched_need_resched);
|
|
rv_detach_trace_probe("nrp", sched_entry_tp, handle_schedule_entry);
|
|
detach_vector_irq();
|
|
|
|
da_monitor_destroy();
|
|
}
|
|
|
|
static struct rv_monitor rv_this = {
|
|
.name = "nrp",
|
|
.description = "need resched preempts.",
|
|
.enable = enable_nrp,
|
|
.disable = disable_nrp,
|
|
.reset = da_monitor_reset_all,
|
|
.enabled = 0,
|
|
};
|
|
|
|
static int __init register_nrp(void)
|
|
{
|
|
return rv_register_monitor(&rv_this, &rv_sched);
|
|
}
|
|
|
|
static void __exit unregister_nrp(void)
|
|
{
|
|
rv_unregister_monitor(&rv_this);
|
|
}
|
|
|
|
module_init(register_nrp);
|
|
module_exit(unregister_nrp);
|
|
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>");
|
|
MODULE_DESCRIPTION("nrp: need resched preempts.");
|