Commit a312a0f7 authored by Steven Rostedt's avatar Steven Rostedt Committed by Steven Rostedt (Google)
Browse files

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: default avatarMasami Hiramatsu (Google) <mhiramat@kernel.org>
Signed-off-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
parent a370b72e
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -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
+49 −15
Original line number Diff line number Diff line
@@ -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;

+12 −11
Original line number Diff line number Diff line
@@ -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;
	}