aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-trace.c
diff options
context:
space:
mode:
authorDavid Ahern <dsahern@gmail.com>2013-10-08 23:26:53 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2013-10-14 09:28:50 -0400
commitbf2575c121ca11247ef07fd02b43f7430834f7b1 (patch)
tree73f45129f7579714c2d4abfc69f322b0deec4e34 /tools/perf/builtin-trace.c
parent813335b8b27d9ceeb67a073f501ada8b8dde37a7 (diff)
perf trace: Add summary option to dump syscall statistics
When enabled dumps a summary of all syscalls by task with the usual statistics -- min, max, average and relative stddev. For example, make - 26341 : 3344 [ 17.4% ] 0.000 ms read : 52 0.000 4.802 0.644 30.08 write : 20 0.004 0.036 0.010 21.72 open : 24 0.003 0.046 0.014 23.68 close : 64 0.002 0.055 0.008 22.53 stat : 2714 0.002 0.222 0.004 4.47 fstat : 18 0.001 0.041 0.006 46.26 mmap : 30 0.003 0.009 0.006 5.71 mprotect : 8 0.006 0.039 0.016 32.16 munmap : 12 0.007 0.077 0.020 38.25 brk : 48 0.002 0.014 0.004 10.18 rt_sigaction : 18 0.002 0.002 0.002 2.11 rt_sigprocmask : 60 0.002 0.128 0.010 32.88 access : 2 0.006 0.006 0.006 0.00 pipe : 12 0.004 0.048 0.013 35.98 vfork : 34 0.448 0.980 0.692 3.04 execve : 20 0.000 0.387 0.046 56.66 wait4 : 34 0.017 9923.287 593.221 68.45 fcntl : 8 0.001 0.041 0.013 48.79 getdents : 48 0.002 0.079 0.013 19.62 getcwd : 2 0.005 0.005 0.005 0.00 chdir : 2 0.070 0.070 0.070 0.00 getrlimit : 2 0.045 0.045 0.045 0.00 arch_prctl : 2 0.002 0.002 0.002 0.00 setrlimit : 2 0.002 0.002 0.002 0.00 openat : 94 0.003 0.005 0.003 2.11 Signed-off-by: David Ahern <dsahern@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Namhyung Kim <namhyung.kim@lge.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/r/1381289214-24885-3-git-send-email-dsahern@gmail.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/builtin-trace.c')
-rw-r--r--tools/perf/builtin-trace.c110
1 files changed, 98 insertions, 12 deletions
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 5496546b7c5c..d0f91fe755a3 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -10,6 +10,7 @@
10#include "util/strlist.h" 10#include "util/strlist.h"
11#include "util/intlist.h" 11#include "util/intlist.h"
12#include "util/thread_map.h" 12#include "util/thread_map.h"
13#include "util/stat.h"
13 14
14#include <libaudit.h> 15#include <libaudit.h>
15#include <stdlib.h> 16#include <stdlib.h>
@@ -909,6 +910,8 @@ struct thread_trace {
909 int max; 910 int max;
910 char **table; 911 char **table;
911 } paths; 912 } paths;
913
914 struct intlist *syscall_stats;
912}; 915};
913 916
914static struct thread_trace *thread_trace__new(void) 917static struct thread_trace *thread_trace__new(void)
@@ -918,6 +921,8 @@ static struct thread_trace *thread_trace__new(void)
918 if (ttrace) 921 if (ttrace)
919 ttrace->paths.max = -1; 922 ttrace->paths.max = -1;
920 923
924 ttrace->syscall_stats = intlist__new(NULL);
925
921 return ttrace; 926 return ttrace;
922} 927}
923 928
@@ -964,6 +969,7 @@ struct trace {
964 struct intlist *pid_list; 969 struct intlist *pid_list;
965 bool sched; 970 bool sched;
966 bool multiple_threads; 971 bool multiple_threads;
972 bool summary;
967 bool show_comm; 973 bool show_comm;
968 double duration_filter; 974 double duration_filter;
969 double runtime_ms; 975 double runtime_ms;
@@ -1291,10 +1297,8 @@ typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
1291 struct perf_sample *sample); 1297 struct perf_sample *sample);
1292 1298
1293static struct syscall *trace__syscall_info(struct trace *trace, 1299static struct syscall *trace__syscall_info(struct trace *trace,
1294 struct perf_evsel *evsel, 1300 struct perf_evsel *evsel, int id)
1295 struct perf_sample *sample)
1296{ 1301{
1297 int id = perf_evsel__intval(evsel, sample, "id");
1298 1302
1299 if (id < 0) { 1303 if (id < 0) {
1300 1304
@@ -1335,6 +1339,32 @@ out_cant_read:
1335 return NULL; 1339 return NULL;
1336} 1340}
1337 1341
1342static void thread__update_stats(struct thread_trace *ttrace,
1343 int id, struct perf_sample *sample)
1344{
1345 struct int_node *inode;
1346 struct stats *stats;
1347 u64 duration = 0;
1348
1349 inode = intlist__findnew(ttrace->syscall_stats, id);
1350 if (inode == NULL)
1351 return;
1352
1353 stats = inode->priv;
1354 if (stats == NULL) {
1355 stats = malloc(sizeof(struct stats));
1356 if (stats == NULL)
1357 return;
1358 init_stats(stats);
1359 inode->priv = stats;
1360 }
1361
1362 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1363 duration = sample->time - ttrace->entry_time;
1364
1365 update_stats(stats, duration);
1366}
1367
1338static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, 1368static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1339 struct perf_sample *sample) 1369 struct perf_sample *sample)
1340{ 1370{
@@ -1342,7 +1372,8 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1342 void *args; 1372 void *args;
1343 size_t printed = 0; 1373 size_t printed = 0;
1344 struct thread *thread; 1374 struct thread *thread;
1345 struct syscall *sc = trace__syscall_info(trace, evsel, sample); 1375 int id = perf_evsel__intval(evsel, sample, "id");
1376 struct syscall *sc = trace__syscall_info(trace, evsel, id);
1346 struct thread_trace *ttrace; 1377 struct thread_trace *ttrace;
1347 1378
1348 if (sc == NULL) 1379 if (sc == NULL)
@@ -1394,7 +1425,8 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1394 int ret; 1425 int ret;
1395 u64 duration = 0; 1426 u64 duration = 0;
1396 struct thread *thread; 1427 struct thread *thread;
1397 struct syscall *sc = trace__syscall_info(trace, evsel, sample); 1428 int id = perf_evsel__intval(evsel, sample, "id");
1429 struct syscall *sc = trace__syscall_info(trace, evsel, id);
1398 struct thread_trace *ttrace; 1430 struct thread_trace *ttrace;
1399 1431
1400 if (sc == NULL) 1432 if (sc == NULL)
@@ -1408,6 +1440,9 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1408 if (ttrace == NULL) 1440 if (ttrace == NULL)
1409 return -1; 1441 return -1;
1410 1442
1443 if (trace->summary)
1444 thread__update_stats(ttrace, id, sample);
1445
1411 ret = perf_evsel__intval(evsel, sample, "ret"); 1446 ret = perf_evsel__intval(evsel, sample, "ret");
1412 1447
1413 ttrace = thread->priv; 1448 ttrace = thread->priv;
@@ -1574,6 +1609,8 @@ static int trace__record(int argc, const char **argv)
1574 return cmd_record(i, rec_argv, NULL); 1609 return cmd_record(i, rec_argv, NULL);
1575} 1610}
1576 1611
1612static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
1613
1577static int trace__run(struct trace *trace, int argc, const char **argv) 1614static int trace__run(struct trace *trace, int argc, const char **argv)
1578{ 1615{
1579 struct perf_evlist *evlist = perf_evlist__new(); 1616 struct perf_evlist *evlist = perf_evlist__new();
@@ -1703,6 +1740,9 @@ again:
1703 goto again; 1740 goto again;
1704 1741
1705out_unmap_evlist: 1742out_unmap_evlist:
1743 if (!err && trace->summary)
1744 trace__fprintf_thread_summary(trace, trace->output);
1745
1706 perf_evlist__munmap(evlist); 1746 perf_evlist__munmap(evlist);
1707out_close_evlist: 1747out_close_evlist:
1708 perf_evlist__close(evlist); 1748 perf_evlist__close(evlist);
@@ -1798,6 +1838,9 @@ static int trace__replay(struct trace *trace)
1798 if (err) 1838 if (err)
1799 pr_err("Failed to process events, error %d", err); 1839 pr_err("Failed to process events, error %d", err);
1800 1840
1841 else if (trace->summary)
1842 trace__fprintf_thread_summary(trace, trace->output);
1843
1801out: 1844out:
1802 perf_session__delete(session); 1845 perf_session__delete(session);
1803 1846
@@ -1808,10 +1851,53 @@ static size_t trace__fprintf_threads_header(FILE *fp)
1808{ 1851{
1809 size_t printed; 1852 size_t printed;
1810 1853
1811 printed = fprintf(fp, "\n _____________________________________________________________________\n"); 1854 printed = fprintf(fp, "\n _____________________________________________________________________________\n");
1812 printed += fprintf(fp," __) Summary of events (__\n\n"); 1855 printed += fprintf(fp, " __) Summary of events (__\n\n");
1813 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n"); 1856 printed += fprintf(fp, " [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1814 printed += fprintf(fp," _____________________________________________________________________\n\n"); 1857 printed += fprintf(fp, " syscall count min max avg stddev\n");
1858 printed += fprintf(fp, " msec msec msec %%\n");
1859 printed += fprintf(fp, " _____________________________________________________________________________\n\n");
1860
1861 return printed;
1862}
1863
1864static size_t thread__dump_stats(struct thread_trace *ttrace,
1865 struct trace *trace, FILE *fp)
1866{
1867 struct stats *stats;
1868 size_t printed = 0;
1869 struct syscall *sc;
1870 struct int_node *inode = intlist__first(ttrace->syscall_stats);
1871
1872 if (inode == NULL)
1873 return 0;
1874
1875 printed += fprintf(fp, "\n");
1876
1877 /* each int_node is a syscall */
1878 while (inode) {
1879 stats = inode->priv;
1880 if (stats) {
1881 double min = (double)(stats->min) / NSEC_PER_MSEC;
1882 double max = (double)(stats->max) / NSEC_PER_MSEC;
1883 double avg = avg_stats(stats);
1884 double pct;
1885 u64 n = (u64) stats->n;
1886
1887 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
1888 avg /= NSEC_PER_MSEC;
1889
1890 sc = &trace->syscalls.table[inode->i];
1891 printed += fprintf(fp, "%24s %14s : ", "", sc->name);
1892 printed += fprintf(fp, "%5" PRIu64 " %8.3f %8.3f",
1893 n, min, max);
1894 printed += fprintf(fp, " %8.3f %6.2f\n", avg, pct);
1895 }
1896
1897 inode = intlist__next(inode);
1898 }
1899
1900 printed += fprintf(fp, "\n\n");
1815 1901
1816 return printed; 1902 return printed;
1817} 1903}
@@ -1850,6 +1936,7 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv)
1850 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events); 1936 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
1851 printed += color_fprintf(fp, color, "%5.1f%%", ratio); 1937 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1852 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms); 1938 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1939 printed += thread__dump_stats(ttrace, trace, fp);
1853 1940
1854 data->printed += printed; 1941 data->printed += printed;
1855 1942
@@ -1953,6 +2040,8 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1953 OPT_INCR('v', "verbose", &verbose, "be more verbose"), 2040 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
1954 OPT_BOOLEAN('T', "time", &trace.full_time, 2041 OPT_BOOLEAN('T', "time", &trace.full_time,
1955 "Show full timestamp, not time relative to first start"), 2042 "Show full timestamp, not time relative to first start"),
2043 OPT_BOOLEAN(0, "summary", &trace.summary,
2044 "Show syscall summary with statistics"),
1956 OPT_END() 2045 OPT_END()
1957 }; 2046 };
1958 int err; 2047 int err;
@@ -2008,9 +2097,6 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2008 else 2097 else
2009 err = trace__run(&trace, argc, argv); 2098 err = trace__run(&trace, argc, argv);
2010 2099
2011 if (trace.sched && !err)
2012 trace__fprintf_thread_summary(&trace, trace.output);
2013
2014out_close: 2100out_close:
2015 if (output_name != NULL) 2101 if (output_name != NULL)
2016 fclose(trace.output); 2102 fclose(trace.output);