mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
fgraph: Use fgraph data to store subtime for profiler
Instead of having the "subtime" for the function profiler in the infrastructure ftrace_ret_stack structure, have it use the fgraph data reserve and retrieve functions. This will keep the limited shadow stack from wasting 8 bytes for something that is seldom used. Cc: Mark Rutland <mark.rutland@arm.com> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Jiri Olsa <olsajiri@gmail.com> Link: https://lore.kernel.org/20240914214826.780323141@goodmis.org Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
This commit is contained in:
parent
a370b72ec7
commit
a312a0f783
@ -1081,6 +1081,7 @@ struct fgraph_ops {
|
||||
|
||||
void *fgraph_reserve_data(int idx, int size_bytes);
|
||||
void *fgraph_retrieve_data(int idx, int *size_bytes);
|
||||
void *fgraph_retrieve_parent_data(int idx, int *size_bytes, int depth);
|
||||
|
||||
/*
|
||||
* Stack of return addresses for functions
|
||||
@ -1091,9 +1092,6 @@ struct ftrace_ret_stack {
|
||||
unsigned long ret;
|
||||
unsigned long func;
|
||||
unsigned long long calltime;
|
||||
#ifdef CONFIG_FUNCTION_PROFILER
|
||||
unsigned long long subtime;
|
||||
#endif
|
||||
#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
|
||||
unsigned long fp;
|
||||
#endif
|
||||
|
@ -390,21 +390,7 @@ void *fgraph_reserve_data(int idx, int size_bytes)
|
||||
*/
|
||||
void *fgraph_retrieve_data(int idx, int *size_bytes)
|
||||
{
|
||||
int offset = current->curr_ret_stack - 1;
|
||||
unsigned long val;
|
||||
|
||||
val = get_fgraph_entry(current, offset);
|
||||
while (__get_type(val) == FGRAPH_TYPE_DATA) {
|
||||
if (__get_data_index(val) == idx)
|
||||
goto found;
|
||||
offset -= __get_data_size(val) + 1;
|
||||
val = get_fgraph_entry(current, offset);
|
||||
}
|
||||
return NULL;
|
||||
found:
|
||||
if (size_bytes)
|
||||
*size_bytes = __get_data_size(val) * sizeof(long);
|
||||
return get_data_type_data(current, offset);
|
||||
return fgraph_retrieve_parent_data(idx, size_bytes, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -460,6 +446,54 @@ get_ret_stack(struct task_struct *t, int offset, int *frame_offset)
|
||||
return RET_STACK(t, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* fgraph_retrieve_parent_data - get data from a parent function
|
||||
* @idx: The index into the fgraph_array (fgraph_ops::idx)
|
||||
* @size_bytes: A pointer to retrieved data size
|
||||
* @depth: The depth to find the parent (0 is the current function)
|
||||
*
|
||||
* This is similar to fgraph_retrieve_data() but can be used to retrieve
|
||||
* data from a parent caller function.
|
||||
*
|
||||
* Return: a pointer to the specified parent data or NULL if not found
|
||||
*/
|
||||
void *fgraph_retrieve_parent_data(int idx, int *size_bytes, int depth)
|
||||
{
|
||||
struct ftrace_ret_stack *ret_stack = NULL;
|
||||
int offset = current->curr_ret_stack;
|
||||
unsigned long val;
|
||||
|
||||
if (offset <= 0)
|
||||
return NULL;
|
||||
|
||||
for (;;) {
|
||||
int next_offset;
|
||||
|
||||
ret_stack = get_ret_stack(current, offset, &next_offset);
|
||||
if (!ret_stack || --depth < 0)
|
||||
break;
|
||||
offset = next_offset;
|
||||
}
|
||||
|
||||
if (!ret_stack)
|
||||
return NULL;
|
||||
|
||||
offset--;
|
||||
|
||||
val = get_fgraph_entry(current, offset);
|
||||
while (__get_type(val) == FGRAPH_TYPE_DATA) {
|
||||
if (__get_data_index(val) == idx)
|
||||
goto found;
|
||||
offset -= __get_data_size(val) + 1;
|
||||
val = get_fgraph_entry(current, offset);
|
||||
}
|
||||
return NULL;
|
||||
found:
|
||||
if (size_bytes)
|
||||
*size_bytes = __get_data_size(val) * sizeof(long);
|
||||
return get_data_type_data(current, offset);
|
||||
}
|
||||
|
||||
/* Both enabled by default (can be cleared by function_graph tracer flags */
|
||||
static bool fgraph_sleep_time = true;
|
||||
|
||||
|
@ -823,7 +823,7 @@ void ftrace_graph_graph_time_control(bool enable)
|
||||
static int profile_graph_entry(struct ftrace_graph_ent *trace,
|
||||
struct fgraph_ops *gops)
|
||||
{
|
||||
struct ftrace_ret_stack *ret_stack;
|
||||
unsigned long long *subtime;
|
||||
|
||||
function_profile_call(trace->func, 0, NULL, NULL);
|
||||
|
||||
@ -831,9 +831,9 @@ static int profile_graph_entry(struct ftrace_graph_ent *trace,
|
||||
if (!current->ret_stack)
|
||||
return 0;
|
||||
|
||||
ret_stack = ftrace_graph_get_ret_stack(current, 0);
|
||||
if (ret_stack)
|
||||
ret_stack->subtime = 0;
|
||||
subtime = fgraph_reserve_data(gops->idx, sizeof(*subtime));
|
||||
if (subtime)
|
||||
*subtime = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -841,11 +841,12 @@ static int profile_graph_entry(struct ftrace_graph_ent *trace,
|
||||
static void profile_graph_return(struct ftrace_graph_ret *trace,
|
||||
struct fgraph_ops *gops)
|
||||
{
|
||||
struct ftrace_ret_stack *ret_stack;
|
||||
struct ftrace_profile_stat *stat;
|
||||
unsigned long long calltime;
|
||||
unsigned long long *subtime;
|
||||
struct ftrace_profile *rec;
|
||||
unsigned long flags;
|
||||
int size;
|
||||
|
||||
local_irq_save(flags);
|
||||
stat = this_cpu_ptr(&ftrace_profile_stats);
|
||||
@ -861,13 +862,13 @@ static void profile_graph_return(struct ftrace_graph_ret *trace,
|
||||
if (!fgraph_graph_time) {
|
||||
|
||||
/* Append this call time to the parent time to subtract */
|
||||
ret_stack = ftrace_graph_get_ret_stack(current, 1);
|
||||
if (ret_stack)
|
||||
ret_stack->subtime += calltime;
|
||||
subtime = fgraph_retrieve_parent_data(gops->idx, &size, 1);
|
||||
if (subtime)
|
||||
*subtime += calltime;
|
||||
|
||||
ret_stack = ftrace_graph_get_ret_stack(current, 0);
|
||||
if (ret_stack && ret_stack->subtime < calltime)
|
||||
calltime -= ret_stack->subtime;
|
||||
subtime = fgraph_retrieve_data(gops->idx, &size);
|
||||
if (subtime && *subtime && *subtime < calltime)
|
||||
calltime -= *subtime;
|
||||
else
|
||||
calltime = 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user