mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
trace,smp: Add tracepoints around remotelly called functions
The recently added ipi_send_{cpu,cpumask} tracepoints allow finding sources of IPIs targeting CPUs running latency-sensitive applications. For NOHZ_FULL CPUs, all IPIs are interference, and those tracepoints are sufficient to find them and work on getting rid of them. In some setups however, not *all* IPIs are to be suppressed, but long-running IPI callbacks can still be problematic. Add a pair of tracepoints to mark the start and end of processing a CSD IPI callback, similar to what exists for softirq, workqueue or timer callbacks. Signed-off-by: Leonardo Bras <leobras@redhat.com> Tested-and-reviewed-by: Valentin Schneider <vschneid@redhat.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/20230615065944.188876-5-leobras@redhat.com
This commit is contained in:
parent
60be49bdf1
commit
949fa3f11c
45
include/trace/events/csd.h
Normal file
45
include/trace/events/csd.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
#undef TRACE_SYSTEM
|
||||||
|
#define TRACE_SYSTEM csd
|
||||||
|
|
||||||
|
#if !defined(_TRACE_CSD_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||||
|
#define _TRACE_CSD_H
|
||||||
|
|
||||||
|
#include <linux/tracepoint.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tracepoints for a function which is called as an effect of smp_call_function.*
|
||||||
|
*/
|
||||||
|
DECLARE_EVENT_CLASS(csd_function,
|
||||||
|
|
||||||
|
TP_PROTO(smp_call_func_t func, struct __call_single_data *csd),
|
||||||
|
|
||||||
|
TP_ARGS(func, csd),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field(void *, func)
|
||||||
|
__field(void *, csd)
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
__entry->func = func;
|
||||||
|
__entry->csd = csd;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk("func=%ps, csd=%p", __entry->func, __entry->csd)
|
||||||
|
);
|
||||||
|
|
||||||
|
DEFINE_EVENT(csd_function, csd_function_entry,
|
||||||
|
TP_PROTO(smp_call_func_t func, struct __call_single_data *csd),
|
||||||
|
TP_ARGS(func, csd)
|
||||||
|
);
|
||||||
|
|
||||||
|
DEFINE_EVENT(csd_function, csd_function_exit,
|
||||||
|
TP_PROTO(smp_call_func_t func, struct __call_single_data *csd),
|
||||||
|
TP_ARGS(func, csd)
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif /* _TRACE_CSD_H */
|
||||||
|
|
||||||
|
/* This part must be outside protection */
|
||||||
|
#include <trace/define_trace.h>
|
25
kernel/smp.c
25
kernel/smp.c
@ -27,6 +27,9 @@
|
|||||||
#include <linux/jump_label.h>
|
#include <linux/jump_label.h>
|
||||||
|
|
||||||
#include <trace/events/ipi.h>
|
#include <trace/events/ipi.h>
|
||||||
|
#define CREATE_TRACE_POINTS
|
||||||
|
#include <trace/events/csd.h>
|
||||||
|
#undef CREATE_TRACE_POINTS
|
||||||
|
|
||||||
#include "smpboot.h"
|
#include "smpboot.h"
|
||||||
#include "sched/smp.h"
|
#include "sched/smp.h"
|
||||||
@ -121,6 +124,14 @@ send_call_function_ipi_mask(struct cpumask *mask)
|
|||||||
arch_send_call_function_ipi_mask(mask);
|
arch_send_call_function_ipi_mask(mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static __always_inline void
|
||||||
|
csd_do_func(smp_call_func_t func, void *info, struct __call_single_data *csd)
|
||||||
|
{
|
||||||
|
trace_csd_function_entry(func, csd);
|
||||||
|
func(info);
|
||||||
|
trace_csd_function_exit(func, csd);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_CSD_LOCK_WAIT_DEBUG
|
#ifdef CONFIG_CSD_LOCK_WAIT_DEBUG
|
||||||
|
|
||||||
static DEFINE_STATIC_KEY_MAYBE(CONFIG_CSD_LOCK_WAIT_DEBUG_DEFAULT, csdlock_debug_enabled);
|
static DEFINE_STATIC_KEY_MAYBE(CONFIG_CSD_LOCK_WAIT_DEBUG_DEFAULT, csdlock_debug_enabled);
|
||||||
@ -375,7 +386,7 @@ static int generic_exec_single(int cpu, struct __call_single_data *csd)
|
|||||||
csd_lock_record(csd);
|
csd_lock_record(csd);
|
||||||
csd_unlock(csd);
|
csd_unlock(csd);
|
||||||
local_irq_save(flags);
|
local_irq_save(flags);
|
||||||
func(info);
|
csd_do_func(func, info, NULL);
|
||||||
csd_lock_record(NULL);
|
csd_lock_record(NULL);
|
||||||
local_irq_restore(flags);
|
local_irq_restore(flags);
|
||||||
return 0;
|
return 0;
|
||||||
@ -477,7 +488,7 @@ static void __flush_smp_call_function_queue(bool warn_cpu_offline)
|
|||||||
}
|
}
|
||||||
|
|
||||||
csd_lock_record(csd);
|
csd_lock_record(csd);
|
||||||
func(info);
|
csd_do_func(func, info, csd);
|
||||||
csd_unlock(csd);
|
csd_unlock(csd);
|
||||||
csd_lock_record(NULL);
|
csd_lock_record(NULL);
|
||||||
} else {
|
} else {
|
||||||
@ -508,7 +519,7 @@ static void __flush_smp_call_function_queue(bool warn_cpu_offline)
|
|||||||
|
|
||||||
csd_lock_record(csd);
|
csd_lock_record(csd);
|
||||||
csd_unlock(csd);
|
csd_unlock(csd);
|
||||||
func(info);
|
csd_do_func(func, info, csd);
|
||||||
csd_lock_record(NULL);
|
csd_lock_record(NULL);
|
||||||
} else if (type == CSD_TYPE_IRQ_WORK) {
|
} else if (type == CSD_TYPE_IRQ_WORK) {
|
||||||
irq_work_single(csd);
|
irq_work_single(csd);
|
||||||
@ -522,8 +533,10 @@ static void __flush_smp_call_function_queue(bool warn_cpu_offline)
|
|||||||
/*
|
/*
|
||||||
* Third; only CSD_TYPE_TTWU is left, issue those.
|
* Third; only CSD_TYPE_TTWU is left, issue those.
|
||||||
*/
|
*/
|
||||||
if (entry)
|
if (entry) {
|
||||||
sched_ttwu_pending(entry);
|
csd = llist_entry(entry, typeof(*csd), node.llist);
|
||||||
|
csd_do_func(sched_ttwu_pending, entry, csd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -816,7 +829,7 @@ static void smp_call_function_many_cond(const struct cpumask *mask,
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
local_irq_save(flags);
|
local_irq_save(flags);
|
||||||
func(info);
|
csd_do_func(func, info, NULL);
|
||||||
local_irq_restore(flags);
|
local_irq_restore(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user