aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-trace.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-trace.c')
-rw-r--r--tools/perf/builtin-trace.c266
1 files changed, 222 insertions, 44 deletions
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index f954c26de231..a6c375224f46 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -1108,6 +1108,7 @@ struct syscall {
1108 struct event_format *tp_format; 1108 struct event_format *tp_format;
1109 const char *name; 1109 const char *name;
1110 bool filtered; 1110 bool filtered;
1111 bool is_exit;
1111 struct syscall_fmt *fmt; 1112 struct syscall_fmt *fmt;
1112 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg); 1113 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
1113 void **arg_parm; 1114 void **arg_parm;
@@ -1132,6 +1133,7 @@ struct thread_trace {
1132 u64 exit_time; 1133 u64 exit_time;
1133 bool entry_pending; 1134 bool entry_pending;
1134 unsigned long nr_events; 1135 unsigned long nr_events;
1136 unsigned long pfmaj, pfmin;
1135 char *entry_str; 1137 char *entry_str;
1136 double runtime_ms; 1138 double runtime_ms;
1137 struct { 1139 struct {
@@ -1177,6 +1179,9 @@ fail:
1177 return NULL; 1179 return NULL;
1178} 1180}
1179 1181
1182#define TRACE_PFMAJ (1 << 0)
1183#define TRACE_PFMIN (1 << 1)
1184
1180struct trace { 1185struct trace {
1181 struct perf_tool tool; 1186 struct perf_tool tool;
1182 struct { 1187 struct {
@@ -1211,6 +1216,8 @@ struct trace {
1211 bool summary_only; 1216 bool summary_only;
1212 bool show_comm; 1217 bool show_comm;
1213 bool show_tool_stats; 1218 bool show_tool_stats;
1219 bool trace_syscalls;
1220 int trace_pgfaults;
1214}; 1221};
1215 1222
1216static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname) 1223static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
@@ -1276,11 +1283,11 @@ static const char *thread__fd_path(struct thread *thread, int fd,
1276 if (fd < 0) 1283 if (fd < 0)
1277 return NULL; 1284 return NULL;
1278 1285
1279 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) 1286 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
1280 if (!trace->live) 1287 if (!trace->live)
1281 return NULL; 1288 return NULL;
1282 ++trace->stats.proc_getname; 1289 ++trace->stats.proc_getname;
1283 if (thread__read_fd_path(thread, fd)) { 1290 if (thread__read_fd_path(thread, fd))
1284 return NULL; 1291 return NULL;
1285 } 1292 }
1286 1293
@@ -1473,6 +1480,8 @@ static int trace__read_syscall_info(struct trace *trace, int id)
1473 if (sc->tp_format == NULL) 1480 if (sc->tp_format == NULL)
1474 return -1; 1481 return -1;
1475 1482
1483 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1484
1476 return syscall__set_arg_fmts(sc); 1485 return syscall__set_arg_fmts(sc);
1477} 1486}
1478 1487
@@ -1535,6 +1544,7 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
1535} 1544}
1536 1545
1537typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel, 1546typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
1547 union perf_event *event,
1538 struct perf_sample *sample); 1548 struct perf_sample *sample);
1539 1549
1540static struct syscall *trace__syscall_info(struct trace *trace, 1550static struct syscall *trace__syscall_info(struct trace *trace,
@@ -1607,6 +1617,7 @@ static void thread__update_stats(struct thread_trace *ttrace,
1607} 1617}
1608 1618
1609static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, 1619static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1620 union perf_event *event __maybe_unused,
1610 struct perf_sample *sample) 1621 struct perf_sample *sample)
1611{ 1622{
1612 char *msg; 1623 char *msg;
@@ -1629,7 +1640,6 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1629 return -1; 1640 return -1;
1630 1641
1631 args = perf_evsel__sc_tp_ptr(evsel, args, sample); 1642 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
1632 ttrace = thread->priv;
1633 1643
1634 if (ttrace->entry_str == NULL) { 1644 if (ttrace->entry_str == NULL) {
1635 ttrace->entry_str = malloc(1024); 1645 ttrace->entry_str = malloc(1024);
@@ -1644,7 +1654,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1644 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, 1654 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1645 args, trace, thread); 1655 args, trace, thread);
1646 1656
1647 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) { 1657 if (sc->is_exit) {
1648 if (!trace->duration_filter && !trace->summary_only) { 1658 if (!trace->duration_filter && !trace->summary_only) {
1649 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output); 1659 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1650 fprintf(trace->output, "%-70s\n", ttrace->entry_str); 1660 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
@@ -1656,6 +1666,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1656} 1666}
1657 1667
1658static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, 1668static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1669 union perf_event *event __maybe_unused,
1659 struct perf_sample *sample) 1670 struct perf_sample *sample)
1660{ 1671{
1661 int ret; 1672 int ret;
@@ -1687,8 +1698,6 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1687 ++trace->stats.vfs_getname; 1698 ++trace->stats.vfs_getname;
1688 } 1699 }
1689 1700
1690 ttrace = thread->priv;
1691
1692 ttrace->exit_time = sample->time; 1701 ttrace->exit_time = sample->time;
1693 1702
1694 if (ttrace->entry_time) { 1703 if (ttrace->entry_time) {
@@ -1735,6 +1744,7 @@ out:
1735} 1744}
1736 1745
1737static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel, 1746static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
1747 union perf_event *event __maybe_unused,
1738 struct perf_sample *sample) 1748 struct perf_sample *sample)
1739{ 1749{
1740 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname"); 1750 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
@@ -1742,6 +1752,7 @@ static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
1742} 1752}
1743 1753
1744static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel, 1754static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1755 union perf_event *event __maybe_unused,
1745 struct perf_sample *sample) 1756 struct perf_sample *sample)
1746{ 1757{
1747 u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); 1758 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
@@ -1768,6 +1779,80 @@ out_dump:
1768 return 0; 1779 return 0;
1769} 1780}
1770 1781
1782static void print_location(FILE *f, struct perf_sample *sample,
1783 struct addr_location *al,
1784 bool print_dso, bool print_sym)
1785{
1786
1787 if ((verbose || print_dso) && al->map)
1788 fprintf(f, "%s@", al->map->dso->long_name);
1789
1790 if ((verbose || print_sym) && al->sym)
1791 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
1792 al->addr - al->sym->start);
1793 else if (al->map)
1794 fprintf(f, "0x%" PRIx64, al->addr);
1795 else
1796 fprintf(f, "0x%" PRIx64, sample->addr);
1797}
1798
1799static int trace__pgfault(struct trace *trace,
1800 struct perf_evsel *evsel,
1801 union perf_event *event,
1802 struct perf_sample *sample)
1803{
1804 struct thread *thread;
1805 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1806 struct addr_location al;
1807 char map_type = 'd';
1808 struct thread_trace *ttrace;
1809
1810 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1811 ttrace = thread__trace(thread, trace->output);
1812 if (ttrace == NULL)
1813 return -1;
1814
1815 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1816 ttrace->pfmaj++;
1817 else
1818 ttrace->pfmin++;
1819
1820 if (trace->summary_only)
1821 return 0;
1822
1823 thread__find_addr_location(thread, trace->host, cpumode, MAP__FUNCTION,
1824 sample->ip, &al);
1825
1826 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
1827
1828 fprintf(trace->output, "%sfault [",
1829 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1830 "maj" : "min");
1831
1832 print_location(trace->output, sample, &al, false, true);
1833
1834 fprintf(trace->output, "] => ");
1835
1836 thread__find_addr_location(thread, trace->host, cpumode, MAP__VARIABLE,
1837 sample->addr, &al);
1838
1839 if (!al.map) {
1840 thread__find_addr_location(thread, trace->host, cpumode,
1841 MAP__FUNCTION, sample->addr, &al);
1842
1843 if (al.map)
1844 map_type = 'x';
1845 else
1846 map_type = '?';
1847 }
1848
1849 print_location(trace->output, sample, &al, true, false);
1850
1851 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
1852
1853 return 0;
1854}
1855
1771static bool skip_sample(struct trace *trace, struct perf_sample *sample) 1856static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1772{ 1857{
1773 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) || 1858 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
@@ -1781,7 +1866,7 @@ static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1781} 1866}
1782 1867
1783static int trace__process_sample(struct perf_tool *tool, 1868static int trace__process_sample(struct perf_tool *tool,
1784 union perf_event *event __maybe_unused, 1869 union perf_event *event,
1785 struct perf_sample *sample, 1870 struct perf_sample *sample,
1786 struct perf_evsel *evsel, 1871 struct perf_evsel *evsel,
1787 struct machine *machine __maybe_unused) 1872 struct machine *machine __maybe_unused)
@@ -1799,7 +1884,7 @@ static int trace__process_sample(struct perf_tool *tool,
1799 1884
1800 if (handler) { 1885 if (handler) {
1801 ++trace->nr_events; 1886 ++trace->nr_events;
1802 handler(trace, evsel, sample); 1887 handler(trace, evsel, event, sample);
1803 } 1888 }
1804 1889
1805 return err; 1890 return err;
@@ -1826,7 +1911,7 @@ static int parse_target_str(struct trace *trace)
1826 return 0; 1911 return 0;
1827} 1912}
1828 1913
1829static int trace__record(int argc, const char **argv) 1914static int trace__record(struct trace *trace, int argc, const char **argv)
1830{ 1915{
1831 unsigned int rec_argc, i, j; 1916 unsigned int rec_argc, i, j;
1832 const char **rec_argv; 1917 const char **rec_argv;
@@ -1835,34 +1920,54 @@ static int trace__record(int argc, const char **argv)
1835 "-R", 1920 "-R",
1836 "-m", "1024", 1921 "-m", "1024",
1837 "-c", "1", 1922 "-c", "1",
1838 "-e",
1839 }; 1923 };
1840 1924
1925 const char * const sc_args[] = { "-e", };
1926 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
1927 const char * const majpf_args[] = { "-e", "major-faults" };
1928 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
1929 const char * const minpf_args[] = { "-e", "minor-faults" };
1930 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
1931
1841 /* +1 is for the event string below */ 1932 /* +1 is for the event string below */
1842 rec_argc = ARRAY_SIZE(record_args) + 1 + argc; 1933 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
1934 majpf_args_nr + minpf_args_nr + argc;
1843 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 1935 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1844 1936
1845 if (rec_argv == NULL) 1937 if (rec_argv == NULL)
1846 return -ENOMEM; 1938 return -ENOMEM;
1847 1939
1940 j = 0;
1848 for (i = 0; i < ARRAY_SIZE(record_args); i++) 1941 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1849 rec_argv[i] = record_args[i]; 1942 rec_argv[j++] = record_args[i];
1850 1943
1851 /* event string may be different for older kernels - e.g., RHEL6 */ 1944 if (trace->trace_syscalls) {
1852 if (is_valid_tracepoint("raw_syscalls:sys_enter")) 1945 for (i = 0; i < sc_args_nr; i++)
1853 rec_argv[i] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit"; 1946 rec_argv[j++] = sc_args[i];
1854 else if (is_valid_tracepoint("syscalls:sys_enter")) 1947
1855 rec_argv[i] = "syscalls:sys_enter,syscalls:sys_exit"; 1948 /* event string may be different for older kernels - e.g., RHEL6 */
1856 else { 1949 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
1857 pr_err("Neither raw_syscalls nor syscalls events exist.\n"); 1950 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
1858 return -1; 1951 else if (is_valid_tracepoint("syscalls:sys_enter"))
1952 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
1953 else {
1954 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
1955 return -1;
1956 }
1859 } 1957 }
1860 i++;
1861 1958
1862 for (j = 0; j < (unsigned int)argc; j++, i++) 1959 if (trace->trace_pgfaults & TRACE_PFMAJ)
1863 rec_argv[i] = argv[j]; 1960 for (i = 0; i < majpf_args_nr; i++)
1961 rec_argv[j++] = majpf_args[i];
1962
1963 if (trace->trace_pgfaults & TRACE_PFMIN)
1964 for (i = 0; i < minpf_args_nr; i++)
1965 rec_argv[j++] = minpf_args[i];
1966
1967 for (i = 0; i < (unsigned int)argc; i++)
1968 rec_argv[j++] = argv[i];
1864 1969
1865 return cmd_record(i, rec_argv, NULL); 1970 return cmd_record(j, rec_argv, NULL);
1866} 1971}
1867 1972
1868static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp); 1973static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
@@ -1882,6 +1987,30 @@ static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
1882 perf_evlist__add(evlist, evsel); 1987 perf_evlist__add(evlist, evsel);
1883} 1988}
1884 1989
1990static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
1991 u64 config)
1992{
1993 struct perf_evsel *evsel;
1994 struct perf_event_attr attr = {
1995 .type = PERF_TYPE_SOFTWARE,
1996 .mmap_data = 1,
1997 };
1998
1999 attr.config = config;
2000 attr.sample_period = 1;
2001
2002 event_attr_init(&attr);
2003
2004 evsel = perf_evsel__new(&attr);
2005 if (!evsel)
2006 return -ENOMEM;
2007
2008 evsel->handler = trace__pgfault;
2009 perf_evlist__add(evlist, evsel);
2010
2011 return 0;
2012}
2013
1885static int trace__run(struct trace *trace, int argc, const char **argv) 2014static int trace__run(struct trace *trace, int argc, const char **argv)
1886{ 2015{
1887 struct perf_evlist *evlist = perf_evlist__new(); 2016 struct perf_evlist *evlist = perf_evlist__new();
@@ -1897,10 +2026,21 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
1897 goto out; 2026 goto out;
1898 } 2027 }
1899 2028
1900 if (perf_evlist__add_syscall_newtp(evlist, trace__sys_enter, trace__sys_exit)) 2029 if (trace->trace_syscalls &&
2030 perf_evlist__add_syscall_newtp(evlist, trace__sys_enter,
2031 trace__sys_exit))
1901 goto out_error_tp; 2032 goto out_error_tp;
1902 2033
1903 perf_evlist__add_vfs_getname(evlist); 2034 if (trace->trace_syscalls)
2035 perf_evlist__add_vfs_getname(evlist);
2036
2037 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
2038 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ))
2039 goto out_error_tp;
2040
2041 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2042 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
2043 goto out_error_tp;
1904 2044
1905 if (trace->sched && 2045 if (trace->sched &&
1906 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime", 2046 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
@@ -1982,7 +2122,8 @@ again:
1982 goto next_event; 2122 goto next_event;
1983 } 2123 }
1984 2124
1985 if (sample.raw_data == NULL) { 2125 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2126 sample.raw_data == NULL) {
1986 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", 2127 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, 2128 perf_evsel__name(evsel), sample.tid,
1988 sample.cpu, sample.raw_size); 2129 sample.cpu, sample.raw_size);
@@ -1990,7 +2131,7 @@ again:
1990 } 2131 }
1991 2132
1992 handler = evsel->handler; 2133 handler = evsel->handler;
1993 handler(trace, evsel, &sample); 2134 handler(trace, evsel, event, &sample);
1994next_event: 2135next_event:
1995 perf_evlist__mmap_consume(evlist, i); 2136 perf_evlist__mmap_consume(evlist, i);
1996 2137
@@ -2093,13 +2234,10 @@ static int trace__replay(struct trace *trace)
2093 if (evsel == NULL) 2234 if (evsel == NULL)
2094 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, 2235 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2095 "syscalls:sys_enter"); 2236 "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 2237
2101 if (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 || 2238 if (evsel &&
2102 perf_evsel__init_sc_tp_ptr_field(evsel, args)) { 2239 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2240 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
2103 pr_err("Error during initialize raw_syscalls:sys_enter event\n"); 2241 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2104 goto out; 2242 goto out;
2105 } 2243 }
@@ -2109,15 +2247,19 @@ static int trace__replay(struct trace *trace)
2109 if (evsel == NULL) 2247 if (evsel == NULL)
2110 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, 2248 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2111 "syscalls:sys_exit"); 2249 "syscalls:sys_exit");
2112 if (evsel == NULL) { 2250 if (evsel &&
2113 pr_err("Data file does not have raw_syscalls:sys_exit event\n"); 2251 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2252 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
2253 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
2114 goto out; 2254 goto out;
2115 } 2255 }
2116 2256
2117 if (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 || 2257 evlist__for_each(session->evlist, evsel) {
2118 perf_evsel__init_sc_tp_uint_field(evsel, ret)) { 2258 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2119 pr_err("Error during initialize raw_syscalls:sys_exit event\n"); 2259 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2120 goto out; 2260 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2261 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2262 evsel->handler = trace__pgfault;
2121 } 2263 }
2122 2264
2123 err = parse_target_str(trace); 2265 err = parse_target_str(trace);
@@ -2217,6 +2359,10 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2217 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid); 2359 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
2218 printed += fprintf(fp, "%lu events, ", ttrace->nr_events); 2360 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
2219 printed += fprintf(fp, "%.1f%%", ratio); 2361 printed += fprintf(fp, "%.1f%%", ratio);
2362 if (ttrace->pfmaj)
2363 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2364 if (ttrace->pfmin)
2365 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
2220 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms); 2366 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2221 printed += thread__dump_stats(ttrace, trace, fp); 2367 printed += thread__dump_stats(ttrace, trace, fp);
2222 2368
@@ -2264,6 +2410,23 @@ static int trace__open_output(struct trace *trace, const char *filename)
2264 return trace->output == NULL ? -errno : 0; 2410 return trace->output == NULL ? -errno : 0;
2265} 2411}
2266 2412
2413static int parse_pagefaults(const struct option *opt, const char *str,
2414 int unset __maybe_unused)
2415{
2416 int *trace_pgfaults = opt->value;
2417
2418 if (strcmp(str, "all") == 0)
2419 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2420 else if (strcmp(str, "maj") == 0)
2421 *trace_pgfaults |= TRACE_PFMAJ;
2422 else if (strcmp(str, "min") == 0)
2423 *trace_pgfaults |= TRACE_PFMIN;
2424 else
2425 return -1;
2426
2427 return 0;
2428}
2429
2267int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) 2430int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2268{ 2431{
2269 const char * const trace_usage[] = { 2432 const char * const trace_usage[] = {
@@ -2293,6 +2456,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2293 }, 2456 },
2294 .output = stdout, 2457 .output = stdout,
2295 .show_comm = true, 2458 .show_comm = true,
2459 .trace_syscalls = true,
2296 }; 2460 };
2297 const char *output_name = NULL; 2461 const char *output_name = NULL;
2298 const char *ev_qualifier_str = NULL; 2462 const char *ev_qualifier_str = NULL;
@@ -2330,20 +2494,34 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2330 "Show only syscall summary with statistics"), 2494 "Show only syscall summary with statistics"),
2331 OPT_BOOLEAN('S', "with-summary", &trace.summary, 2495 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2332 "Show all syscalls and summary with statistics"), 2496 "Show all syscalls and summary with statistics"),
2497 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2498 "Trace pagefaults", parse_pagefaults, "maj"),
2499 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
2333 OPT_END() 2500 OPT_END()
2334 }; 2501 };
2335 int err; 2502 int err;
2336 char bf[BUFSIZ]; 2503 char bf[BUFSIZ];
2337 2504
2338 if ((argc > 1) && (strcmp(argv[1], "record") == 0)) 2505 argc = parse_options(argc, argv, trace_options, trace_usage,
2339 return trace__record(argc-2, &argv[2]); 2506 PARSE_OPT_STOP_AT_NON_OPTION);
2340 2507
2341 argc = parse_options(argc, argv, trace_options, trace_usage, 0); 2508 if (trace.trace_pgfaults) {
2509 trace.opts.sample_address = true;
2510 trace.opts.sample_time = true;
2511 }
2512
2513 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2514 return trace__record(&trace, argc-1, &argv[1]);
2342 2515
2343 /* summary_only implies summary option, but don't overwrite summary if set */ 2516 /* summary_only implies summary option, but don't overwrite summary if set */
2344 if (trace.summary_only) 2517 if (trace.summary_only)
2345 trace.summary = trace.summary_only; 2518 trace.summary = trace.summary_only;
2346 2519
2520 if (!trace.trace_syscalls && !trace.trace_pgfaults) {
2521 pr_err("Please specify something to trace.\n");
2522 return -1;
2523 }
2524
2347 if (output_name != NULL) { 2525 if (output_name != NULL) {
2348 err = trace__open_output(&trace, output_name); 2526 err = trace__open_output(&trace, output_name);
2349 if (err < 0) { 2527 if (err < 0) {