Skip to content

Commit f1f36e2

Browse files
committed
ftrace: Have calltime be saved in the fgraph storage
The calltime field in the shadow stack frame is only used by the function graph tracer and profiler. But now that there's other users of the function graph infrastructure, this adds overhead and wastes space on the shadow stack. Move the calltime to the fgraph data storage, where the function graph and profiler entry functions will save it in its own graph storage and retrieve it in its exit functions. Cc: Mark Rutland <[email protected]> Cc: Mathieu Desnoyers <[email protected]> Cc: Andrew Morton <[email protected]> Cc: Jiri Olsa <[email protected]> Link: https://lore.kernel.org/[email protected] Acked-by: Masami Hiramatsu (Google) <[email protected]> Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent 3c9880f commit f1f36e2

File tree

4 files changed

+51
-34
lines changed

4 files changed

+51
-34
lines changed

include/linux/ftrace.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1091,7 +1091,6 @@ void *fgraph_retrieve_parent_data(int idx, int *size_bytes, int depth);
10911091
struct ftrace_ret_stack {
10921092
unsigned long ret;
10931093
unsigned long func;
1094-
unsigned long long calltime;
10951094
#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
10961095
unsigned long fp;
10971096
#endif

kernel/trace/fgraph.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,6 @@ ftrace_push_return_trace(unsigned long ret, unsigned long func,
558558
int fgraph_idx)
559559
{
560560
struct ftrace_ret_stack *ret_stack;
561-
unsigned long long calltime;
562561
unsigned long val;
563562
int offset;
564563

@@ -588,8 +587,6 @@ ftrace_push_return_trace(unsigned long ret, unsigned long func,
588587
return -EBUSY;
589588
}
590589

591-
calltime = trace_clock_local();
592-
593590
offset = READ_ONCE(current->curr_ret_stack);
594591
ret_stack = RET_STACK(current, offset);
595592
offset += FGRAPH_FRAME_OFFSET;
@@ -623,7 +620,6 @@ ftrace_push_return_trace(unsigned long ret, unsigned long func,
623620

624621
ret_stack->ret = ret;
625622
ret_stack->func = func;
626-
ret_stack->calltime = calltime;
627623
#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
628624
ret_stack->fp = frame_pointer;
629625
#endif
@@ -757,7 +753,6 @@ ftrace_pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret,
757753
*offset += FGRAPH_FRAME_OFFSET;
758754
*ret = ret_stack->ret;
759755
trace->func = ret_stack->func;
760-
trace->calltime = ret_stack->calltime;
761756
trace->overrun = atomic_read(&current->trace_overrun);
762757
trace->depth = current->curr_ret_depth;
763758
/*

kernel/trace/ftrace.c

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,7 @@ void ftrace_graph_graph_time_control(bool enable)
821821
}
822822

823823
struct profile_fgraph_data {
824+
unsigned long long calltime;
824825
unsigned long long subtime;
825826
unsigned long long sleeptime;
826827
};
@@ -842,6 +843,7 @@ static int profile_graph_entry(struct ftrace_graph_ent *trace,
842843

843844
profile_data->subtime = 0;
844845
profile_data->sleeptime = current->ftrace_sleeptime;
846+
profile_data->calltime = trace_clock_local();
845847

846848
return 1;
847849
}
@@ -850,9 +852,9 @@ static void profile_graph_return(struct ftrace_graph_ret *trace,
850852
struct fgraph_ops *gops)
851853
{
852854
struct profile_fgraph_data *profile_data;
853-
struct profile_fgraph_data *parent_data;
854855
struct ftrace_profile_stat *stat;
855856
unsigned long long calltime;
857+
unsigned long long rettime = trace_clock_local();
856858
struct ftrace_profile *rec;
857859
unsigned long flags;
858860
int size;
@@ -862,29 +864,28 @@ static void profile_graph_return(struct ftrace_graph_ret *trace,
862864
if (!stat->hash || !ftrace_profile_enabled)
863865
goto out;
864866

867+
profile_data = fgraph_retrieve_data(gops->idx, &size);
868+
865869
/* If the calltime was zero'd ignore it */
866-
if (!trace->calltime)
870+
if (!profile_data || !profile_data->calltime)
867871
goto out;
868872

869-
calltime = trace->rettime - trace->calltime;
873+
calltime = rettime - profile_data->calltime;
870874

871875
if (!fgraph_sleep_time) {
872-
profile_data = fgraph_retrieve_data(gops->idx, &size);
873-
if (profile_data && current->ftrace_sleeptime)
876+
if (current->ftrace_sleeptime)
874877
calltime -= current->ftrace_sleeptime - profile_data->sleeptime;
875878
}
876879

877880
if (!fgraph_graph_time) {
881+
struct profile_fgraph_data *parent_data;
878882

879883
/* Append this call time to the parent time to subtract */
880884
parent_data = fgraph_retrieve_parent_data(gops->idx, &size, 1);
881885
if (parent_data)
882886
parent_data->subtime += calltime;
883887

884-
if (!profile_data)
885-
profile_data = fgraph_retrieve_data(gops->idx, &size);
886-
887-
if (profile_data && profile_data->subtime && profile_data->subtime < calltime)
888+
if (profile_data->subtime && profile_data->subtime < calltime)
888889
calltime -= profile_data->subtime;
889890
else
890891
calltime = 0;

kernel/trace/trace_functions_graph.c

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,18 @@ static inline int ftrace_graph_ignore_irqs(void)
127127
return in_hardirq();
128128
}
129129

130+
struct fgraph_times {
131+
unsigned long long calltime;
132+
unsigned long long sleeptime; /* may be optional! */
133+
};
134+
130135
int trace_graph_entry(struct ftrace_graph_ent *trace,
131136
struct fgraph_ops *gops)
132137
{
133138
unsigned long *task_var = fgraph_get_task_var(gops);
134139
struct trace_array *tr = gops->private;
135140
struct trace_array_cpu *data;
136-
unsigned long *sleeptime;
141+
struct fgraph_times *ftimes;
137142
unsigned long flags;
138143
unsigned int trace_ctx;
139144
long disabled;
@@ -168,12 +173,18 @@ int trace_graph_entry(struct ftrace_graph_ent *trace,
168173
if (ftrace_graph_ignore_irqs())
169174
return 0;
170175

171-
/* save the current sleep time if we are to ignore it */
172-
if (!fgraph_sleep_time) {
173-
sleeptime = fgraph_reserve_data(gops->idx, sizeof(*sleeptime));
174-
if (sleeptime)
175-
*sleeptime = current->ftrace_sleeptime;
176+
if (fgraph_sleep_time) {
177+
/* Only need to record the calltime */
178+
ftimes = fgraph_reserve_data(gops->idx, sizeof(ftimes->calltime));
179+
} else {
180+
ftimes = fgraph_reserve_data(gops->idx, sizeof(*ftimes));
181+
if (ftimes)
182+
ftimes->sleeptime = current->ftrace_sleeptime;
176183
}
184+
if (!ftimes)
185+
return 0;
186+
187+
ftimes->calltime = trace_clock_local();
177188

178189
/*
179190
* Stop here if tracing_threshold is set. We only write function return
@@ -247,19 +258,13 @@ void __trace_graph_return(struct trace_array *tr,
247258
}
248259

249260
static void handle_nosleeptime(struct ftrace_graph_ret *trace,
250-
struct fgraph_ops *gops)
261+
struct fgraph_times *ftimes,
262+
int size)
251263
{
252-
unsigned long long *sleeptime;
253-
int size;
254-
255-
if (fgraph_sleep_time)
256-
return;
257-
258-
sleeptime = fgraph_retrieve_data(gops->idx, &size);
259-
if (!sleeptime)
264+
if (fgraph_sleep_time || size < sizeof(*ftimes))
260265
return;
261266

262-
trace->calltime += current->ftrace_sleeptime - *sleeptime;
267+
ftimes->calltime += current->ftrace_sleeptime - ftimes->sleeptime;
263268
}
264269

265270
void trace_graph_return(struct ftrace_graph_ret *trace,
@@ -268,9 +273,11 @@ void trace_graph_return(struct ftrace_graph_ret *trace,
268273
unsigned long *task_var = fgraph_get_task_var(gops);
269274
struct trace_array *tr = gops->private;
270275
struct trace_array_cpu *data;
276+
struct fgraph_times *ftimes;
271277
unsigned long flags;
272278
unsigned int trace_ctx;
273279
long disabled;
280+
int size;
274281
int cpu;
275282

276283
ftrace_graph_addr_finish(gops, trace);
@@ -280,7 +287,13 @@ void trace_graph_return(struct ftrace_graph_ret *trace,
280287
return;
281288
}
282289

283-
handle_nosleeptime(trace, gops);
290+
ftimes = fgraph_retrieve_data(gops->idx, &size);
291+
if (!ftimes)
292+
return;
293+
294+
handle_nosleeptime(trace, ftimes, size);
295+
296+
trace->calltime = ftimes->calltime;
284297

285298
local_irq_save(flags);
286299
cpu = raw_smp_processor_id();
@@ -297,17 +310,26 @@ void trace_graph_return(struct ftrace_graph_ret *trace,
297310
static void trace_graph_thresh_return(struct ftrace_graph_ret *trace,
298311
struct fgraph_ops *gops)
299312
{
313+
struct fgraph_times *ftimes;
314+
int size;
315+
300316
ftrace_graph_addr_finish(gops, trace);
301317

302318
if (trace_recursion_test(TRACE_GRAPH_NOTRACE_BIT)) {
303319
trace_recursion_clear(TRACE_GRAPH_NOTRACE_BIT);
304320
return;
305321
}
306322

307-
handle_nosleeptime(trace, gops);
323+
ftimes = fgraph_retrieve_data(gops->idx, &size);
324+
if (!ftimes)
325+
return;
326+
327+
handle_nosleeptime(trace, ftimes, size);
328+
329+
trace->calltime = ftimes->calltime;
308330

309331
if (tracing_thresh &&
310-
(trace->rettime - trace->calltime < tracing_thresh))
332+
(trace->rettime - ftimes->calltime < tracing_thresh))
311333
return;
312334
else
313335
trace_graph_return(trace, gops);

0 commit comments

Comments
 (0)