aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Ahern <dsahern@gmail.com>2016-11-16 01:06:30 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2016-11-23 08:44:08 -0500
commit52df138caaa8daaaf4e0dc64428ef06f303a8dbf (patch)
treed588d597bd8fe1c945c68f2b4b430cb15148dbf8
parent49394a2a24c78ce034fe0e732b1b54922c23fd92 (diff)
perf sched timehist: Add summary options
The -s/--summary option is to show process runtime statistics. And the -S/--with-summary option is to show the stats with the normal output. $ perf sched timehist -s Runtime summary comm parent sched-in run-time min-run avg-run max-run stddev (count) (msec) (msec) (msec) (msec) % --------------------------------------------------------------------------------------------------------- ksoftirqd/0[3] 2 2 0.011 0.004 0.005 0.006 14.87 rcu_preempt[7] 2 11 0.071 0.002 0.006 0.017 20.23 watchdog/0[11] 2 1 0.002 0.002 0.002 0.002 0.00 watchdog/1[12] 2 1 0.004 0.004 0.004 0.004 0.00 ... Terminated tasks: sleep[7220] 7219 3 0.770 0.087 0.256 0.576 62.28 Idle stats: CPU 0 idle for 2352.006 msec CPU 1 idle for 2764.497 msec CPU 2 idle for 2998.229 msec CPU 3 idle for 2967.800 msec Total number of unique tasks: 52 Total number of context switches: 2532 Total run time (msec): 218.036 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-5-namhyung@kernel.org [ Add documentation from last commit, so that docs comes with the cset that introduces the feature ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/builtin-sched.c166
1 files changed, 160 insertions, 6 deletions
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index c0ac0c9557e8..1e7d81ad5ec6 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -194,6 +194,11 @@ struct perf_sched {
194 bool force; 194 bool force;
195 bool skip_merge; 195 bool skip_merge;
196 struct perf_sched_map map; 196 struct perf_sched_map map;
197
198 /* options for timehist command */
199 bool summary;
200 bool summary_only;
201 u64 skipped_samples;
197}; 202};
198 203
199/* per thread run time data */ 204/* per thread run time data */
@@ -2010,12 +2015,15 @@ static struct thread *timehist_get_thread(struct perf_sample *sample,
2010 return thread; 2015 return thread;
2011} 2016}
2012 2017
2013static bool timehist_skip_sample(struct thread *thread) 2018static bool timehist_skip_sample(struct perf_sched *sched,
2019 struct thread *thread)
2014{ 2020{
2015 bool rc = false; 2021 bool rc = false;
2016 2022
2017 if (thread__is_filtered(thread)) 2023 if (thread__is_filtered(thread)) {
2018 rc = true; 2024 rc = true;
2025 sched->skipped_samples++;
2026 }
2019 2027
2020 return rc; 2028 return rc;
2021} 2029}
@@ -2045,7 +2053,7 @@ static int timehist_sched_wakeup_event(struct perf_tool *tool __maybe_unused,
2045 return 0; 2053 return 0;
2046} 2054}
2047 2055
2048static int timehist_sched_change_event(struct perf_tool *tool __maybe_unused, 2056static int timehist_sched_change_event(struct perf_tool *tool,
2049 union perf_event *event, 2057 union perf_event *event,
2050 struct perf_evsel *evsel, 2058 struct perf_evsel *evsel,
2051 struct perf_sample *sample, 2059 struct perf_sample *sample,
@@ -2056,6 +2064,7 @@ static int timehist_sched_change_event(struct perf_tool *tool __maybe_unused,
2056 struct thread_runtime *tr = NULL; 2064 struct thread_runtime *tr = NULL;
2057 u64 tprev; 2065 u64 tprev;
2058 int rc = 0; 2066 int rc = 0;
2067 struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
2059 2068
2060 if (machine__resolve(machine, &al, sample) < 0) { 2069 if (machine__resolve(machine, &al, sample) < 0) {
2061 pr_err("problem processing %d event. skipping it\n", 2070 pr_err("problem processing %d event. skipping it\n",
@@ -2070,7 +2079,7 @@ static int timehist_sched_change_event(struct perf_tool *tool __maybe_unused,
2070 goto out; 2079 goto out;
2071 } 2080 }
2072 2081
2073 if (timehist_skip_sample(thread)) 2082 if (timehist_skip_sample(sched, thread))
2074 goto out; 2083 goto out;
2075 2084
2076 tr = thread__get_runtime(thread); 2085 tr = thread__get_runtime(thread);
@@ -2082,7 +2091,8 @@ static int timehist_sched_change_event(struct perf_tool *tool __maybe_unused,
2082 tprev = perf_evsel__get_time(evsel, sample->cpu); 2091 tprev = perf_evsel__get_time(evsel, sample->cpu);
2083 2092
2084 timehist_update_runtime_stats(tr, sample->time, tprev); 2093 timehist_update_runtime_stats(tr, sample->time, tprev);
2085 timehist_print_sample(sample, thread); 2094 if (!sched->summary_only)
2095 timehist_print_sample(sample, thread);
2086 2096
2087out: 2097out:
2088 if (tr) { 2098 if (tr) {
@@ -2122,6 +2132,131 @@ static int process_lost(struct perf_tool *tool __maybe_unused,
2122} 2132}
2123 2133
2124 2134
2135static void print_thread_runtime(struct thread *t,
2136 struct thread_runtime *r)
2137{
2138 double mean = avg_stats(&r->run_stats);
2139 float stddev;
2140
2141 printf("%*s %5d %9" PRIu64 " ",
2142 comm_width, timehist_get_commstr(t), t->ppid,
2143 (u64) r->run_stats.n);
2144
2145 print_sched_time(r->total_run_time, 8);
2146 stddev = rel_stddev_stats(stddev_stats(&r->run_stats), mean);
2147 print_sched_time(r->run_stats.min, 6);
2148 printf(" ");
2149 print_sched_time((u64) mean, 6);
2150 printf(" ");
2151 print_sched_time(r->run_stats.max, 6);
2152 printf(" ");
2153 printf("%5.2f", stddev);
2154 printf("\n");
2155}
2156
2157struct total_run_stats {
2158 u64 sched_count;
2159 u64 task_count;
2160 u64 total_run_time;
2161};
2162
2163static int __show_thread_runtime(struct thread *t, void *priv)
2164{
2165 struct total_run_stats *stats = priv;
2166 struct thread_runtime *r;
2167
2168 if (thread__is_filtered(t))
2169 return 0;
2170
2171 r = thread__priv(t);
2172 if (r && r->run_stats.n) {
2173 stats->task_count++;
2174 stats->sched_count += r->run_stats.n;
2175 stats->total_run_time += r->total_run_time;
2176 print_thread_runtime(t, r);
2177 }
2178
2179 return 0;
2180}
2181
2182static int show_thread_runtime(struct thread *t, void *priv)
2183{
2184 if (t->dead)
2185 return 0;
2186
2187 return __show_thread_runtime(t, priv);
2188}
2189
2190static int show_deadthread_runtime(struct thread *t, void *priv)
2191{
2192 if (!t->dead)
2193 return 0;
2194
2195 return __show_thread_runtime(t, priv);
2196}
2197
2198static void timehist_print_summary(struct perf_sched *sched,
2199 struct perf_session *session)
2200{
2201 struct machine *m = &session->machines.host;
2202 struct total_run_stats totals;
2203 u64 task_count;
2204 struct thread *t;
2205 struct thread_runtime *r;
2206 int i;
2207
2208 memset(&totals, 0, sizeof(totals));
2209
2210 if (comm_width < 30)
2211 comm_width = 30;
2212
2213 printf("\nRuntime summary\n");
2214 printf("%*s parent sched-in ", comm_width, "comm");
2215 printf(" run-time min-run avg-run max-run stddev\n");
2216 printf("%*s (count) ", comm_width, "");
2217 printf(" (msec) (msec) (msec) (msec) %%\n");
2218 printf("%.105s\n", graph_dotted_line);
2219
2220 machine__for_each_thread(m, show_thread_runtime, &totals);
2221 task_count = totals.task_count;
2222 if (!task_count)
2223 printf("<no still running tasks>\n");
2224
2225 printf("\nTerminated tasks:\n");
2226 machine__for_each_thread(m, show_deadthread_runtime, &totals);
2227 if (task_count == totals.task_count)
2228 printf("<no terminated tasks>\n");
2229
2230 /* CPU idle stats not tracked when samples were skipped */
2231 if (sched->skipped_samples)
2232 return;
2233
2234 printf("\nIdle stats:\n");
2235 for (i = 0; i <= idle_max_cpu; ++i) {
2236 t = idle_threads[i];
2237 if (!t)
2238 continue;
2239
2240 r = thread__priv(t);
2241 if (r && r->run_stats.n) {
2242 totals.sched_count += r->run_stats.n;
2243 printf(" CPU %2d idle for ", i);
2244 print_sched_time(r->total_run_time, 6);
2245 printf(" msec\n");
2246 } else
2247 printf(" CPU %2d idle entire time window\n", i);
2248 }
2249
2250 printf("\n"
2251 " Total number of unique tasks: %" PRIu64 "\n"
2252 "Total number of context switches: %" PRIu64 "\n"
2253 " Total run time (msec): ",
2254 totals.task_count, totals.sched_count);
2255
2256 print_sched_time(totals.total_run_time, 2);
2257 printf("\n");
2258}
2259
2125typedef int (*sched_handler)(struct perf_tool *tool, 2260typedef int (*sched_handler)(struct perf_tool *tool,
2126 union perf_event *event, 2261 union perf_event *event,
2127 struct perf_evsel *evsel, 2262 struct perf_evsel *evsel,
@@ -2163,6 +2298,7 @@ static int perf_sched__timehist(struct perf_sched *sched)
2163 }; 2298 };
2164 2299
2165 struct perf_session *session; 2300 struct perf_session *session;
2301 struct perf_evlist *evlist;
2166 int err = -1; 2302 int err = -1;
2167 2303
2168 /* 2304 /*
@@ -2185,6 +2321,8 @@ static int perf_sched__timehist(struct perf_sched *sched)
2185 if (session == NULL) 2321 if (session == NULL)
2186 return -ENOMEM; 2322 return -ENOMEM;
2187 2323
2324 evlist = session->evlist;
2325
2188 symbol__init(&session->header.env); 2326 symbol__init(&session->header.env);
2189 2327
2190 setup_pager(); 2328 setup_pager();
@@ -2203,7 +2341,12 @@ static int perf_sched__timehist(struct perf_sched *sched)
2203 if (init_idle_threads(sched->max_cpu)) 2341 if (init_idle_threads(sched->max_cpu))
2204 goto out; 2342 goto out;
2205 2343
2206 timehist_header(); 2344 /* summary_only implies summary option, but don't overwrite summary if set */
2345 if (sched->summary_only)
2346 sched->summary = sched->summary_only;
2347
2348 if (!sched->summary_only)
2349 timehist_header();
2207 2350
2208 err = perf_session__process_events(session); 2351 err = perf_session__process_events(session);
2209 if (err) { 2352 if (err) {
@@ -2211,6 +2354,13 @@ static int perf_sched__timehist(struct perf_sched *sched)
2211 goto out; 2354 goto out;
2212 } 2355 }
2213 2356
2357 sched->nr_events = evlist->stats.nr_events[0];
2358 sched->nr_lost_events = evlist->stats.total_lost;
2359 sched->nr_lost_chunks = evlist->stats.nr_events[PERF_RECORD_LOST];
2360
2361 if (sched->summary)
2362 timehist_print_summary(sched, session);
2363
2214out: 2364out:
2215 free_idle_threads(); 2365 free_idle_threads();
2216 perf_session__delete(session); 2366 perf_session__delete(session);
@@ -2569,6 +2719,10 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
2569 "file", "kallsyms pathname"), 2719 "file", "kallsyms pathname"),
2570 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 2720 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
2571 "Look for files with symbols relative to this directory"), 2721 "Look for files with symbols relative to this directory"),
2722 OPT_BOOLEAN('s', "summary", &sched.summary_only,
2723 "Show only syscall summary with statistics"),
2724 OPT_BOOLEAN('S', "with-summary", &sched.summary,
2725 "Show all syscalls and summary with statistics"),
2572 OPT_PARENT(sched_options) 2726 OPT_PARENT(sched_options)
2573 }; 2727 };
2574 2728