Skip to content

Commit c7cc773

Browse files
author
Ingo Molnar
committed
Merge branches 'tracing/blktrace', 'tracing/ftrace', 'tracing/function-graph-tracer' and 'tracing/power-tracer' into tracing/core
4 parents 0bfc245 + d144d5e + 437f24f + f3f47a6 commit c7cc773

File tree

24 files changed

+1054
-273
lines changed

24 files changed

+1054
-273
lines changed

Documentation/ftrace.txt

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ of ftrace. Here is a list of some of the key files:
127127
be traced. If a function exists in both set_ftrace_filter
128128
and set_ftrace_notrace, the function will _not_ be traced.
129129

130+
set_ftrace_pid: Have the function tracer only trace a single thread.
131+
130132
available_filter_functions: This lists the functions that ftrace
131133
has processed and can trace. These are the function
132134
names that you can pass to "set_ftrace_filter" or
@@ -1073,6 +1075,83 @@ For simple one time traces, the above is sufficent. For anything else,
10731075
a search through /proc/mounts may be needed to find where the debugfs
10741076
file-system is mounted.
10751077

1078+
1079+
Single thread tracing
1080+
---------------------
1081+
1082+
By writing into /debug/tracing/set_ftrace_pid you can trace a
1083+
single thread. For example:
1084+
1085+
# cat /debug/tracing/set_ftrace_pid
1086+
no pid
1087+
# echo 3111 > /debug/tracing/set_ftrace_pid
1088+
# cat /debug/tracing/set_ftrace_pid
1089+
3111
1090+
# echo function > /debug/tracing/current_tracer
1091+
# cat /debug/tracing/trace | head
1092+
# tracer: function
1093+
#
1094+
# TASK-PID CPU# TIMESTAMP FUNCTION
1095+
# | | | | |
1096+
yum-updatesd-3111 [003] 1637.254676: finish_task_switch <-thread_return
1097+
yum-updatesd-3111 [003] 1637.254681: hrtimer_cancel <-schedule_hrtimeout_range
1098+
yum-updatesd-3111 [003] 1637.254682: hrtimer_try_to_cancel <-hrtimer_cancel
1099+
yum-updatesd-3111 [003] 1637.254683: lock_hrtimer_base <-hrtimer_try_to_cancel
1100+
yum-updatesd-3111 [003] 1637.254685: fget_light <-do_sys_poll
1101+
yum-updatesd-3111 [003] 1637.254686: pipe_poll <-do_sys_poll
1102+
# echo -1 > /debug/tracing/set_ftrace_pid
1103+
# cat /debug/tracing/trace |head
1104+
# tracer: function
1105+
#
1106+
# TASK-PID CPU# TIMESTAMP FUNCTION
1107+
# | | | | |
1108+
##### CPU 3 buffer started ####
1109+
yum-updatesd-3111 [003] 1701.957688: free_poll_entry <-poll_freewait
1110+
yum-updatesd-3111 [003] 1701.957689: remove_wait_queue <-free_poll_entry
1111+
yum-updatesd-3111 [003] 1701.957691: fput <-free_poll_entry
1112+
yum-updatesd-3111 [003] 1701.957692: audit_syscall_exit <-sysret_audit
1113+
yum-updatesd-3111 [003] 1701.957693: path_put <-audit_syscall_exit
1114+
1115+
If you want to trace a function when executing, you could use
1116+
something like this simple program:
1117+
1118+
#include <stdio.h>
1119+
#include <stdlib.h>
1120+
#include <sys/types.h>
1121+
#include <sys/stat.h>
1122+
#include <fcntl.h>
1123+
#include <unistd.h>
1124+
1125+
int main (int argc, char **argv)
1126+
{
1127+
if (argc < 1)
1128+
exit(-1);
1129+
1130+
if (fork() > 0) {
1131+
int fd, ffd;
1132+
char line[64];
1133+
int s;
1134+
1135+
ffd = open("/debug/tracing/current_tracer", O_WRONLY);
1136+
if (ffd < 0)
1137+
exit(-1);
1138+
write(ffd, "nop", 3);
1139+
1140+
fd = open("/debug/tracing/set_ftrace_pid", O_WRONLY);
1141+
s = sprintf(line, "%d\n", getpid());
1142+
write(fd, line, s);
1143+
1144+
write(ffd, "function", 8);
1145+
1146+
close(fd);
1147+
close(ffd);
1148+
1149+
execvp(argv[1], argv+1);
1150+
}
1151+
1152+
return 0;
1153+
}
1154+
10761155
dynamic ftrace
10771156
--------------
10781157

arch/x86/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ config X86
2929
select HAVE_FTRACE_MCOUNT_RECORD
3030
select HAVE_DYNAMIC_FTRACE
3131
select HAVE_FUNCTION_TRACER
32-
select HAVE_FUNCTION_RET_TRACER if X86_32
32+
select HAVE_FUNCTION_GRAPH_TRACER if X86_32
3333
select HAVE_FUNCTION_TRACE_MCOUNT_TEST
3434
select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64)
3535
select HAVE_ARCH_KGDB if !X86_VOYAGER

arch/x86/include/asm/ftrace.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ struct dyn_arch_ftrace {
2828
#endif /* __ASSEMBLY__ */
2929
#endif /* CONFIG_FUNCTION_TRACER */
3030

31-
#ifdef CONFIG_FUNCTION_RET_TRACER
31+
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
3232

3333
#ifndef __ASSEMBLY__
3434

@@ -51,6 +51,6 @@ struct ftrace_ret_stack {
5151
extern void return_to_handler(void);
5252

5353
#endif /* __ASSEMBLY__ */
54-
#endif /* CONFIG_FUNCTION_RET_TRACER */
54+
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
5555

5656
#endif /* _ASM_X86_FTRACE_H */

arch/x86/kernel/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ CFLAGS_REMOVE_paravirt-spinlocks.o = -pg
1414
CFLAGS_REMOVE_ftrace.o = -pg
1515
endif
1616

17-
ifdef CONFIG_FUNCTION_RET_TRACER
17+
ifdef CONFIG_FUNCTION_GRAPH_TRACER
1818
# Don't trace __switch_to() but let it for function tracer
1919
CFLAGS_REMOVE_process_32.o = -pg
2020
endif
@@ -70,7 +70,7 @@ obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o
7070
obj-$(CONFIG_X86_IO_APIC) += io_apic.o
7171
obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups_32.o
7272
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
73-
obj-$(CONFIG_FUNCTION_RET_TRACER) += ftrace.o
73+
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
7474
obj-$(CONFIG_KEXEC) += machine_kexec_$(BITS).o
7575
obj-$(CONFIG_KEXEC) += relocate_kernel_$(BITS).o crash.o
7676
obj-$(CONFIG_CRASH_DUMP) += crash_dump_$(BITS).o

arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <linux/cpufreq.h>
3434
#include <linux/compiler.h>
3535
#include <linux/dmi.h>
36+
#include <linux/ftrace.h>
3637

3738
#include <linux/acpi.h>
3839
#include <acpi/processor.h>
@@ -391,6 +392,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
391392
unsigned int next_perf_state = 0; /* Index into perf table */
392393
unsigned int i;
393394
int result = 0;
395+
struct power_trace it;
394396

395397
dprintk("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu);
396398

@@ -427,6 +429,8 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
427429
}
428430
}
429431

432+
trace_power_mark(&it, POWER_PSTATE, next_perf_state);
433+
430434
switch (data->cpu_feature) {
431435
case SYSTEM_INTEL_MSR_CAPABLE:
432436
cmd.type = SYSTEM_INTEL_MSR_CAPABLE;

arch/x86/kernel/entry_32.S

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,6 +1174,11 @@ ftrace_call:
11741174
popl %edx
11751175
popl %ecx
11761176
popl %eax
1177+
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
1178+
.globl ftrace_graph_call
1179+
ftrace_graph_call:
1180+
jmp ftrace_stub
1181+
#endif
11771182

11781183
.globl ftrace_stub
11791184
ftrace_stub:
@@ -1188,9 +1193,9 @@ ENTRY(mcount)
11881193

11891194
cmpl $ftrace_stub, ftrace_trace_function
11901195
jnz trace
1191-
#ifdef CONFIG_FUNCTION_RET_TRACER
1192-
cmpl $ftrace_stub, ftrace_function_return
1193-
jnz ftrace_return_caller
1196+
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
1197+
cmpl $ftrace_stub, ftrace_graph_return
1198+
jnz ftrace_graph_caller
11941199
#endif
11951200
.globl ftrace_stub
11961201
ftrace_stub:
@@ -1215,8 +1220,8 @@ END(mcount)
12151220
#endif /* CONFIG_DYNAMIC_FTRACE */
12161221
#endif /* CONFIG_FUNCTION_TRACER */
12171222

1218-
#ifdef CONFIG_FUNCTION_RET_TRACER
1219-
ENTRY(ftrace_return_caller)
1223+
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
1224+
ENTRY(ftrace_graph_caller)
12201225
cmpl $0, function_trace_stop
12211226
jne ftrace_stub
12221227

@@ -1230,7 +1235,7 @@ ENTRY(ftrace_return_caller)
12301235
popl %ecx
12311236
popl %eax
12321237
ret
1233-
END(ftrace_return_caller)
1238+
END(ftrace_graph_caller)
12341239

12351240
.globl return_to_handler
12361241
return_to_handler:

arch/x86/kernel/ftrace.c

Lines changed: 72 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ static void ftrace_mod_code(void)
111111
*/
112112
mod_code_status = probe_kernel_write(mod_code_ip, mod_code_newcode,
113113
MCOUNT_INSN_SIZE);
114-
115114
}
116115

117116
void ftrace_nmi_enter(void)
@@ -323,9 +322,53 @@ int __init ftrace_dyn_arch_init(void *data)
323322
}
324323
#endif
325324

326-
#ifdef CONFIG_FUNCTION_RET_TRACER
325+
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
326+
327+
#ifdef CONFIG_DYNAMIC_FTRACE
328+
extern void ftrace_graph_call(void);
329+
330+
static int ftrace_mod_jmp(unsigned long ip,
331+
int old_offset, int new_offset)
332+
{
333+
unsigned char code[MCOUNT_INSN_SIZE];
334+
335+
if (probe_kernel_read(code, (void *)ip, MCOUNT_INSN_SIZE))
336+
return -EFAULT;
337+
338+
if (code[0] != 0xe9 || old_offset != *(int *)(&code[1]))
339+
return -EINVAL;
340+
341+
*(int *)(&code[1]) = new_offset;
342+
343+
if (do_ftrace_mod_code(ip, &code))
344+
return -EPERM;
345+
346+
return 0;
347+
}
348+
349+
int ftrace_enable_ftrace_graph_caller(void)
350+
{
351+
unsigned long ip = (unsigned long)(&ftrace_graph_call);
352+
int old_offset, new_offset;
353+
354+
old_offset = (unsigned long)(&ftrace_stub) - (ip + MCOUNT_INSN_SIZE);
355+
new_offset = (unsigned long)(&ftrace_graph_caller) - (ip + MCOUNT_INSN_SIZE);
356+
357+
return ftrace_mod_jmp(ip, old_offset, new_offset);
358+
}
359+
360+
int ftrace_disable_ftrace_graph_caller(void)
361+
{
362+
unsigned long ip = (unsigned long)(&ftrace_graph_call);
363+
int old_offset, new_offset;
364+
365+
old_offset = (unsigned long)(&ftrace_graph_caller) - (ip + MCOUNT_INSN_SIZE);
366+
new_offset = (unsigned long)(&ftrace_stub) - (ip + MCOUNT_INSN_SIZE);
367+
368+
return ftrace_mod_jmp(ip, old_offset, new_offset);
369+
}
327370

328-
#ifndef CONFIG_DYNAMIC_FTRACE
371+
#else /* CONFIG_DYNAMIC_FTRACE */
329372

330373
/*
331374
* These functions are picked from those used on
@@ -343,11 +386,12 @@ void ftrace_nmi_exit(void)
343386
{
344387
atomic_dec(&in_nmi);
345388
}
389+
346390
#endif /* !CONFIG_DYNAMIC_FTRACE */
347391

348392
/* Add a function return address to the trace stack on thread info.*/
349393
static int push_return_trace(unsigned long ret, unsigned long long time,
350-
unsigned long func)
394+
unsigned long func, int *depth)
351395
{
352396
int index;
353397

@@ -365,21 +409,22 @@ static int push_return_trace(unsigned long ret, unsigned long long time,
365409
current->ret_stack[index].ret = ret;
366410
current->ret_stack[index].func = func;
367411
current->ret_stack[index].calltime = time;
412+
*depth = index;
368413

369414
return 0;
370415
}
371416

372417
/* Retrieve a function return address to the trace stack on thread info.*/
373-
static void pop_return_trace(unsigned long *ret, unsigned long long *time,
374-
unsigned long *func, unsigned long *overrun)
418+
static void pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret)
375419
{
376420
int index;
377421

378422
index = current->curr_ret_stack;
379423
*ret = current->ret_stack[index].ret;
380-
*func = current->ret_stack[index].func;
381-
*time = current->ret_stack[index].calltime;
382-
*overrun = atomic_read(&current->trace_overrun);
424+
trace->func = current->ret_stack[index].func;
425+
trace->calltime = current->ret_stack[index].calltime;
426+
trace->overrun = atomic_read(&current->trace_overrun);
427+
trace->depth = index;
383428
current->curr_ret_stack--;
384429
}
385430

@@ -389,13 +434,14 @@ static void pop_return_trace(unsigned long *ret, unsigned long long *time,
389434
*/
390435
unsigned long ftrace_return_to_handler(void)
391436
{
392-
struct ftrace_retfunc trace;
393-
pop_return_trace(&trace.ret, &trace.calltime, &trace.func,
394-
&trace.overrun);
437+
struct ftrace_graph_ret trace;
438+
unsigned long ret;
439+
440+
pop_return_trace(&trace, &ret);
395441
trace.rettime = cpu_clock(raw_smp_processor_id());
396-
ftrace_function_return(&trace);
442+
ftrace_graph_return(&trace);
397443

398-
return trace.ret;
444+
return ret;
399445
}
400446

401447
/*
@@ -407,6 +453,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
407453
unsigned long old;
408454
unsigned long long calltime;
409455
int faulted;
456+
struct ftrace_graph_ent trace;
410457
unsigned long return_hooker = (unsigned long)
411458
&return_to_handler;
412459

@@ -440,20 +487,27 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
440487
);
441488

442489
if (WARN_ON(faulted)) {
443-
unregister_ftrace_return();
490+
unregister_ftrace_graph();
444491
return;
445492
}
446493

447494
if (WARN_ON(!__kernel_text_address(old))) {
448-
unregister_ftrace_return();
495+
unregister_ftrace_graph();
449496
*parent = old;
450497
return;
451498
}
452499

453500
calltime = cpu_clock(raw_smp_processor_id());
454501

455-
if (push_return_trace(old, calltime, self_addr) == -EBUSY)
502+
if (push_return_trace(old, calltime,
503+
self_addr, &trace.depth) == -EBUSY) {
456504
*parent = old;
505+
return;
506+
}
507+
508+
trace.func = self_addr;
509+
ftrace_graph_entry(&trace);
510+
457511
}
458512

459-
#endif /* CONFIG_FUNCTION_RET_TRACER */
513+
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */

0 commit comments

Comments
 (0)