diff options
author | Ingo Molnar <mingo@kernel.org> | 2014-07-05 05:28:13 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-07-05 05:28:13 -0400 |
commit | 432100ba2aacc2146a2b1f26e5b5ae5d6e29972a (patch) | |
tree | de1bd7b51e55c8b61507a56d69e6e333b4c84cd7 | |
parent | 2172c1f5aa58310784f358ca20fdddfcdc2a0d7b (diff) | |
parent | e281a9606d7073c517f2571e83faaff029ddc1cf (diff) |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
New features:
* Add support for pagefault tracing in 'trace', please see multiple examples
in the changeset messages (Stanislav Fomichev).
User visible changes:
* Fallback to syscalls:* when raw_syscalls:* is not available in the perl and
python perf scripts. (Daniel Bristot de Oliveira)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | tools/perf/Documentation/perf-trace.txt | 46 | ||||
-rw-r--r-- | tools/perf/builtin-trace.c | 237 | ||||
-rw-r--r-- | tools/perf/scripts/perl/bin/failed-syscalls-record | 3 | ||||
-rw-r--r-- | tools/perf/scripts/perl/failed-syscalls.pl | 5 | ||||
-rw-r--r-- | tools/perf/scripts/python/bin/failed-syscalls-by-pid-record | 3 | ||||
-rw-r--r-- | tools/perf/scripts/python/bin/sctop-record | 3 | ||||
-rw-r--r-- | tools/perf/scripts/python/bin/syscall-counts-by-pid-record | 3 | ||||
-rw-r--r-- | tools/perf/scripts/python/bin/syscall-counts-record | 3 | ||||
-rw-r--r-- | tools/perf/scripts/python/failed-syscalls-by-pid.py | 5 | ||||
-rw-r--r-- | tools/perf/scripts/python/sctop.py | 5 | ||||
-rw-r--r-- | tools/perf/scripts/python/syscall-counts-by-pid.py | 5 | ||||
-rw-r--r-- | tools/perf/scripts/python/syscall-counts.py | 5 |
12 files changed, 280 insertions, 43 deletions
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt index fae38d9a44a4..02aac831bdd9 100644 --- a/tools/perf/Documentation/perf-trace.txt +++ b/tools/perf/Documentation/perf-trace.txt | |||
@@ -107,6 +107,52 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs. | |||
107 | Show tool stats such as number of times fd->pathname was discovered thru | 107 | Show tool stats such as number of times fd->pathname was discovered thru |
108 | hooking the open syscall return + vfs_getname or via reading /proc/pid/fd, etc. | 108 | hooking the open syscall return + vfs_getname or via reading /proc/pid/fd, etc. |
109 | 109 | ||
110 | -F=[all|min|maj]:: | ||
111 | --pf=[all|min|maj]:: | ||
112 | Trace pagefaults. Optionally, you can specify whether you want minor, | ||
113 | major or all pagefaults. Default value is maj. | ||
114 | |||
115 | --syscalls:: | ||
116 | Trace system calls. This options is enabled by default. | ||
117 | |||
118 | PAGEFAULTS | ||
119 | ---------- | ||
120 | |||
121 | When tracing pagefaults, the format of the trace is as follows: | ||
122 | |||
123 | <min|maj>fault [<ip.symbol>+<ip.offset>] => <addr.dso@addr.offset> (<map type><addr level>). | ||
124 | |||
125 | - min/maj indicates whether fault event is minor or major; | ||
126 | - ip.symbol shows symbol for instruction pointer (the code that generated the | ||
127 | fault); if no debug symbols available, perf trace will print raw IP; | ||
128 | - addr.dso shows DSO for the faulted address; | ||
129 | - map type is either 'd' for non-executable maps or 'x' for executable maps; | ||
130 | - addr level is either 'k' for kernel dso or '.' for user dso. | ||
131 | |||
132 | For symbols resolution you may need to install debugging symbols. | ||
133 | |||
134 | Please be aware that duration is currently always 0 and doesn't reflect actual | ||
135 | time it took for fault to be handled! | ||
136 | |||
137 | When --verbose specified, perf trace tries to print all available information | ||
138 | for both IP and fault address in the form of dso@symbol+offset. | ||
139 | |||
140 | EXAMPLES | ||
141 | -------- | ||
142 | |||
143 | Trace only major pagefaults: | ||
144 | |||
145 | $ perf trace --no-syscalls -F | ||
146 | |||
147 | Trace syscalls, major and minor pagefaults: | ||
148 | |||
149 | $ perf trace -F all | ||
150 | |||
151 | 1416.547 ( 0.000 ms): python/20235 majfault [CRYPTO_push_info_+0x0] => /lib/x86_64-linux-gnu/libcrypto.so.1.0.0@0x61be0 (x.) | ||
152 | |||
153 | As you can see, there was major pagefault in python process, from | ||
154 | CRYPTO_push_info_ routine which faulted somewhere in libcrypto.so. | ||
155 | |||
110 | SEE ALSO | 156 | SEE ALSO |
111 | -------- | 157 | -------- |
112 | linkperf:perf-record[1], linkperf:perf-script[1] | 158 | linkperf:perf-record[1], linkperf:perf-script[1] |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 5549cee61680..dc7a694b61fe 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -1178,6 +1178,9 @@ fail: | |||
1178 | return NULL; | 1178 | return NULL; |
1179 | } | 1179 | } |
1180 | 1180 | ||
1181 | #define TRACE_PFMAJ (1 << 0) | ||
1182 | #define TRACE_PFMIN (1 << 1) | ||
1183 | |||
1181 | struct trace { | 1184 | struct trace { |
1182 | struct perf_tool tool; | 1185 | struct perf_tool tool; |
1183 | struct { | 1186 | struct { |
@@ -1212,6 +1215,8 @@ struct trace { | |||
1212 | bool summary_only; | 1215 | bool summary_only; |
1213 | bool show_comm; | 1216 | bool show_comm; |
1214 | bool show_tool_stats; | 1217 | bool show_tool_stats; |
1218 | bool trace_syscalls; | ||
1219 | int trace_pgfaults; | ||
1215 | }; | 1220 | }; |
1216 | 1221 | ||
1217 | static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname) | 1222 | static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname) |
@@ -1538,6 +1543,7 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size, | |||
1538 | } | 1543 | } |
1539 | 1544 | ||
1540 | typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel, | 1545 | typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel, |
1546 | union perf_event *event, | ||
1541 | struct perf_sample *sample); | 1547 | struct perf_sample *sample); |
1542 | 1548 | ||
1543 | static struct syscall *trace__syscall_info(struct trace *trace, | 1549 | static struct syscall *trace__syscall_info(struct trace *trace, |
@@ -1610,6 +1616,7 @@ static void thread__update_stats(struct thread_trace *ttrace, | |||
1610 | } | 1616 | } |
1611 | 1617 | ||
1612 | static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, | 1618 | static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, |
1619 | union perf_event *event __maybe_unused, | ||
1613 | struct perf_sample *sample) | 1620 | struct perf_sample *sample) |
1614 | { | 1621 | { |
1615 | char *msg; | 1622 | char *msg; |
@@ -1658,6 +1665,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, | |||
1658 | } | 1665 | } |
1659 | 1666 | ||
1660 | static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, | 1667 | static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, |
1668 | union perf_event *event __maybe_unused, | ||
1661 | struct perf_sample *sample) | 1669 | struct perf_sample *sample) |
1662 | { | 1670 | { |
1663 | int ret; | 1671 | int ret; |
@@ -1735,6 +1743,7 @@ out: | |||
1735 | } | 1743 | } |
1736 | 1744 | ||
1737 | static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel, | 1745 | static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel, |
1746 | union perf_event *event __maybe_unused, | ||
1738 | struct perf_sample *sample) | 1747 | struct perf_sample *sample) |
1739 | { | 1748 | { |
1740 | trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname"); | 1749 | trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname"); |
@@ -1742,6 +1751,7 @@ static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel, | |||
1742 | } | 1751 | } |
1743 | 1752 | ||
1744 | static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel, | 1753 | static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel, |
1754 | union perf_event *event __maybe_unused, | ||
1745 | struct perf_sample *sample) | 1755 | struct perf_sample *sample) |
1746 | { | 1756 | { |
1747 | u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); | 1757 | u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); |
@@ -1768,6 +1778,68 @@ out_dump: | |||
1768 | return 0; | 1778 | return 0; |
1769 | } | 1779 | } |
1770 | 1780 | ||
1781 | static void print_location(FILE *f, struct perf_sample *sample, | ||
1782 | struct addr_location *al, | ||
1783 | bool print_dso, bool print_sym) | ||
1784 | { | ||
1785 | |||
1786 | if ((verbose || print_dso) && al->map) | ||
1787 | fprintf(f, "%s@", al->map->dso->long_name); | ||
1788 | |||
1789 | if ((verbose || print_sym) && al->sym) | ||
1790 | fprintf(f, "%s+0x%lx", al->sym->name, | ||
1791 | al->addr - al->sym->start); | ||
1792 | else if (al->map) | ||
1793 | fprintf(f, "0x%lx", al->addr); | ||
1794 | else | ||
1795 | fprintf(f, "0x%lx", sample->addr); | ||
1796 | } | ||
1797 | |||
1798 | static int trace__pgfault(struct trace *trace, | ||
1799 | struct perf_evsel *evsel, | ||
1800 | union perf_event *event, | ||
1801 | struct perf_sample *sample) | ||
1802 | { | ||
1803 | struct thread *thread; | ||
1804 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | ||
1805 | struct addr_location al; | ||
1806 | char map_type = 'd'; | ||
1807 | |||
1808 | thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); | ||
1809 | |||
1810 | thread__find_addr_location(thread, trace->host, cpumode, MAP__FUNCTION, | ||
1811 | sample->ip, &al); | ||
1812 | |||
1813 | trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output); | ||
1814 | |||
1815 | fprintf(trace->output, "%sfault [", | ||
1816 | evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ? | ||
1817 | "maj" : "min"); | ||
1818 | |||
1819 | print_location(trace->output, sample, &al, false, true); | ||
1820 | |||
1821 | fprintf(trace->output, "] => "); | ||
1822 | |||
1823 | thread__find_addr_location(thread, trace->host, cpumode, MAP__VARIABLE, | ||
1824 | sample->addr, &al); | ||
1825 | |||
1826 | if (!al.map) { | ||
1827 | thread__find_addr_location(thread, trace->host, cpumode, | ||
1828 | MAP__FUNCTION, sample->addr, &al); | ||
1829 | |||
1830 | if (al.map) | ||
1831 | map_type = 'x'; | ||
1832 | else | ||
1833 | map_type = '?'; | ||
1834 | } | ||
1835 | |||
1836 | print_location(trace->output, sample, &al, true, false); | ||
1837 | |||
1838 | fprintf(trace->output, " (%c%c)\n", map_type, al.level); | ||
1839 | |||
1840 | return 0; | ||
1841 | } | ||
1842 | |||
1771 | static bool skip_sample(struct trace *trace, struct perf_sample *sample) | 1843 | static bool skip_sample(struct trace *trace, struct perf_sample *sample) |
1772 | { | 1844 | { |
1773 | if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) || | 1845 | if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) || |
@@ -1781,7 +1853,7 @@ static bool skip_sample(struct trace *trace, struct perf_sample *sample) | |||
1781 | } | 1853 | } |
1782 | 1854 | ||
1783 | static int trace__process_sample(struct perf_tool *tool, | 1855 | static int trace__process_sample(struct perf_tool *tool, |
1784 | union perf_event *event __maybe_unused, | 1856 | union perf_event *event, |
1785 | struct perf_sample *sample, | 1857 | struct perf_sample *sample, |
1786 | struct perf_evsel *evsel, | 1858 | struct perf_evsel *evsel, |
1787 | struct machine *machine __maybe_unused) | 1859 | struct machine *machine __maybe_unused) |
@@ -1799,7 +1871,7 @@ static int trace__process_sample(struct perf_tool *tool, | |||
1799 | 1871 | ||
1800 | if (handler) { | 1872 | if (handler) { |
1801 | ++trace->nr_events; | 1873 | ++trace->nr_events; |
1802 | handler(trace, evsel, sample); | 1874 | handler(trace, evsel, event, sample); |
1803 | } | 1875 | } |
1804 | 1876 | ||
1805 | return err; | 1877 | return err; |
@@ -1826,7 +1898,7 @@ static int parse_target_str(struct trace *trace) | |||
1826 | return 0; | 1898 | return 0; |
1827 | } | 1899 | } |
1828 | 1900 | ||
1829 | static int trace__record(int argc, const char **argv) | 1901 | static int trace__record(struct trace *trace, int argc, const char **argv) |
1830 | { | 1902 | { |
1831 | unsigned int rec_argc, i, j; | 1903 | unsigned int rec_argc, i, j; |
1832 | const char **rec_argv; | 1904 | const char **rec_argv; |
@@ -1835,34 +1907,54 @@ static int trace__record(int argc, const char **argv) | |||
1835 | "-R", | 1907 | "-R", |
1836 | "-m", "1024", | 1908 | "-m", "1024", |
1837 | "-c", "1", | 1909 | "-c", "1", |
1838 | "-e", | ||
1839 | }; | 1910 | }; |
1840 | 1911 | ||
1912 | const char * const sc_args[] = { "-e", }; | ||
1913 | unsigned int sc_args_nr = ARRAY_SIZE(sc_args); | ||
1914 | const char * const majpf_args[] = { "-e", "major-faults" }; | ||
1915 | unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args); | ||
1916 | const char * const minpf_args[] = { "-e", "minor-faults" }; | ||
1917 | unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args); | ||
1918 | |||
1841 | /* +1 is for the event string below */ | 1919 | /* +1 is for the event string below */ |
1842 | rec_argc = ARRAY_SIZE(record_args) + 1 + argc; | 1920 | rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 + |
1921 | majpf_args_nr + minpf_args_nr + argc; | ||
1843 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 1922 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
1844 | 1923 | ||
1845 | if (rec_argv == NULL) | 1924 | if (rec_argv == NULL) |
1846 | return -ENOMEM; | 1925 | return -ENOMEM; |
1847 | 1926 | ||
1927 | j = 0; | ||
1848 | for (i = 0; i < ARRAY_SIZE(record_args); i++) | 1928 | for (i = 0; i < ARRAY_SIZE(record_args); i++) |
1849 | rec_argv[i] = record_args[i]; | 1929 | rec_argv[j++] = record_args[i]; |
1850 | 1930 | ||
1851 | /* event string may be different for older kernels - e.g., RHEL6 */ | 1931 | if (trace->trace_syscalls) { |
1852 | if (is_valid_tracepoint("raw_syscalls:sys_enter")) | 1932 | for (i = 0; i < sc_args_nr; i++) |
1853 | rec_argv[i] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit"; | 1933 | rec_argv[j++] = sc_args[i]; |
1854 | else if (is_valid_tracepoint("syscalls:sys_enter")) | 1934 | |
1855 | rec_argv[i] = "syscalls:sys_enter,syscalls:sys_exit"; | 1935 | /* event string may be different for older kernels - e.g., RHEL6 */ |
1856 | else { | 1936 | if (is_valid_tracepoint("raw_syscalls:sys_enter")) |
1857 | pr_err("Neither raw_syscalls nor syscalls events exist.\n"); | 1937 | rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit"; |
1858 | return -1; | 1938 | else if (is_valid_tracepoint("syscalls:sys_enter")) |
1939 | rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit"; | ||
1940 | else { | ||
1941 | pr_err("Neither raw_syscalls nor syscalls events exist.\n"); | ||
1942 | return -1; | ||
1943 | } | ||
1859 | } | 1944 | } |
1860 | i++; | ||
1861 | 1945 | ||
1862 | for (j = 0; j < (unsigned int)argc; j++, i++) | 1946 | if (trace->trace_pgfaults & TRACE_PFMAJ) |
1863 | rec_argv[i] = argv[j]; | 1947 | for (i = 0; i < majpf_args_nr; i++) |
1948 | rec_argv[j++] = majpf_args[i]; | ||
1949 | |||
1950 | if (trace->trace_pgfaults & TRACE_PFMIN) | ||
1951 | for (i = 0; i < minpf_args_nr; i++) | ||
1952 | rec_argv[j++] = minpf_args[i]; | ||
1864 | 1953 | ||
1865 | return cmd_record(i, rec_argv, NULL); | 1954 | for (i = 0; i < (unsigned int)argc; i++) |
1955 | rec_argv[j++] = argv[i]; | ||
1956 | |||
1957 | return cmd_record(j, rec_argv, NULL); | ||
1866 | } | 1958 | } |
1867 | 1959 | ||
1868 | static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp); | 1960 | static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp); |
@@ -1882,6 +1974,30 @@ static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist) | |||
1882 | perf_evlist__add(evlist, evsel); | 1974 | perf_evlist__add(evlist, evsel); |
1883 | } | 1975 | } |
1884 | 1976 | ||
1977 | static int perf_evlist__add_pgfault(struct perf_evlist *evlist, | ||
1978 | u64 config) | ||
1979 | { | ||
1980 | struct perf_evsel *evsel; | ||
1981 | struct perf_event_attr attr = { | ||
1982 | .type = PERF_TYPE_SOFTWARE, | ||
1983 | .mmap_data = 1, | ||
1984 | .sample_period = 1, | ||
1985 | }; | ||
1986 | |||
1987 | attr.config = config; | ||
1988 | |||
1989 | event_attr_init(&attr); | ||
1990 | |||
1991 | evsel = perf_evsel__new(&attr); | ||
1992 | if (!evsel) | ||
1993 | return -ENOMEM; | ||
1994 | |||
1995 | evsel->handler = trace__pgfault; | ||
1996 | perf_evlist__add(evlist, evsel); | ||
1997 | |||
1998 | return 0; | ||
1999 | } | ||
2000 | |||
1885 | static int trace__run(struct trace *trace, int argc, const char **argv) | 2001 | static int trace__run(struct trace *trace, int argc, const char **argv) |
1886 | { | 2002 | { |
1887 | struct perf_evlist *evlist = perf_evlist__new(); | 2003 | struct perf_evlist *evlist = perf_evlist__new(); |
@@ -1897,10 +2013,21 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
1897 | goto out; | 2013 | goto out; |
1898 | } | 2014 | } |
1899 | 2015 | ||
1900 | if (perf_evlist__add_syscall_newtp(evlist, trace__sys_enter, trace__sys_exit)) | 2016 | if (trace->trace_syscalls && |
2017 | perf_evlist__add_syscall_newtp(evlist, trace__sys_enter, | ||
2018 | trace__sys_exit)) | ||
2019 | goto out_error_tp; | ||
2020 | |||
2021 | if (trace->trace_syscalls) | ||
2022 | perf_evlist__add_vfs_getname(evlist); | ||
2023 | |||
2024 | if ((trace->trace_pgfaults & TRACE_PFMAJ) && | ||
2025 | perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) | ||
1901 | goto out_error_tp; | 2026 | goto out_error_tp; |
1902 | 2027 | ||
1903 | perf_evlist__add_vfs_getname(evlist); | 2028 | if ((trace->trace_pgfaults & TRACE_PFMIN) && |
2029 | perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN)) | ||
2030 | goto out_error_tp; | ||
1904 | 2031 | ||
1905 | if (trace->sched && | 2032 | if (trace->sched && |
1906 | perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime", | 2033 | perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime", |
@@ -1982,7 +2109,8 @@ again: | |||
1982 | goto next_event; | 2109 | goto next_event; |
1983 | } | 2110 | } |
1984 | 2111 | ||
1985 | if (sample.raw_data == NULL) { | 2112 | if (evsel->attr.type == PERF_TYPE_TRACEPOINT && |
2113 | sample.raw_data == NULL) { | ||
1986 | fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", | 2114 | fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", |
1987 | perf_evsel__name(evsel), sample.tid, | 2115 | perf_evsel__name(evsel), sample.tid, |
1988 | sample.cpu, sample.raw_size); | 2116 | sample.cpu, sample.raw_size); |
@@ -1990,7 +2118,7 @@ again: | |||
1990 | } | 2118 | } |
1991 | 2119 | ||
1992 | handler = evsel->handler; | 2120 | handler = evsel->handler; |
1993 | handler(trace, evsel, &sample); | 2121 | handler(trace, evsel, event, &sample); |
1994 | next_event: | 2122 | next_event: |
1995 | perf_evlist__mmap_consume(evlist, i); | 2123 | perf_evlist__mmap_consume(evlist, i); |
1996 | 2124 | ||
@@ -2093,13 +2221,10 @@ static int trace__replay(struct trace *trace) | |||
2093 | if (evsel == NULL) | 2221 | if (evsel == NULL) |
2094 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, | 2222 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, |
2095 | "syscalls:sys_enter"); | 2223 | "syscalls:sys_enter"); |
2096 | if (evsel == NULL) { | ||
2097 | pr_err("Data file does not have raw_syscalls:sys_enter event\n"); | ||
2098 | goto out; | ||
2099 | } | ||
2100 | 2224 | ||
2101 | if (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 || | 2225 | if (evsel && |
2102 | perf_evsel__init_sc_tp_ptr_field(evsel, args)) { | 2226 | (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 || |
2227 | perf_evsel__init_sc_tp_ptr_field(evsel, args))) { | ||
2103 | pr_err("Error during initialize raw_syscalls:sys_enter event\n"); | 2228 | pr_err("Error during initialize raw_syscalls:sys_enter event\n"); |
2104 | goto out; | 2229 | goto out; |
2105 | } | 2230 | } |
@@ -2109,15 +2234,19 @@ static int trace__replay(struct trace *trace) | |||
2109 | if (evsel == NULL) | 2234 | if (evsel == NULL) |
2110 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, | 2235 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, |
2111 | "syscalls:sys_exit"); | 2236 | "syscalls:sys_exit"); |
2112 | if (evsel == NULL) { | 2237 | if (evsel && |
2113 | pr_err("Data file does not have raw_syscalls:sys_exit event\n"); | 2238 | (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 || |
2239 | perf_evsel__init_sc_tp_uint_field(evsel, ret))) { | ||
2240 | pr_err("Error during initialize raw_syscalls:sys_exit event\n"); | ||
2114 | goto out; | 2241 | goto out; |
2115 | } | 2242 | } |
2116 | 2243 | ||
2117 | if (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 || | 2244 | evlist__for_each(session->evlist, evsel) { |
2118 | perf_evsel__init_sc_tp_uint_field(evsel, ret)) { | 2245 | if (evsel->attr.type == PERF_TYPE_SOFTWARE && |
2119 | pr_err("Error during initialize raw_syscalls:sys_exit event\n"); | 2246 | (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ || |
2120 | goto out; | 2247 | evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN || |
2248 | evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS)) | ||
2249 | evsel->handler = trace__pgfault; | ||
2121 | } | 2250 | } |
2122 | 2251 | ||
2123 | err = parse_target_str(trace); | 2252 | err = parse_target_str(trace); |
@@ -2264,6 +2393,23 @@ static int trace__open_output(struct trace *trace, const char *filename) | |||
2264 | return trace->output == NULL ? -errno : 0; | 2393 | return trace->output == NULL ? -errno : 0; |
2265 | } | 2394 | } |
2266 | 2395 | ||
2396 | static int parse_pagefaults(const struct option *opt, const char *str, | ||
2397 | int unset __maybe_unused) | ||
2398 | { | ||
2399 | int *trace_pgfaults = opt->value; | ||
2400 | |||
2401 | if (strcmp(str, "all") == 0) | ||
2402 | *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN; | ||
2403 | else if (strcmp(str, "maj") == 0) | ||
2404 | *trace_pgfaults |= TRACE_PFMAJ; | ||
2405 | else if (strcmp(str, "min") == 0) | ||
2406 | *trace_pgfaults |= TRACE_PFMIN; | ||
2407 | else | ||
2408 | return -1; | ||
2409 | |||
2410 | return 0; | ||
2411 | } | ||
2412 | |||
2267 | int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | 2413 | int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) |
2268 | { | 2414 | { |
2269 | const char * const trace_usage[] = { | 2415 | const char * const trace_usage[] = { |
@@ -2293,6 +2439,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | |||
2293 | }, | 2439 | }, |
2294 | .output = stdout, | 2440 | .output = stdout, |
2295 | .show_comm = true, | 2441 | .show_comm = true, |
2442 | .trace_syscalls = true, | ||
2296 | }; | 2443 | }; |
2297 | const char *output_name = NULL; | 2444 | const char *output_name = NULL; |
2298 | const char *ev_qualifier_str = NULL; | 2445 | const char *ev_qualifier_str = NULL; |
@@ -2330,20 +2477,34 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | |||
2330 | "Show only syscall summary with statistics"), | 2477 | "Show only syscall summary with statistics"), |
2331 | OPT_BOOLEAN('S', "with-summary", &trace.summary, | 2478 | OPT_BOOLEAN('S', "with-summary", &trace.summary, |
2332 | "Show all syscalls and summary with statistics"), | 2479 | "Show all syscalls and summary with statistics"), |
2480 | OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min", | ||
2481 | "Trace pagefaults", parse_pagefaults, "maj"), | ||
2482 | OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"), | ||
2333 | OPT_END() | 2483 | OPT_END() |
2334 | }; | 2484 | }; |
2335 | int err; | 2485 | int err; |
2336 | char bf[BUFSIZ]; | 2486 | char bf[BUFSIZ]; |
2337 | 2487 | ||
2338 | if ((argc > 1) && (strcmp(argv[1], "record") == 0)) | 2488 | argc = parse_options(argc, argv, trace_options, trace_usage, |
2339 | return trace__record(argc-2, &argv[2]); | 2489 | PARSE_OPT_STOP_AT_NON_OPTION); |
2490 | |||
2491 | if (trace.trace_pgfaults) { | ||
2492 | trace.opts.sample_address = true; | ||
2493 | trace.opts.sample_time = true; | ||
2494 | } | ||
2340 | 2495 | ||
2341 | argc = parse_options(argc, argv, trace_options, trace_usage, 0); | 2496 | if ((argc >= 1) && (strcmp(argv[0], "record") == 0)) |
2497 | return trace__record(&trace, argc-1, &argv[1]); | ||
2342 | 2498 | ||
2343 | /* summary_only implies summary option, but don't overwrite summary if set */ | 2499 | /* summary_only implies summary option, but don't overwrite summary if set */ |
2344 | if (trace.summary_only) | 2500 | if (trace.summary_only) |
2345 | trace.summary = trace.summary_only; | 2501 | trace.summary = trace.summary_only; |
2346 | 2502 | ||
2503 | if (!trace.trace_syscalls && !trace.trace_pgfaults) { | ||
2504 | pr_err("Please specify something to trace.\n"); | ||
2505 | return -1; | ||
2506 | } | ||
2507 | |||
2347 | if (output_name != NULL) { | 2508 | if (output_name != NULL) { |
2348 | err = trace__open_output(&trace, output_name); | 2509 | err = trace__open_output(&trace, output_name); |
2349 | if (err < 0) { | 2510 | if (err < 0) { |
diff --git a/tools/perf/scripts/perl/bin/failed-syscalls-record b/tools/perf/scripts/perl/bin/failed-syscalls-record index 8104895a7b67..74685f318379 100644 --- a/tools/perf/scripts/perl/bin/failed-syscalls-record +++ b/tools/perf/scripts/perl/bin/failed-syscalls-record | |||
@@ -1,2 +1,3 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -e raw_syscalls:sys_exit $@ | 2 | (perf record -e raw_syscalls:sys_exit $@ || \ |
3 | perf record -e syscalls:sys_exit $@) 2> /dev/null | ||
diff --git a/tools/perf/scripts/perl/failed-syscalls.pl b/tools/perf/scripts/perl/failed-syscalls.pl index 94bc25a347eb..55e7ae4c5c88 100644 --- a/tools/perf/scripts/perl/failed-syscalls.pl +++ b/tools/perf/scripts/perl/failed-syscalls.pl | |||
@@ -26,6 +26,11 @@ sub raw_syscalls::sys_exit | |||
26 | } | 26 | } |
27 | } | 27 | } |
28 | 28 | ||
29 | sub syscalls::sys_exit | ||
30 | { | ||
31 | raw_syscalls::sys_exit(@_) | ||
32 | } | ||
33 | |||
29 | sub trace_end | 34 | sub trace_end |
30 | { | 35 | { |
31 | printf("\nfailed syscalls by comm:\n\n"); | 36 | printf("\nfailed syscalls by comm:\n\n"); |
diff --git a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record index 8104895a7b67..74685f318379 100644 --- a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record +++ b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record | |||
@@ -1,2 +1,3 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -e raw_syscalls:sys_exit $@ | 2 | (perf record -e raw_syscalls:sys_exit $@ || \ |
3 | perf record -e syscalls:sys_exit $@) 2> /dev/null | ||
diff --git a/tools/perf/scripts/python/bin/sctop-record b/tools/perf/scripts/python/bin/sctop-record index 4efbfaa7f6a5..d6940841e54f 100644 --- a/tools/perf/scripts/python/bin/sctop-record +++ b/tools/perf/scripts/python/bin/sctop-record | |||
@@ -1,2 +1,3 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -e raw_syscalls:sys_enter $@ | 2 | (perf record -e raw_syscalls:sys_enter $@ || \ |
3 | perf record -e syscalls:sys_enter $@) 2> /dev/null | ||
diff --git a/tools/perf/scripts/python/bin/syscall-counts-by-pid-record b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record index 4efbfaa7f6a5..d6940841e54f 100644 --- a/tools/perf/scripts/python/bin/syscall-counts-by-pid-record +++ b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record | |||
@@ -1,2 +1,3 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -e raw_syscalls:sys_enter $@ | 2 | (perf record -e raw_syscalls:sys_enter $@ || \ |
3 | perf record -e syscalls:sys_enter $@) 2> /dev/null | ||
diff --git a/tools/perf/scripts/python/bin/syscall-counts-record b/tools/perf/scripts/python/bin/syscall-counts-record index 4efbfaa7f6a5..d6940841e54f 100644 --- a/tools/perf/scripts/python/bin/syscall-counts-record +++ b/tools/perf/scripts/python/bin/syscall-counts-record | |||
@@ -1,2 +1,3 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -e raw_syscalls:sys_enter $@ | 2 | (perf record -e raw_syscalls:sys_enter $@ || \ |
3 | perf record -e syscalls:sys_enter $@) 2> /dev/null | ||
diff --git a/tools/perf/scripts/python/failed-syscalls-by-pid.py b/tools/perf/scripts/python/failed-syscalls-by-pid.py index 85805fac4116..266a8364bce5 100644 --- a/tools/perf/scripts/python/failed-syscalls-by-pid.py +++ b/tools/perf/scripts/python/failed-syscalls-by-pid.py | |||
@@ -50,6 +50,11 @@ def raw_syscalls__sys_exit(event_name, context, common_cpu, | |||
50 | except TypeError: | 50 | except TypeError: |
51 | syscalls[common_comm][common_pid][id][ret] = 1 | 51 | syscalls[common_comm][common_pid][id][ret] = 1 |
52 | 52 | ||
53 | def syscalls__sys_exit(event_name, context, common_cpu, | ||
54 | common_secs, common_nsecs, common_pid, common_comm, | ||
55 | id, ret): | ||
56 | raw_syscalls__sys_exit(**locals()) | ||
57 | |||
53 | def print_error_totals(): | 58 | def print_error_totals(): |
54 | if for_comm is not None: | 59 | if for_comm is not None: |
55 | print "\nsyscall errors for %s:\n\n" % (for_comm), | 60 | print "\nsyscall errors for %s:\n\n" % (for_comm), |
diff --git a/tools/perf/scripts/python/sctop.py b/tools/perf/scripts/python/sctop.py index 42c267e292fa..c9f3058b7dd4 100644 --- a/tools/perf/scripts/python/sctop.py +++ b/tools/perf/scripts/python/sctop.py | |||
@@ -53,6 +53,11 @@ def raw_syscalls__sys_enter(event_name, context, common_cpu, | |||
53 | except TypeError: | 53 | except TypeError: |
54 | syscalls[id] = 1 | 54 | syscalls[id] = 1 |
55 | 55 | ||
56 | def syscalls__sys_enter(event_name, context, common_cpu, | ||
57 | common_secs, common_nsecs, common_pid, common_comm, | ||
58 | id, args): | ||
59 | raw_syscalls__sys_enter(**locals()) | ||
60 | |||
56 | def print_syscall_totals(interval): | 61 | def print_syscall_totals(interval): |
57 | while 1: | 62 | while 1: |
58 | clear_term() | 63 | clear_term() |
diff --git a/tools/perf/scripts/python/syscall-counts-by-pid.py b/tools/perf/scripts/python/syscall-counts-by-pid.py index c64d1c55d745..cf2054c529c9 100644 --- a/tools/perf/scripts/python/syscall-counts-by-pid.py +++ b/tools/perf/scripts/python/syscall-counts-by-pid.py | |||
@@ -48,6 +48,11 @@ def raw_syscalls__sys_enter(event_name, context, common_cpu, | |||
48 | except TypeError: | 48 | except TypeError: |
49 | syscalls[common_comm][common_pid][id] = 1 | 49 | syscalls[common_comm][common_pid][id] = 1 |
50 | 50 | ||
51 | def syscalls__sys_enter(event_name, context, common_cpu, | ||
52 | common_secs, common_nsecs, common_pid, common_comm, | ||
53 | id, args): | ||
54 | raw_syscalls__sys_enter(**locals()) | ||
55 | |||
51 | def print_syscall_totals(): | 56 | def print_syscall_totals(): |
52 | if for_comm is not None: | 57 | if for_comm is not None: |
53 | print "\nsyscall events for %s:\n\n" % (for_comm), | 58 | print "\nsyscall events for %s:\n\n" % (for_comm), |
diff --git a/tools/perf/scripts/python/syscall-counts.py b/tools/perf/scripts/python/syscall-counts.py index b435d3f188e8..92b29381bd39 100644 --- a/tools/perf/scripts/python/syscall-counts.py +++ b/tools/perf/scripts/python/syscall-counts.py | |||
@@ -44,6 +44,11 @@ def raw_syscalls__sys_enter(event_name, context, common_cpu, | |||
44 | except TypeError: | 44 | except TypeError: |
45 | syscalls[id] = 1 | 45 | syscalls[id] = 1 |
46 | 46 | ||
47 | def syscalls__sys_enter(event_name, context, common_cpu, | ||
48 | common_secs, common_nsecs, common_pid, common_comm, | ||
49 | id, args): | ||
50 | raw_syscalls__sys_enter(**locals()) | ||
51 | |||
47 | def print_syscall_totals(): | 52 | def print_syscall_totals(): |
48 | if for_comm is not None: | 53 | if for_comm is not None: |
49 | print "\nsyscall events for %s:\n\n" % (for_comm), | 54 | print "\nsyscall events for %s:\n\n" % (for_comm), |