aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Ahern <dsahern@gmail.com>2016-11-16 01:06:32 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2016-11-23 08:44:09 -0500
commit6c973c90852c3fa4b4e76a061ce89dcd373efccc (patch)
tree72efae60d507320855c1a1844b7d112d54411c44
parentfc1469f1b20777929a47f6f8e55bca12c6f142ac (diff)
perf sched timehist: Add call graph options
If callchains were recorded they are appended to the line with a default stack depth of 5: 1.874569 [0011] gcc[31949] 0.014 0.000 1.148 wait_for_completion_killable <- do_fork <- sys_vfork <- stub_vfork <- __vfork 1.874591 [0010] gcc[31951] 0.000 0.000 0.024 __cond_resched <- _cond_resched <- wait_for_completion <- stop_one_cpu <- sched_exec 1.874603 [0010] migration/10[59] 3.350 0.004 0.011 smpboot_thread_fn <- kthread <- ret_from_fork 1.874604 [0011] <idle> 1.148 0.000 0.035 cpu_startup_entry <- start_secondary 1.874723 [0005] <idle> 0.016 0.000 1.383 cpu_startup_entry <- start_secondary 1.874746 [0005] gcc[31949] 0.153 0.078 0.022 do_wait sys_wait4 <- system_call_fastpath <- __GI___waitpid --no-call-graph can be used to not show the callchains. --max-stack is used to control the number of frames shown (default of 5). -x/--excl options can be used to collapse redundant callchains to get more relevant data on screen. Signed-off-by: David Ahern <dsahern@gmail.com> Signed-off-by: Namhyung Kim <namhyung@kernel.org> Acked-by: Ingo Molnar <mingo@kernel.org> Acked-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Andi Kleen <andi@firstfloor.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/r/20161116060634.28477-7-namhyung@kernel.org [ Add documentation based on above commit message ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/Documentation/perf-sched.txt7
-rw-r--r--tools/perf/builtin-sched.c88
2 files changed, 89 insertions, 6 deletions
diff --git a/tools/perf/Documentation/perf-sched.txt b/tools/perf/Documentation/perf-sched.txt
index 9a77bc73e8a3..83452088727d 100644
--- a/tools/perf/Documentation/perf-sched.txt
+++ b/tools/perf/Documentation/perf-sched.txt
@@ -99,6 +99,13 @@ OPTIONS for 'perf sched timehist'
99--kallsyms=<file>:: 99--kallsyms=<file>::
100 kallsyms pathname 100 kallsyms pathname
101 101
102-g::
103--no-call-graph::
104 Do not display call chains if present.
105
106--max-stack::
107 Maximum number of functions to display in backtrace, default 5.
108
102-s:: 109-s::
103--summary:: 110--summary::
104 Show only a summary of scheduling by thread with min, max, and average 111 Show only a summary of scheduling by thread with min, max, and average
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 8fb7bcc2cb76..1f8731640809 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -14,6 +14,7 @@
14#include "util/thread_map.h" 14#include "util/thread_map.h"
15#include "util/color.h" 15#include "util/color.h"
16#include "util/stat.h" 16#include "util/stat.h"
17#include "util/callchain.h"
17 18
18#include <subcmd/parse-options.h> 19#include <subcmd/parse-options.h>
19#include "util/trace-event.h" 20#include "util/trace-event.h"
@@ -198,6 +199,8 @@ struct perf_sched {
198 /* options for timehist command */ 199 /* options for timehist command */
199 bool summary; 200 bool summary;
200 bool summary_only; 201 bool summary_only;
202 bool show_callchain;
203 unsigned int max_stack;
201 bool show_wakeups; 204 bool show_wakeups;
202 u64 skipped_samples; 205 u64 skipped_samples;
203}; 206};
@@ -1810,6 +1813,7 @@ static void timehist_header(void)
1810 1813
1811static void timehist_print_sample(struct perf_sched *sched, 1814static void timehist_print_sample(struct perf_sched *sched,
1812 struct perf_sample *sample, 1815 struct perf_sample *sample,
1816 struct addr_location *al,
1813 struct thread *thread) 1817 struct thread *thread)
1814{ 1818{
1815 struct thread_runtime *tr = thread__priv(thread); 1819 struct thread_runtime *tr = thread__priv(thread);
@@ -1827,6 +1831,18 @@ static void timehist_print_sample(struct perf_sched *sched,
1827 if (sched->show_wakeups) 1831 if (sched->show_wakeups)
1828 printf(" %-*s", comm_width, ""); 1832 printf(" %-*s", comm_width, "");
1829 1833
1834 if (thread->tid == 0)
1835 goto out;
1836
1837 if (sched->show_callchain)
1838 printf(" ");
1839
1840 sample__fprintf_sym(sample, al, 0,
1841 EVSEL__PRINT_SYM | EVSEL__PRINT_ONELINE |
1842 EVSEL__PRINT_CALLCHAIN_ARROW,
1843 &callchain_cursor, stdout);
1844
1845out:
1830 printf("\n"); 1846 printf("\n");
1831} 1847}
1832 1848
@@ -1878,9 +1894,14 @@ static void timehist_update_runtime_stats(struct thread_runtime *r,
1878 r->total_run_time += r->dt_run; 1894 r->total_run_time += r->dt_run;
1879} 1895}
1880 1896
1881static bool is_idle_sample(struct perf_sample *sample, 1897static bool is_idle_sample(struct perf_sched *sched,
1882 struct perf_evsel *evsel) 1898 struct perf_sample *sample,
1899 struct perf_evsel *evsel,
1900 struct machine *machine)
1883{ 1901{
1902 struct thread *thread;
1903 struct callchain_cursor *cursor = &callchain_cursor;
1904
1884 /* pid 0 == swapper == idle task */ 1905 /* pid 0 == swapper == idle task */
1885 if (sample->pid == 0) 1906 if (sample->pid == 0)
1886 return true; 1907 return true;
@@ -1889,6 +1910,25 @@ static bool is_idle_sample(struct perf_sample *sample,
1889 if (perf_evsel__intval(evsel, sample, "prev_pid") == 0) 1910 if (perf_evsel__intval(evsel, sample, "prev_pid") == 0)
1890 return true; 1911 return true;
1891 } 1912 }
1913
1914 /* want main thread for process - has maps */
1915 thread = machine__findnew_thread(machine, sample->pid, sample->pid);
1916 if (thread == NULL) {
1917 pr_debug("Failed to get thread for pid %d.\n", sample->pid);
1918 return false;
1919 }
1920
1921 if (!symbol_conf.use_callchain || sample->callchain == NULL)
1922 return false;
1923
1924 if (thread__resolve_callchain(thread, cursor, evsel, sample,
1925 NULL, NULL, sched->max_stack) != 0) {
1926 if (verbose)
1927 error("Failed to resolve callchain. Skipping\n");
1928
1929 return false;
1930 }
1931 callchain_cursor_commit(cursor);
1892 return false; 1932 return false;
1893} 1933}
1894 1934
@@ -1999,13 +2039,14 @@ static struct thread_runtime *thread__get_runtime(struct thread *thread)
1999 return tr; 2039 return tr;
2000} 2040}
2001 2041
2002static struct thread *timehist_get_thread(struct perf_sample *sample, 2042static struct thread *timehist_get_thread(struct perf_sched *sched,
2043 struct perf_sample *sample,
2003 struct machine *machine, 2044 struct machine *machine,
2004 struct perf_evsel *evsel) 2045 struct perf_evsel *evsel)
2005{ 2046{
2006 struct thread *thread; 2047 struct thread *thread;
2007 2048
2008 if (is_idle_sample(sample, evsel)) { 2049 if (is_idle_sample(sched, sample, evsel, machine)) {
2009 thread = get_idle_thread(sample->cpu); 2050 thread = get_idle_thread(sample->cpu);
2010 if (thread == NULL) 2051 if (thread == NULL)
2011 pr_err("Failed to get idle thread for cpu %d.\n", sample->cpu); 2052 pr_err("Failed to get idle thread for cpu %d.\n", sample->cpu);
@@ -2115,7 +2156,7 @@ static int timehist_sched_change_event(struct perf_tool *tool,
2115 goto out; 2156 goto out;
2116 } 2157 }
2117 2158
2118 thread = timehist_get_thread(sample, machine, evsel); 2159 thread = timehist_get_thread(sched, sample, machine, evsel);
2119 if (thread == NULL) { 2160 if (thread == NULL) {
2120 rc = -1; 2161 rc = -1;
2121 goto out; 2162 goto out;
@@ -2134,7 +2175,7 @@ static int timehist_sched_change_event(struct perf_tool *tool,
2134 2175
2135 timehist_update_runtime_stats(tr, sample->time, tprev); 2176 timehist_update_runtime_stats(tr, sample->time, tprev);
2136 if (!sched->summary_only) 2177 if (!sched->summary_only)
2137 timehist_print_sample(sched, sample, thread); 2178 timehist_print_sample(sched, sample, &al, thread);
2138 2179
2139out: 2180out:
2140 if (tr) { 2181 if (tr) {
@@ -2327,6 +2368,30 @@ static int perf_timehist__process_sample(struct perf_tool *tool,
2327 return err; 2368 return err;
2328} 2369}
2329 2370
2371static int timehist_check_attr(struct perf_sched *sched,
2372 struct perf_evlist *evlist)
2373{
2374 struct perf_evsel *evsel;
2375 struct evsel_runtime *er;
2376
2377 list_for_each_entry(evsel, &evlist->entries, node) {
2378 er = perf_evsel__get_runtime(evsel);
2379 if (er == NULL) {
2380 pr_err("Failed to allocate memory for evsel runtime data\n");
2381 return -1;
2382 }
2383
2384 if (sched->show_callchain &&
2385 !(evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN)) {
2386 pr_info("Samples do not have callchains.\n");
2387 sched->show_callchain = 0;
2388 symbol_conf.use_callchain = 0;
2389 }
2390 }
2391
2392 return 0;
2393}
2394
2330static int perf_sched__timehist(struct perf_sched *sched) 2395static int perf_sched__timehist(struct perf_sched *sched)
2331{ 2396{
2332 const struct perf_evsel_str_handler handlers[] = { 2397 const struct perf_evsel_str_handler handlers[] = {
@@ -2359,6 +2424,8 @@ static int perf_sched__timehist(struct perf_sched *sched)
2359 sched->tool.ordered_events = true; 2424 sched->tool.ordered_events = true;
2360 sched->tool.ordering_requires_timestamps = true; 2425 sched->tool.ordering_requires_timestamps = true;
2361 2426
2427 symbol_conf.use_callchain = sched->show_callchain;
2428
2362 session = perf_session__new(&file, false, &sched->tool); 2429 session = perf_session__new(&file, false, &sched->tool);
2363 if (session == NULL) 2430 if (session == NULL)
2364 return -ENOMEM; 2431 return -ENOMEM;
@@ -2367,6 +2434,9 @@ static int perf_sched__timehist(struct perf_sched *sched)
2367 2434
2368 symbol__init(&session->header.env); 2435 symbol__init(&session->header.env);
2369 2436
2437 if (timehist_check_attr(sched, evlist) != 0)
2438 goto out;
2439
2370 setup_pager(); 2440 setup_pager();
2371 2441
2372 /* setup per-evsel handlers */ 2442 /* setup per-evsel handlers */
@@ -2714,6 +2784,8 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
2714 .next_shortname1 = 'A', 2784 .next_shortname1 = 'A',
2715 .next_shortname2 = '0', 2785 .next_shortname2 = '0',
2716 .skip_merge = 0, 2786 .skip_merge = 0,
2787 .show_callchain = 1,
2788 .max_stack = 5,
2717 }; 2789 };
2718 const struct option sched_options[] = { 2790 const struct option sched_options[] = {
2719 OPT_STRING('i', "input", &input_name, "file", 2791 OPT_STRING('i', "input", &input_name, "file",
@@ -2759,6 +2831,10 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
2759 "file", "vmlinux pathname"), 2831 "file", "vmlinux pathname"),
2760 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, 2832 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
2761 "file", "kallsyms pathname"), 2833 "file", "kallsyms pathname"),
2834 OPT_BOOLEAN('g', "call-graph", &sched.show_callchain,
2835 "Display call chains if present (default on)"),
2836 OPT_UINTEGER(0, "max-stack", &sched.max_stack,
2837 "Maximum number of functions to display backtrace."),
2762 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 2838 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
2763 "Look for files with symbols relative to this directory"), 2839 "Look for files with symbols relative to this directory"),
2764 OPT_BOOLEAN('s', "summary", &sched.summary_only, 2840 OPT_BOOLEAN('s', "summary", &sched.summary_only,