aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-trace.c
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2013-09-27 17:06:19 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2013-10-16 10:18:24 -0400
commitc522739d72a341a3e74a369ce6298b9412813d3f (patch)
tree0e84cb0276157f06fbb126f81aabe9646a57f8af /tools/perf/builtin-trace.c
parent97119f37bbebbab852899bd37ed52b80396728f9 (diff)
perf trace: Use vfs_getname hook if available
Initially it tries to find a probe:vfs_getname that should be setup with: perf probe 'vfs_getname=getname_flags:65 pathname=result->name:string' or with slight changes to cope with code flux in the getname_flags code. In the future, if a "vfs:getname" tracepoint becomes available, then it will be preferred. This is not strictly required and more expensive method of reading the /proc/pid/fd/ symlink will be used when the fd->path array entry is not populated by a previous vfs_getname + open syscall ret sequence. As with any other 'perf probe' probe the setup must be done just once and the probe will be left inactive, waiting for users, be it 'perf trace' of any other tool. Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/n/tip-ujg8se8glq5izmu8cdkq15po@git.kernel.org 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.c83
1 files changed, 71 insertions, 12 deletions
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 763bef45afad..86d2b1f2399c 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -951,7 +951,10 @@ fail:
951 951
952struct trace { 952struct trace {
953 struct perf_tool tool; 953 struct perf_tool tool;
954 int audit_machine; 954 struct {
955 int machine;
956 int open_id;
957 } audit;
955 struct { 958 struct {
956 int max; 959 int max;
957 struct syscall *table; 960 struct syscall *table;
@@ -965,14 +968,19 @@ struct trace {
965 struct strlist *ev_qualifier; 968 struct strlist *ev_qualifier;
966 bool not_ev_qualifier; 969 bool not_ev_qualifier;
967 bool live; 970 bool live;
971 const char *last_vfs_getname;
968 struct intlist *tid_list; 972 struct intlist *tid_list;
969 struct intlist *pid_list; 973 struct intlist *pid_list;
970 bool sched; 974 bool sched;
971 bool multiple_threads; 975 bool multiple_threads;
972 bool summary; 976 bool summary;
973 bool show_comm; 977 bool show_comm;
978 bool show_tool_stats;
974 double duration_filter; 979 double duration_filter;
975 double runtime_ms; 980 double runtime_ms;
981 struct {
982 u64 vfs_getname, proc_getname;
983 } stats;
976}; 984};
977 985
978static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname) 986static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
@@ -1027,7 +1035,8 @@ static int thread__read_fd_path(struct thread *thread, int fd)
1027 return trace__set_fd_pathname(thread, fd, pathname); 1035 return trace__set_fd_pathname(thread, fd, pathname);
1028} 1036}
1029 1037
1030static const char *thread__fd_path(struct thread *thread, int fd, bool live) 1038static const char *thread__fd_path(struct thread *thread, int fd,
1039 struct trace *trace)
1031{ 1040{
1032 struct thread_trace *ttrace = thread->priv; 1041 struct thread_trace *ttrace = thread->priv;
1033 1042
@@ -1037,9 +1046,13 @@ static const char *thread__fd_path(struct thread *thread, int fd, bool live)
1037 if (fd < 0) 1046 if (fd < 0)
1038 return NULL; 1047 return NULL;
1039 1048
1040 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL) && 1049 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL))
1041 (!live || thread__read_fd_path(thread, fd))) 1050 if (!trace->live)
1042 return NULL; 1051 return NULL;
1052 ++trace->stats.proc_getname;
1053 if (thread__read_fd_path(thread, fd)) {
1054 return NULL;
1055 }
1043 1056
1044 return ttrace->paths.table[fd]; 1057 return ttrace->paths.table[fd];
1045} 1058}
@@ -1049,7 +1062,7 @@ static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1049{ 1062{
1050 int fd = arg->val; 1063 int fd = arg->val;
1051 size_t printed = scnprintf(bf, size, "%d", fd); 1064 size_t printed = scnprintf(bf, size, "%d", fd);
1052 const char *path = thread__fd_path(arg->thread, fd, arg->trace->live); 1065 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
1053 1066
1054 if (path) 1067 if (path)
1055 printed += scnprintf(bf + printed, size - printed, "<%s>", path); 1068 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
@@ -1186,7 +1199,7 @@ static int trace__read_syscall_info(struct trace *trace, int id)
1186{ 1199{
1187 char tp_name[128]; 1200 char tp_name[128];
1188 struct syscall *sc; 1201 struct syscall *sc;
1189 const char *name = audit_syscall_to_name(id, trace->audit_machine); 1202 const char *name = audit_syscall_to_name(id, trace->audit.machine);
1190 1203
1191 if (name == NULL) 1204 if (name == NULL)
1192 return -1; 1205 return -1;
@@ -1450,6 +1463,12 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1450 1463
1451 ret = perf_evsel__intval(evsel, sample, "ret"); 1464 ret = perf_evsel__intval(evsel, sample, "ret");
1452 1465
1466 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1467 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1468 trace->last_vfs_getname = NULL;
1469 ++trace->stats.vfs_getname;
1470 }
1471
1453 ttrace = thread->priv; 1472 ttrace = thread->priv;
1454 1473
1455 ttrace->exit_time = sample->time; 1474 ttrace->exit_time = sample->time;
@@ -1494,6 +1513,13 @@ out:
1494 return 0; 1513 return 0;
1495} 1514}
1496 1515
1516static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
1517 struct perf_sample *sample)
1518{
1519 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1520 return 0;
1521}
1522
1497static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel, 1523static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1498 struct perf_sample *sample) 1524 struct perf_sample *sample)
1499{ 1525{
@@ -1616,6 +1642,22 @@ static int trace__record(int argc, const char **argv)
1616 1642
1617static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp); 1643static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
1618 1644
1645static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
1646{
1647 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname",
1648 evlist->nr_entries);
1649 if (evsel == NULL)
1650 return;
1651
1652 if (perf_evsel__field(evsel, "pathname") == NULL) {
1653 perf_evsel__delete(evsel);
1654 return;
1655 }
1656
1657 evsel->handler.func = trace__vfs_getname;
1658 perf_evlist__add(evlist, evsel);
1659}
1660
1619static int trace__run(struct trace *trace, int argc, const char **argv) 1661static int trace__run(struct trace *trace, int argc, const char **argv)
1620{ 1662{
1621 struct perf_evlist *evlist = perf_evlist__new(); 1663 struct perf_evlist *evlist = perf_evlist__new();
@@ -1635,6 +1677,8 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
1635 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) 1677 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit))
1636 goto out_error_tp; 1678 goto out_error_tp;
1637 1679
1680 perf_evlist__add_vfs_getname(evlist);
1681
1638 if (trace->sched && 1682 if (trace->sched &&
1639 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime", 1683 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1640 trace__sched_stat_runtime)) 1684 trace__sched_stat_runtime))
@@ -1741,12 +1785,22 @@ again:
1741 1785
1742 if (done) 1786 if (done)
1743 perf_evlist__disable(evlist); 1787 perf_evlist__disable(evlist);
1744 1788 else
1745 goto again; 1789 goto again;
1746 1790
1747out_unmap_evlist: 1791out_unmap_evlist:
1748 if (!err && trace->summary) 1792 if (!err) {
1749 trace__fprintf_thread_summary(trace, trace->output); 1793 if (trace->summary)
1794 trace__fprintf_thread_summary(trace, trace->output);
1795
1796 if (trace->show_tool_stats) {
1797 fprintf(trace->output, "Stats:\n "
1798 " vfs_getname : %" PRIu64 "\n"
1799 " proc_getname: %" PRIu64 "\n",
1800 trace->stats.vfs_getname,
1801 trace->stats.proc_getname);
1802 }
1803 }
1750 1804
1751 perf_evlist__munmap(evlist); 1805 perf_evlist__munmap(evlist);
1752out_close_evlist: 1806out_close_evlist:
@@ -1788,6 +1842,7 @@ static int trace__replay(struct trace *trace)
1788 const struct perf_evsel_str_handler handlers[] = { 1842 const struct perf_evsel_str_handler handlers[] = {
1789 { "raw_syscalls:sys_enter", trace__sys_enter, }, 1843 { "raw_syscalls:sys_enter", trace__sys_enter, },
1790 { "raw_syscalls:sys_exit", trace__sys_exit, }, 1844 { "raw_syscalls:sys_exit", trace__sys_exit, },
1845 { "probe:vfs_getname", trace__vfs_getname, },
1791 }; 1846 };
1792 1847
1793 struct perf_session *session; 1848 struct perf_session *session;
@@ -1997,7 +2052,10 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1997 NULL 2052 NULL
1998 }; 2053 };
1999 struct trace trace = { 2054 struct trace trace = {
2000 .audit_machine = audit_detect_machine(), 2055 .audit = {
2056 .machine = audit_detect_machine(),
2057 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2058 },
2001 .syscalls = { 2059 .syscalls = {
2002 . max = -1, 2060 . max = -1,
2003 }, 2061 },
@@ -2019,6 +2077,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2019 const struct option trace_options[] = { 2077 const struct option trace_options[] = {
2020 OPT_BOOLEAN(0, "comm", &trace.show_comm, 2078 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2021 "show the thread COMM next to its id"), 2079 "show the thread COMM next to its id"),
2080 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
2022 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", 2081 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
2023 "list of events to trace"), 2082 "list of events to trace"),
2024 OPT_STRING('o', "output", &output_name, "file", "output file name"), 2083 OPT_STRING('o', "output", &output_name, "file", "output file name"),