diff options
Diffstat (limited to 'tools/perf/builtin-trace.c')
-rw-r--r-- | tools/perf/builtin-trace.c | 98 |
1 files changed, 54 insertions, 44 deletions
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 8be17fc462ba..896f27047ed6 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -11,6 +11,8 @@ | |||
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 | #include "util/stat.h" |
14 | #include "trace-event.h" | ||
15 | #include "util/parse-events.h" | ||
14 | 16 | ||
15 | #include <libaudit.h> | 17 | #include <libaudit.h> |
16 | #include <stdlib.h> | 18 | #include <stdlib.h> |
@@ -144,8 +146,7 @@ static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel, | |||
144 | 146 | ||
145 | static void perf_evsel__delete_priv(struct perf_evsel *evsel) | 147 | static void perf_evsel__delete_priv(struct perf_evsel *evsel) |
146 | { | 148 | { |
147 | free(evsel->priv); | 149 | zfree(&evsel->priv); |
148 | evsel->priv = NULL; | ||
149 | perf_evsel__delete(evsel); | 150 | perf_evsel__delete(evsel); |
150 | } | 151 | } |
151 | 152 | ||
@@ -163,8 +164,7 @@ static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler) | |||
163 | return -ENOMEM; | 164 | return -ENOMEM; |
164 | 165 | ||
165 | out_delete: | 166 | out_delete: |
166 | free(evsel->priv); | 167 | zfree(&evsel->priv); |
167 | evsel->priv = NULL; | ||
168 | return -ENOENT; | 168 | return -ENOENT; |
169 | } | 169 | } |
170 | 170 | ||
@@ -172,6 +172,10 @@ static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void | |||
172 | { | 172 | { |
173 | struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction); | 173 | struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction); |
174 | 174 | ||
175 | /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */ | ||
176 | if (evsel == NULL) | ||
177 | evsel = perf_evsel__newtp("syscalls", direction); | ||
178 | |||
175 | if (evsel) { | 179 | if (evsel) { |
176 | if (perf_evsel__init_syscall_tp(evsel, handler)) | 180 | if (perf_evsel__init_syscall_tp(evsel, handler)) |
177 | goto out_delete; | 181 | goto out_delete; |
@@ -1153,29 +1157,30 @@ struct trace { | |||
1153 | int max; | 1157 | int max; |
1154 | struct syscall *table; | 1158 | struct syscall *table; |
1155 | } syscalls; | 1159 | } syscalls; |
1156 | struct perf_record_opts opts; | 1160 | struct record_opts opts; |
1157 | struct machine *host; | 1161 | struct machine *host; |
1158 | u64 base_time; | 1162 | u64 base_time; |
1159 | bool full_time; | ||
1160 | FILE *output; | 1163 | FILE *output; |
1161 | unsigned long nr_events; | 1164 | unsigned long nr_events; |
1162 | struct strlist *ev_qualifier; | 1165 | struct strlist *ev_qualifier; |
1163 | bool not_ev_qualifier; | ||
1164 | bool live; | ||
1165 | const char *last_vfs_getname; | 1166 | const char *last_vfs_getname; |
1166 | struct intlist *tid_list; | 1167 | struct intlist *tid_list; |
1167 | struct intlist *pid_list; | 1168 | struct intlist *pid_list; |
1169 | double duration_filter; | ||
1170 | double runtime_ms; | ||
1171 | struct { | ||
1172 | u64 vfs_getname, | ||
1173 | proc_getname; | ||
1174 | } stats; | ||
1175 | bool not_ev_qualifier; | ||
1176 | bool live; | ||
1177 | bool full_time; | ||
1168 | bool sched; | 1178 | bool sched; |
1169 | bool multiple_threads; | 1179 | bool multiple_threads; |
1170 | bool summary; | 1180 | bool summary; |
1171 | bool summary_only; | 1181 | bool summary_only; |
1172 | bool show_comm; | 1182 | bool show_comm; |
1173 | bool show_tool_stats; | 1183 | bool show_tool_stats; |
1174 | double duration_filter; | ||
1175 | double runtime_ms; | ||
1176 | struct { | ||
1177 | u64 vfs_getname, proc_getname; | ||
1178 | } stats; | ||
1179 | }; | 1184 | }; |
1180 | 1185 | ||
1181 | static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname) | 1186 | static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname) |
@@ -1272,10 +1277,8 @@ static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size, | |||
1272 | size_t printed = syscall_arg__scnprintf_fd(bf, size, arg); | 1277 | size_t printed = syscall_arg__scnprintf_fd(bf, size, arg); |
1273 | struct thread_trace *ttrace = arg->thread->priv; | 1278 | struct thread_trace *ttrace = arg->thread->priv; |
1274 | 1279 | ||
1275 | if (ttrace && fd >= 0 && fd <= ttrace->paths.max) { | 1280 | if (ttrace && fd >= 0 && fd <= ttrace->paths.max) |
1276 | free(ttrace->paths.table[fd]); | 1281 | zfree(&ttrace->paths.table[fd]); |
1277 | ttrace->paths.table[fd] = NULL; | ||
1278 | } | ||
1279 | 1282 | ||
1280 | return printed; | 1283 | return printed; |
1281 | } | 1284 | } |
@@ -1430,11 +1433,11 @@ static int trace__read_syscall_info(struct trace *trace, int id) | |||
1430 | sc->fmt = syscall_fmt__find(sc->name); | 1433 | sc->fmt = syscall_fmt__find(sc->name); |
1431 | 1434 | ||
1432 | snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name); | 1435 | snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name); |
1433 | sc->tp_format = event_format__new("syscalls", tp_name); | 1436 | sc->tp_format = trace_event__tp_format("syscalls", tp_name); |
1434 | 1437 | ||
1435 | if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) { | 1438 | if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) { |
1436 | snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias); | 1439 | snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias); |
1437 | sc->tp_format = event_format__new("syscalls", tp_name); | 1440 | sc->tp_format = trace_event__tp_format("syscalls", tp_name); |
1438 | } | 1441 | } |
1439 | 1442 | ||
1440 | if (sc->tp_format == NULL) | 1443 | if (sc->tp_format == NULL) |
@@ -1764,8 +1767,10 @@ static int trace__process_sample(struct perf_tool *tool, | |||
1764 | if (!trace->full_time && trace->base_time == 0) | 1767 | if (!trace->full_time && trace->base_time == 0) |
1765 | trace->base_time = sample->time; | 1768 | trace->base_time = sample->time; |
1766 | 1769 | ||
1767 | if (handler) | 1770 | if (handler) { |
1771 | ++trace->nr_events; | ||
1768 | handler(trace, evsel, sample); | 1772 | handler(trace, evsel, sample); |
1773 | } | ||
1769 | 1774 | ||
1770 | return err; | 1775 | return err; |
1771 | } | 1776 | } |
@@ -1800,10 +1805,11 @@ static int trace__record(int argc, const char **argv) | |||
1800 | "-R", | 1805 | "-R", |
1801 | "-m", "1024", | 1806 | "-m", "1024", |
1802 | "-c", "1", | 1807 | "-c", "1", |
1803 | "-e", "raw_syscalls:sys_enter,raw_syscalls:sys_exit", | 1808 | "-e", |
1804 | }; | 1809 | }; |
1805 | 1810 | ||
1806 | rec_argc = ARRAY_SIZE(record_args) + argc; | 1811 | /* +1 is for the event string below */ |
1812 | rec_argc = ARRAY_SIZE(record_args) + 1 + argc; | ||
1807 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 1813 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
1808 | 1814 | ||
1809 | if (rec_argv == NULL) | 1815 | if (rec_argv == NULL) |
@@ -1812,6 +1818,17 @@ static int trace__record(int argc, const char **argv) | |||
1812 | for (i = 0; i < ARRAY_SIZE(record_args); i++) | 1818 | for (i = 0; i < ARRAY_SIZE(record_args); i++) |
1813 | rec_argv[i] = record_args[i]; | 1819 | rec_argv[i] = record_args[i]; |
1814 | 1820 | ||
1821 | /* event string may be different for older kernels - e.g., RHEL6 */ | ||
1822 | if (is_valid_tracepoint("raw_syscalls:sys_enter")) | ||
1823 | rec_argv[i] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit"; | ||
1824 | else if (is_valid_tracepoint("syscalls:sys_enter")) | ||
1825 | rec_argv[i] = "syscalls:sys_enter,syscalls:sys_exit"; | ||
1826 | else { | ||
1827 | pr_err("Neither raw_syscalls nor syscalls events exist.\n"); | ||
1828 | return -1; | ||
1829 | } | ||
1830 | i++; | ||
1831 | |||
1815 | for (j = 0; j < (unsigned int)argc; j++, i++) | 1832 | for (j = 0; j < (unsigned int)argc; j++, i++) |
1816 | rec_argv[i] = argv[j]; | 1833 | rec_argv[i] = argv[j]; |
1817 | 1834 | ||
@@ -1869,7 +1886,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
1869 | err = trace__symbols_init(trace, evlist); | 1886 | err = trace__symbols_init(trace, evlist); |
1870 | if (err < 0) { | 1887 | if (err < 0) { |
1871 | fprintf(trace->output, "Problems initializing symbol libraries!\n"); | 1888 | fprintf(trace->output, "Problems initializing symbol libraries!\n"); |
1872 | goto out_delete_maps; | 1889 | goto out_delete_evlist; |
1873 | } | 1890 | } |
1874 | 1891 | ||
1875 | perf_evlist__config(evlist, &trace->opts); | 1892 | perf_evlist__config(evlist, &trace->opts); |
@@ -1879,10 +1896,10 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
1879 | 1896 | ||
1880 | if (forks) { | 1897 | if (forks) { |
1881 | err = perf_evlist__prepare_workload(evlist, &trace->opts.target, | 1898 | err = perf_evlist__prepare_workload(evlist, &trace->opts.target, |
1882 | argv, false, false); | 1899 | argv, false, NULL); |
1883 | if (err < 0) { | 1900 | if (err < 0) { |
1884 | fprintf(trace->output, "Couldn't run the workload!\n"); | 1901 | fprintf(trace->output, "Couldn't run the workload!\n"); |
1885 | goto out_delete_maps; | 1902 | goto out_delete_evlist; |
1886 | } | 1903 | } |
1887 | } | 1904 | } |
1888 | 1905 | ||
@@ -1890,10 +1907,10 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
1890 | if (err < 0) | 1907 | if (err < 0) |
1891 | goto out_error_open; | 1908 | goto out_error_open; |
1892 | 1909 | ||
1893 | err = perf_evlist__mmap(evlist, UINT_MAX, false); | 1910 | err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false); |
1894 | if (err < 0) { | 1911 | if (err < 0) { |
1895 | fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno)); | 1912 | fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno)); |
1896 | goto out_close_evlist; | 1913 | goto out_delete_evlist; |
1897 | } | 1914 | } |
1898 | 1915 | ||
1899 | perf_evlist__enable(evlist); | 1916 | perf_evlist__enable(evlist); |
@@ -1977,11 +1994,6 @@ out_disable: | |||
1977 | } | 1994 | } |
1978 | } | 1995 | } |
1979 | 1996 | ||
1980 | perf_evlist__munmap(evlist); | ||
1981 | out_close_evlist: | ||
1982 | perf_evlist__close(evlist); | ||
1983 | out_delete_maps: | ||
1984 | perf_evlist__delete_maps(evlist); | ||
1985 | out_delete_evlist: | 1997 | out_delete_evlist: |
1986 | perf_evlist__delete(evlist); | 1998 | perf_evlist__delete(evlist); |
1987 | out: | 1999 | out: |
@@ -2047,6 +2059,10 @@ static int trace__replay(struct trace *trace) | |||
2047 | 2059 | ||
2048 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, | 2060 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, |
2049 | "raw_syscalls:sys_enter"); | 2061 | "raw_syscalls:sys_enter"); |
2062 | /* older kernels have syscalls tp versus raw_syscalls */ | ||
2063 | if (evsel == NULL) | ||
2064 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, | ||
2065 | "syscalls:sys_enter"); | ||
2050 | if (evsel == NULL) { | 2066 | if (evsel == NULL) { |
2051 | pr_err("Data file does not have raw_syscalls:sys_enter event\n"); | 2067 | pr_err("Data file does not have raw_syscalls:sys_enter event\n"); |
2052 | goto out; | 2068 | goto out; |
@@ -2060,6 +2076,9 @@ static int trace__replay(struct trace *trace) | |||
2060 | 2076 | ||
2061 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, | 2077 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, |
2062 | "raw_syscalls:sys_exit"); | 2078 | "raw_syscalls:sys_exit"); |
2079 | if (evsel == NULL) | ||
2080 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, | ||
2081 | "syscalls:sys_exit"); | ||
2063 | if (evsel == NULL) { | 2082 | if (evsel == NULL) { |
2064 | pr_err("Data file does not have raw_syscalls:sys_exit event\n"); | 2083 | pr_err("Data file does not have raw_syscalls:sys_exit event\n"); |
2065 | goto out; | 2084 | goto out; |
@@ -2158,7 +2177,6 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv) | |||
2158 | size_t printed = data->printed; | 2177 | size_t printed = data->printed; |
2159 | struct trace *trace = data->trace; | 2178 | struct trace *trace = data->trace; |
2160 | struct thread_trace *ttrace = thread->priv; | 2179 | struct thread_trace *ttrace = thread->priv; |
2161 | const char *color; | ||
2162 | double ratio; | 2180 | double ratio; |
2163 | 2181 | ||
2164 | if (ttrace == NULL) | 2182 | if (ttrace == NULL) |
@@ -2166,17 +2184,9 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv) | |||
2166 | 2184 | ||
2167 | ratio = (double)ttrace->nr_events / trace->nr_events * 100.0; | 2185 | ratio = (double)ttrace->nr_events / trace->nr_events * 100.0; |
2168 | 2186 | ||
2169 | color = PERF_COLOR_NORMAL; | 2187 | printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid); |
2170 | if (ratio > 50.0) | ||
2171 | color = PERF_COLOR_RED; | ||
2172 | else if (ratio > 25.0) | ||
2173 | color = PERF_COLOR_GREEN; | ||
2174 | else if (ratio > 5.0) | ||
2175 | color = PERF_COLOR_YELLOW; | ||
2176 | |||
2177 | printed += color_fprintf(fp, color, " %s (%d), ", thread__comm_str(thread), thread->tid); | ||
2178 | printed += fprintf(fp, "%lu events, ", ttrace->nr_events); | 2188 | printed += fprintf(fp, "%lu events, ", ttrace->nr_events); |
2179 | printed += color_fprintf(fp, color, "%.1f%%", ratio); | 2189 | printed += fprintf(fp, "%.1f%%", ratio); |
2180 | printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms); | 2190 | printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms); |
2181 | printed += thread__dump_stats(ttrace, trace, fp); | 2191 | printed += thread__dump_stats(ttrace, trace, fp); |
2182 | 2192 | ||
@@ -2248,7 +2258,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | |||
2248 | }, | 2258 | }, |
2249 | .user_freq = UINT_MAX, | 2259 | .user_freq = UINT_MAX, |
2250 | .user_interval = ULLONG_MAX, | 2260 | .user_interval = ULLONG_MAX, |
2251 | .no_delay = true, | 2261 | .no_buffering = true, |
2252 | .mmap_pages = 1024, | 2262 | .mmap_pages = 1024, |
2253 | }, | 2263 | }, |
2254 | .output = stdout, | 2264 | .output = stdout, |