Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2bcd521a authored by Steven Rostedt's avatar Steven Rostedt Committed by Ingo Molnar
Browse files

trace: profile all if conditionals



Impact: feature to profile if statements

This patch adds a branch profiler for all if () statements.
The results will be found in:

  /debugfs/tracing/profile_branch

For example:

   miss      hit    %        Function                  File              Line
 ------- ---------  -        --------                  ----              ----
       0        1 100 x86_64_start_reservations      head64.c             127
       0        1 100 copy_bootdata                  head64.c             69
       1        0   0 x86_64_start_kernel            head64.c             111
      32        0   0 set_intr_gate                  desc.h               319
       1        0   0 reserve_ebda_region            head.c               51
       1        0   0 reserve_ebda_region            head.c               47
       0        1 100 reserve_ebda_region            head.c               42
       0        0   X maxcpus                        main.c               165

Miss means the branch was not taken. Hit means the branch was taken.
The percent is the percentage the branch was taken.

This adds a significant amount of overhead and should only be used
by those analyzing their system.

Signed-off-by: default avatarSteven Rostedt <srostedt@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent bac28bfe
Loading
Loading
Loading
Loading
+10 −1
Original line number Original line Diff line number Diff line
@@ -53,6 +53,14 @@
#define LIKELY_PROFILE()
#define LIKELY_PROFILE()
#endif
#endif


#ifdef CONFIG_PROFILE_ALL_BRANCHES
#define BRANCH_PROFILE()	VMLINUX_SYMBOL(__start_branch_profile) = .;   \
				*(_ftrace_branch)			      \
				VMLINUX_SYMBOL(__stop_branch_profile) = .;
#else
#define BRANCH_PROFILE()
#endif

/* .data section */
/* .data section */
#define DATA_DATA							\
#define DATA_DATA							\
	*(.data)							\
	*(.data)							\
@@ -72,7 +80,8 @@
	VMLINUX_SYMBOL(__start___tracepoints) = .;			\
	VMLINUX_SYMBOL(__start___tracepoints) = .;			\
	*(__tracepoints)						\
	*(__tracepoints)						\
	VMLINUX_SYMBOL(__stop___tracepoints) = .;			\
	VMLINUX_SYMBOL(__stop___tracepoints) = .;			\
	LIKELY_PROFILE()
	LIKELY_PROFILE()		       				\
	BRANCH_PROFILE()


#define RO_DATA(align)							\
#define RO_DATA(align)							\
	. = ALIGN((align));						\
	. = ALIGN((align));						\
+36 −2
Original line number Original line Diff line number Diff line
@@ -63,9 +63,17 @@ struct ftrace_branch_data {
	const char *func;
	const char *func;
	const char *file;
	const char *file;
	unsigned line;
	unsigned line;
	union {
		struct {
			unsigned long correct;
			unsigned long correct;
			unsigned long incorrect;
			unsigned long incorrect;
		};
		};
		struct {
			unsigned long miss;
			unsigned long hit;
		};
	};
};


/*
/*
 * Note: DISABLE_BRANCH_PROFILING can be used by special lowlevel code
 * Note: DISABLE_BRANCH_PROFILING can be used by special lowlevel code
@@ -103,6 +111,32 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
# ifndef unlikely
# ifndef unlikely
#  define unlikely(x)	(__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 0))
#  define unlikely(x)	(__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 0))
# endif
# endif

#ifdef CONFIG_PROFILE_ALL_BRANCHES
/*
 * "Define 'is'", Bill Clinton
 * "Define 'if'", Steven Rostedt
 */
#define if(cond) if (__builtin_constant_p((cond)) ? !!(cond) :		\
	({								\
		int ______r;						\
		static struct ftrace_branch_data			\
			__attribute__((__aligned__(4)))			\
			__attribute__((section("_ftrace_branch")))	\
			______f = {					\
				.func = __func__,			\
				.file = __FILE__,			\
				.line = __LINE__,			\
			};						\
		______r = !!(cond);					\
		if (______r)						\
			______f.hit++;					\
		else							\
			______f.miss++;					\
		______r;						\
	}))
#endif /* CONFIG_PROFILE_ALL_BRANCHES */

#else
#else
# define likely(x)	__builtin_expect(!!(x), 1)
# define likely(x)	__builtin_expect(!!(x), 1)
# define unlikely(x)	__builtin_expect(!!(x), 0)
# define unlikely(x)	__builtin_expect(!!(x), 0)
+16 −0
Original line number Original line Diff line number Diff line
@@ -173,6 +173,22 @@ config TRACE_BRANCH_PROFILING


	  Say N if unsure.
	  Say N if unsure.


config PROFILE_ALL_BRANCHES
	bool "Profile all if conditionals"
	depends on TRACE_BRANCH_PROFILING
	help
	  This tracer profiles all branch conditions. Every if ()
	  taken in the kernel is recorded whether it hit or miss.
	  The results will be displayed in:

	  /debugfs/tracing/profile_branch

	  This configuration, when enabled, will impose a great overhead
	  on the system. This should only be enabled when the system
	  is to be analyzed

	  Say N if unsure.

config TRACING_BRANCHES
config TRACING_BRANCHES
	bool
	bool
	help
	help
+31 −2
Original line number Original line Diff line number Diff line
@@ -185,6 +185,7 @@ EXPORT_SYMBOL(ftrace_likely_update);
struct ftrace_pointer {
struct ftrace_pointer {
	void		*start;
	void		*start;
	void		*stop;
	void		*stop;
	int		hit;
};
};


static void *
static void *
@@ -223,13 +224,17 @@ static void t_stop(struct seq_file *m, void *p)


static int t_show(struct seq_file *m, void *v)
static int t_show(struct seq_file *m, void *v)
{
{
	struct ftrace_pointer *fp = m->private;
	struct ftrace_branch_data *p = v;
	struct ftrace_branch_data *p = v;
	const char *f;
	const char *f;
	long percent;
	long percent;


	if (v == (void *)1) {
	if (v == (void *)1) {
		seq_printf(m, " correct incorrect  %% "
		if (fp->hit)
			      "       Function                "
			seq_printf(m, "   miss      hit    %% ");
		else
			seq_printf(m, " correct incorrect  %% ");
		seq_printf(m, "       Function                "
			      "  File              Line\n"
			      "  File              Line\n"
			      " ------- ---------  - "
			      " ------- ---------  - "
			      "       --------                "
			      "       --------                "
@@ -243,6 +248,9 @@ static int t_show(struct seq_file *m, void *v)
		f--;
		f--;
	f++;
	f++;


	/*
	 * The miss is overlayed on correct, and hit on incorrect.
	 */
	if (p->correct) {
	if (p->correct) {
		percent = p->incorrect * 100;
		percent = p->incorrect * 100;
		percent /= p->correct + p->incorrect;
		percent /= p->correct + p->incorrect;
@@ -284,6 +292,18 @@ static const struct file_operations tracing_branch_fops = {
	.llseek		= seq_lseek,
	.llseek		= seq_lseek,
};
};


#ifdef CONFIG_PROFILE_ALL_BRANCHES
extern unsigned long __start_branch_profile[];
extern unsigned long __stop_branch_profile[];

static struct ftrace_pointer ftrace_branch_pos = {
	.start			= __start_branch_profile,
	.stop			= __stop_branch_profile,
	.hit			= 1,
};

#endif /* CONFIG_PROFILE_ALL_BRANCHES */

extern unsigned long __start_annotated_branch_profile[];
extern unsigned long __start_annotated_branch_profile[];
extern unsigned long __stop_annotated_branch_profile[];
extern unsigned long __stop_annotated_branch_profile[];


@@ -306,6 +326,15 @@ static __init int ftrace_branch_init(void)
		pr_warning("Could not create debugfs "
		pr_warning("Could not create debugfs "
			   "'profile_annotatet_branch' entry\n");
			   "'profile_annotatet_branch' entry\n");


#ifdef CONFIG_PROFILE_ALL_BRANCHES
	entry = debugfs_create_file("profile_branch", 0444, d_tracer,
				    &ftrace_branch_pos,
				    &tracing_branch_fops);
	if (!entry)
		pr_warning("Could not create debugfs"
			   " 'profile_branch' entry\n");
#endif

	return 0;
	return 0;
}
}