mirror of https://github.com/torvalds/linux.git
tracing: Have function graph tracer option sleep-time be per instance
Currently the option to have function graph tracer to ignore time spent
when a task is sleeping is global when the interface is per-instance.
Changing the value in one instance will affect the results of another
instance that is also running the function graph tracer. This can lead to
confusing results.
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Link: https://patch.msgid.link/20251114192318.950255167@kernel.org
Fixes: c132be2c4f ("function_graph: Have the instances use their own ftrace_ops for filtering")
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
This commit is contained in:
parent
4132886e1b
commit
5abb6ccb58
|
|
@ -498,9 +498,6 @@ void *fgraph_retrieve_parent_data(int idx, int *size_bytes, int depth)
|
||||||
return get_data_type_data(current, offset);
|
return get_data_type_data(current, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Both enabled by default (can be cleared by function_graph tracer flags */
|
|
||||||
bool fgraph_sleep_time = true;
|
|
||||||
|
|
||||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||||
/*
|
/*
|
||||||
* archs can override this function if they must do something
|
* archs can override this function if they must do something
|
||||||
|
|
@ -1023,11 +1020,6 @@ void fgraph_init_ops(struct ftrace_ops *dst_ops,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ftrace_graph_sleep_time_control(bool enable)
|
|
||||||
{
|
|
||||||
fgraph_sleep_time = enable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Simply points to ftrace_stub, but with the proper protocol.
|
* Simply points to ftrace_stub, but with the proper protocol.
|
||||||
* Defined by the linker script in linux/vmlinux.lds.h
|
* Defined by the linker script in linux/vmlinux.lds.h
|
||||||
|
|
@ -1098,7 +1090,7 @@ ftrace_graph_probe_sched_switch(void *ignore, bool preempt,
|
||||||
* Does the user want to count the time a function was asleep.
|
* Does the user want to count the time a function was asleep.
|
||||||
* If so, do not update the time stamps.
|
* If so, do not update the time stamps.
|
||||||
*/
|
*/
|
||||||
if (fgraph_sleep_time)
|
if (!fgraph_no_sleep_time)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
timestamp = trace_clock_local();
|
timestamp = trace_clock_local();
|
||||||
|
|
|
||||||
|
|
@ -862,6 +862,8 @@ static int profile_graph_entry(struct ftrace_graph_ent *trace,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool fprofile_no_sleep_time;
|
||||||
|
|
||||||
static void profile_graph_return(struct ftrace_graph_ret *trace,
|
static void profile_graph_return(struct ftrace_graph_ret *trace,
|
||||||
struct fgraph_ops *gops,
|
struct fgraph_ops *gops,
|
||||||
struct ftrace_regs *fregs)
|
struct ftrace_regs *fregs)
|
||||||
|
|
@ -887,7 +889,7 @@ static void profile_graph_return(struct ftrace_graph_ret *trace,
|
||||||
|
|
||||||
calltime = rettime - profile_data->calltime;
|
calltime = rettime - profile_data->calltime;
|
||||||
|
|
||||||
if (!fgraph_sleep_time) {
|
if (fprofile_no_sleep_time) {
|
||||||
if (current->ftrace_sleeptime)
|
if (current->ftrace_sleeptime)
|
||||||
calltime -= current->ftrace_sleeptime - profile_data->sleeptime;
|
calltime -= current->ftrace_sleeptime - profile_data->sleeptime;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -943,8 +943,6 @@ static __always_inline bool ftrace_hash_empty(struct ftrace_hash *hash)
|
||||||
#define TRACE_GRAPH_PRINT_FILL_SHIFT 28
|
#define TRACE_GRAPH_PRINT_FILL_SHIFT 28
|
||||||
#define TRACE_GRAPH_PRINT_FILL_MASK (0x3 << TRACE_GRAPH_PRINT_FILL_SHIFT)
|
#define TRACE_GRAPH_PRINT_FILL_MASK (0x3 << TRACE_GRAPH_PRINT_FILL_SHIFT)
|
||||||
|
|
||||||
extern void ftrace_graph_sleep_time_control(bool enable);
|
|
||||||
|
|
||||||
#ifdef CONFIG_FUNCTION_PROFILER
|
#ifdef CONFIG_FUNCTION_PROFILER
|
||||||
extern void ftrace_graph_graph_time_control(bool enable);
|
extern void ftrace_graph_graph_time_control(bool enable);
|
||||||
#else
|
#else
|
||||||
|
|
@ -1115,7 +1113,8 @@ static inline void ftrace_graph_addr_finish(struct fgraph_ops *gops, struct ftra
|
||||||
#endif /* CONFIG_DYNAMIC_FTRACE */
|
#endif /* CONFIG_DYNAMIC_FTRACE */
|
||||||
|
|
||||||
extern unsigned int fgraph_max_depth;
|
extern unsigned int fgraph_max_depth;
|
||||||
extern bool fgraph_sleep_time;
|
extern unsigned int fgraph_no_sleep_time;
|
||||||
|
extern bool fprofile_no_sleep_time;
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
ftrace_graph_ignore_func(struct fgraph_ops *gops, struct ftrace_graph_ent *trace)
|
ftrace_graph_ignore_func(struct fgraph_ops *gops, struct ftrace_graph_ent *trace)
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,9 @@
|
||||||
/* When set, irq functions might be ignored */
|
/* When set, irq functions might be ignored */
|
||||||
static int ftrace_graph_skip_irqs;
|
static int ftrace_graph_skip_irqs;
|
||||||
|
|
||||||
|
/* Do not record function time when task is sleeping */
|
||||||
|
unsigned int fgraph_no_sleep_time;
|
||||||
|
|
||||||
struct fgraph_cpu_data {
|
struct fgraph_cpu_data {
|
||||||
pid_t last_pid;
|
pid_t last_pid;
|
||||||
int depth;
|
int depth;
|
||||||
|
|
@ -239,13 +242,14 @@ static int graph_entry(struct ftrace_graph_ent *trace,
|
||||||
if (ftrace_graph_ignore_irqs(tr))
|
if (ftrace_graph_ignore_irqs(tr))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (fgraph_sleep_time) {
|
if (fgraph_no_sleep_time &&
|
||||||
/* Only need to record the calltime */
|
!tracer_flags_is_set(tr, TRACE_GRAPH_SLEEP_TIME)) {
|
||||||
ftimes = fgraph_reserve_data(gops->idx, sizeof(ftimes->calltime));
|
|
||||||
} else {
|
|
||||||
ftimes = fgraph_reserve_data(gops->idx, sizeof(*ftimes));
|
ftimes = fgraph_reserve_data(gops->idx, sizeof(*ftimes));
|
||||||
if (ftimes)
|
if (ftimes)
|
||||||
ftimes->sleeptime = current->ftrace_sleeptime;
|
ftimes->sleeptime = current->ftrace_sleeptime;
|
||||||
|
} else {
|
||||||
|
/* Only need to record the calltime */
|
||||||
|
ftimes = fgraph_reserve_data(gops->idx, sizeof(ftimes->calltime));
|
||||||
}
|
}
|
||||||
if (!ftimes)
|
if (!ftimes)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -331,11 +335,15 @@ void __trace_graph_return(struct trace_array *tr,
|
||||||
trace_buffer_unlock_commit_nostack(buffer, event);
|
trace_buffer_unlock_commit_nostack(buffer, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_nosleeptime(struct ftrace_graph_ret *trace,
|
static void handle_nosleeptime(struct trace_array *tr,
|
||||||
|
struct ftrace_graph_ret *trace,
|
||||||
struct fgraph_times *ftimes,
|
struct fgraph_times *ftimes,
|
||||||
int size)
|
int size)
|
||||||
{
|
{
|
||||||
if (fgraph_sleep_time || size < sizeof(*ftimes))
|
if (size < sizeof(*ftimes))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!fgraph_no_sleep_time || tracer_flags_is_set(tr, TRACE_GRAPH_SLEEP_TIME))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ftimes->calltime += current->ftrace_sleeptime - ftimes->sleeptime;
|
ftimes->calltime += current->ftrace_sleeptime - ftimes->sleeptime;
|
||||||
|
|
@ -364,7 +372,7 @@ void trace_graph_return(struct ftrace_graph_ret *trace,
|
||||||
if (!ftimes)
|
if (!ftimes)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
handle_nosleeptime(trace, ftimes, size);
|
handle_nosleeptime(tr, trace, ftimes, size);
|
||||||
|
|
||||||
calltime = ftimes->calltime;
|
calltime = ftimes->calltime;
|
||||||
|
|
||||||
|
|
@ -377,6 +385,7 @@ static void trace_graph_thresh_return(struct ftrace_graph_ret *trace,
|
||||||
struct ftrace_regs *fregs)
|
struct ftrace_regs *fregs)
|
||||||
{
|
{
|
||||||
struct fgraph_times *ftimes;
|
struct fgraph_times *ftimes;
|
||||||
|
struct trace_array *tr;
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
ftrace_graph_addr_finish(gops, trace);
|
ftrace_graph_addr_finish(gops, trace);
|
||||||
|
|
@ -390,7 +399,8 @@ static void trace_graph_thresh_return(struct ftrace_graph_ret *trace,
|
||||||
if (!ftimes)
|
if (!ftimes)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
handle_nosleeptime(trace, ftimes, size);
|
tr = gops->private;
|
||||||
|
handle_nosleeptime(tr, trace, ftimes, size);
|
||||||
|
|
||||||
if (tracing_thresh &&
|
if (tracing_thresh &&
|
||||||
(trace_clock_local() - ftimes->calltime < tracing_thresh))
|
(trace_clock_local() - ftimes->calltime < tracing_thresh))
|
||||||
|
|
@ -452,6 +462,9 @@ static int graph_trace_init(struct trace_array *tr)
|
||||||
if (!tracer_flags_is_set(tr, TRACE_GRAPH_PRINT_IRQS))
|
if (!tracer_flags_is_set(tr, TRACE_GRAPH_PRINT_IRQS))
|
||||||
ftrace_graph_skip_irqs++;
|
ftrace_graph_skip_irqs++;
|
||||||
|
|
||||||
|
if (!tracer_flags_is_set(tr, TRACE_GRAPH_SLEEP_TIME))
|
||||||
|
fgraph_no_sleep_time++;
|
||||||
|
|
||||||
/* Make gops functions visible before we start tracing */
|
/* Make gops functions visible before we start tracing */
|
||||||
smp_mb();
|
smp_mb();
|
||||||
|
|
||||||
|
|
@ -494,6 +507,11 @@ static void graph_trace_reset(struct trace_array *tr)
|
||||||
if (WARN_ON_ONCE(ftrace_graph_skip_irqs < 0))
|
if (WARN_ON_ONCE(ftrace_graph_skip_irqs < 0))
|
||||||
ftrace_graph_skip_irqs = 0;
|
ftrace_graph_skip_irqs = 0;
|
||||||
|
|
||||||
|
if (!tracer_flags_is_set(tr, TRACE_GRAPH_SLEEP_TIME))
|
||||||
|
fgraph_no_sleep_time--;
|
||||||
|
if (WARN_ON_ONCE(fgraph_no_sleep_time < 0))
|
||||||
|
fgraph_no_sleep_time = 0;
|
||||||
|
|
||||||
tracing_stop_cmdline_record();
|
tracing_stop_cmdline_record();
|
||||||
unregister_ftrace_graph(tr->gops);
|
unregister_ftrace_graph(tr->gops);
|
||||||
}
|
}
|
||||||
|
|
@ -1619,8 +1637,24 @@ void graph_trace_close(struct trace_iterator *iter)
|
||||||
static int
|
static int
|
||||||
func_graph_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
|
func_graph_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
|
||||||
{
|
{
|
||||||
if (bit == TRACE_GRAPH_SLEEP_TIME)
|
/*
|
||||||
ftrace_graph_sleep_time_control(set);
|
* The function profiler gets updated even if function graph
|
||||||
|
* isn't the current tracer. Handle it separately.
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_FUNCTION_PROFILER
|
||||||
|
if (bit == TRACE_GRAPH_SLEEP_TIME && (tr->flags & TRACE_ARRAY_FL_GLOBAL) &&
|
||||||
|
!!set == fprofile_no_sleep_time) {
|
||||||
|
if (set) {
|
||||||
|
fgraph_no_sleep_time--;
|
||||||
|
if (WARN_ON_ONCE(fgraph_no_sleep_time < 0))
|
||||||
|
fgraph_no_sleep_time = 0;
|
||||||
|
fprofile_no_sleep_time = false;
|
||||||
|
} else {
|
||||||
|
fgraph_no_sleep_time++;
|
||||||
|
fprofile_no_sleep_time = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Do nothing if the current tracer is not this tracer */
|
/* Do nothing if the current tracer is not this tracer */
|
||||||
if (tr->current_trace != &graph_trace)
|
if (tr->current_trace != &graph_trace)
|
||||||
|
|
@ -1630,6 +1664,16 @@ func_graph_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
|
||||||
if (!!set == !!(tr->current_trace_flags->val & bit))
|
if (!!set == !!(tr->current_trace_flags->val & bit))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (bit == TRACE_GRAPH_SLEEP_TIME) {
|
||||||
|
if (set) {
|
||||||
|
fgraph_no_sleep_time--;
|
||||||
|
if (WARN_ON_ONCE(fgraph_no_sleep_time < 0))
|
||||||
|
fgraph_no_sleep_time = 0;
|
||||||
|
} else {
|
||||||
|
fgraph_no_sleep_time++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (bit == TRACE_GRAPH_PRINT_IRQS) {
|
if (bit == TRACE_GRAPH_PRINT_IRQS) {
|
||||||
if (set)
|
if (set)
|
||||||
ftrace_graph_skip_irqs--;
|
ftrace_graph_skip_irqs--;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue