diff options
Diffstat (limited to 'tools')
28 files changed, 487 insertions, 146 deletions
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt index 13293de8869f..1bbcf305d233 100644 --- a/tools/perf/Documentation/perf-trace.txt +++ b/tools/perf/Documentation/perf-trace.txt | |||
| @@ -117,6 +117,15 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs. | |||
| 117 | --syscalls:: | 117 | --syscalls:: |
| 118 | Trace system calls. This options is enabled by default. | 118 | Trace system calls. This options is enabled by default. |
| 119 | 119 | ||
| 120 | --call-graph [mode,type,min[,limit],order[,key][,branch]]:: | ||
| 121 | Setup and enable call-graph (stack chain/backtrace) recording. | ||
| 122 | See `--call-graph` section in perf-record and perf-report | ||
| 123 | man pages for details. The ones that are most useful in 'perf trace' | ||
| 124 | are 'dwarf' and 'lbr', where available, try: 'perf trace --call-graph dwarf'. | ||
| 125 | |||
| 126 | --kernel-syscall-graph:: | ||
| 127 | Show the kernel callchains on the syscall exit path. | ||
| 128 | |||
| 120 | --event:: | 129 | --event:: |
| 121 | Trace other events, see 'perf list' for a complete list. | 130 | Trace other events, see 'perf list' for a complete list. |
| 122 | 131 | ||
diff --git a/tools/perf/arch/x86/tests/perf-time-to-tsc.c b/tools/perf/arch/x86/tests/perf-time-to-tsc.c index 9d29ee283ac5..d4aa567a29c4 100644 --- a/tools/perf/arch/x86/tests/perf-time-to-tsc.c +++ b/tools/perf/arch/x86/tests/perf-time-to-tsc.c | |||
| @@ -71,7 +71,7 @@ int test__perf_time_to_tsc(int subtest __maybe_unused) | |||
| 71 | 71 | ||
| 72 | CHECK__(parse_events(evlist, "cycles:u", NULL)); | 72 | CHECK__(parse_events(evlist, "cycles:u", NULL)); |
| 73 | 73 | ||
| 74 | perf_evlist__config(evlist, &opts); | 74 | perf_evlist__config(evlist, &opts, NULL); |
| 75 | 75 | ||
| 76 | evsel = perf_evlist__first(evlist); | 76 | evsel = perf_evlist__first(evlist); |
| 77 | 77 | ||
diff --git a/tools/perf/arch/x86/util/dwarf-regs.c b/tools/perf/arch/x86/util/dwarf-regs.c index 9223c164e545..1f86ee8fb831 100644 --- a/tools/perf/arch/x86/util/dwarf-regs.c +++ b/tools/perf/arch/x86/util/dwarf-regs.c | |||
| @@ -63,6 +63,8 @@ struct pt_regs_offset { | |||
| 63 | # define REG_OFFSET_NAME_32(n, r) {.name = n, .offset = offsetof(struct pt_regs, r)} | 63 | # define REG_OFFSET_NAME_32(n, r) {.name = n, .offset = offsetof(struct pt_regs, r)} |
| 64 | #endif | 64 | #endif |
| 65 | 65 | ||
| 66 | /* TODO: switching by dwarf address size */ | ||
| 67 | #ifndef __x86_64__ | ||
| 66 | static const struct pt_regs_offset x86_32_regoffset_table[] = { | 68 | static const struct pt_regs_offset x86_32_regoffset_table[] = { |
| 67 | REG_OFFSET_NAME_32("%ax", eax), | 69 | REG_OFFSET_NAME_32("%ax", eax), |
| 68 | REG_OFFSET_NAME_32("%cx", ecx), | 70 | REG_OFFSET_NAME_32("%cx", ecx), |
| @@ -75,6 +77,8 @@ static const struct pt_regs_offset x86_32_regoffset_table[] = { | |||
| 75 | REG_OFFSET_END, | 77 | REG_OFFSET_END, |
| 76 | }; | 78 | }; |
| 77 | 79 | ||
| 80 | #define regoffset_table x86_32_regoffset_table | ||
| 81 | #else | ||
| 78 | static const struct pt_regs_offset x86_64_regoffset_table[] = { | 82 | static const struct pt_regs_offset x86_64_regoffset_table[] = { |
| 79 | REG_OFFSET_NAME_64("%ax", rax), | 83 | REG_OFFSET_NAME_64("%ax", rax), |
| 80 | REG_OFFSET_NAME_64("%dx", rdx), | 84 | REG_OFFSET_NAME_64("%dx", rdx), |
| @@ -95,11 +99,7 @@ static const struct pt_regs_offset x86_64_regoffset_table[] = { | |||
| 95 | REG_OFFSET_END, | 99 | REG_OFFSET_END, |
| 96 | }; | 100 | }; |
| 97 | 101 | ||
| 98 | /* TODO: switching by dwarf address size */ | ||
| 99 | #ifdef __x86_64__ | ||
| 100 | #define regoffset_table x86_64_regoffset_table | 102 | #define regoffset_table x86_64_regoffset_table |
| 101 | #else | ||
| 102 | #define regoffset_table x86_32_regoffset_table | ||
| 103 | #endif | 103 | #endif |
| 104 | 104 | ||
| 105 | /* Minus 1 for the ending REG_OFFSET_END */ | 105 | /* Minus 1 for the ending REG_OFFSET_END */ |
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index bff666458b28..6487c06d2708 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c | |||
| @@ -982,7 +982,7 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm) | |||
| 982 | struct perf_evlist *evlist = kvm->evlist; | 982 | struct perf_evlist *evlist = kvm->evlist; |
| 983 | char sbuf[STRERR_BUFSIZE]; | 983 | char sbuf[STRERR_BUFSIZE]; |
| 984 | 984 | ||
| 985 | perf_evlist__config(evlist, &kvm->opts); | 985 | perf_evlist__config(evlist, &kvm->opts, NULL); |
| 986 | 986 | ||
| 987 | /* | 987 | /* |
| 988 | * Note: exclude_{guest,host} do not apply here. | 988 | * Note: exclude_{guest,host} do not apply here. |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 410035c6e300..eb6a199a833c 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
| @@ -284,7 +284,7 @@ static int record__open(struct record *rec) | |||
| 284 | struct record_opts *opts = &rec->opts; | 284 | struct record_opts *opts = &rec->opts; |
| 285 | int rc = 0; | 285 | int rc = 0; |
| 286 | 286 | ||
| 287 | perf_evlist__config(evlist, opts); | 287 | perf_evlist__config(evlist, opts, &callchain_param); |
| 288 | 288 | ||
| 289 | evlist__for_each(evlist, pos) { | 289 | evlist__for_each(evlist, pos) { |
| 290 | try_again: | 290 | try_again: |
| @@ -1276,6 +1276,14 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 1276 | if (err) | 1276 | if (err) |
| 1277 | return err; | 1277 | return err; |
| 1278 | 1278 | ||
| 1279 | err = bpf__setup_stdout(rec->evlist); | ||
| 1280 | if (err) { | ||
| 1281 | bpf__strerror_setup_stdout(rec->evlist, err, errbuf, sizeof(errbuf)); | ||
| 1282 | pr_err("ERROR: Setup BPF stdout failed: %s\n", | ||
| 1283 | errbuf); | ||
| 1284 | return err; | ||
| 1285 | } | ||
| 1286 | |||
| 1279 | err = -ENOMEM; | 1287 | err = -ENOMEM; |
| 1280 | 1288 | ||
| 1281 | symbol__init(NULL); | 1289 | symbol__init(NULL); |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 59009aa7e2ca..ddd5b79e94c2 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
| @@ -579,8 +579,8 @@ static void print_sample_bts(struct perf_sample *sample, | |||
| 579 | print_opts &= ~PRINT_IP_OPT_SRCLINE; | 579 | print_opts &= ~PRINT_IP_OPT_SRCLINE; |
| 580 | } | 580 | } |
| 581 | } | 581 | } |
| 582 | perf_evsel__print_ip(evsel, sample, al, print_opts, | 582 | perf_evsel__fprintf_sym(evsel, sample, al, 0, print_opts, |
| 583 | scripting_max_stack); | 583 | scripting_max_stack, stdout); |
| 584 | } | 584 | } |
| 585 | 585 | ||
| 586 | /* print branch_to information */ | 586 | /* print branch_to information */ |
| @@ -788,9 +788,9 @@ static void process_event(struct perf_script *script, | |||
| 788 | else | 788 | else |
| 789 | printf("\n"); | 789 | printf("\n"); |
| 790 | 790 | ||
| 791 | perf_evsel__print_ip(evsel, sample, al, | 791 | perf_evsel__fprintf_sym(evsel, sample, al, 0, |
| 792 | output[attr->type].print_ip_opts, | 792 | output[attr->type].print_ip_opts, |
| 793 | scripting_max_stack); | 793 | scripting_max_stack, stdout); |
| 794 | } | 794 | } |
| 795 | 795 | ||
| 796 | if (PRINT_FIELD(IREGS)) | 796 | if (PRINT_FIELD(IREGS)) |
| @@ -1415,21 +1415,19 @@ static int is_directory(const char *base_path, const struct dirent *dent) | |||
| 1415 | return S_ISDIR(st.st_mode); | 1415 | return S_ISDIR(st.st_mode); |
| 1416 | } | 1416 | } |
| 1417 | 1417 | ||
| 1418 | #define for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next)\ | 1418 | #define for_each_lang(scripts_path, scripts_dir, lang_dirent) \ |
| 1419 | while (!readdir_r(scripts_dir, &lang_dirent, &lang_next) && \ | 1419 | while ((lang_dirent = readdir(scripts_dir)) != NULL) \ |
| 1420 | lang_next) \ | 1420 | if ((lang_dirent->d_type == DT_DIR || \ |
| 1421 | if ((lang_dirent.d_type == DT_DIR || \ | 1421 | (lang_dirent->d_type == DT_UNKNOWN && \ |
| 1422 | (lang_dirent.d_type == DT_UNKNOWN && \ | 1422 | is_directory(scripts_path, lang_dirent))) && \ |
| 1423 | is_directory(scripts_path, &lang_dirent))) && \ | 1423 | (strcmp(lang_dirent->d_name, ".")) && \ |
| 1424 | (strcmp(lang_dirent.d_name, ".")) && \ | 1424 | (strcmp(lang_dirent->d_name, ".."))) |
| 1425 | (strcmp(lang_dirent.d_name, ".."))) | ||
| 1426 | 1425 | ||
| 1427 | #define for_each_script(lang_path, lang_dir, script_dirent, script_next)\ | 1426 | #define for_each_script(lang_path, lang_dir, script_dirent) \ |
| 1428 | while (!readdir_r(lang_dir, &script_dirent, &script_next) && \ | 1427 | while ((script_dirent = readdir(lang_dir)) != NULL) \ |
| 1429 | script_next) \ | 1428 | if (script_dirent->d_type != DT_DIR && \ |
| 1430 | if (script_dirent.d_type != DT_DIR && \ | 1429 | (script_dirent->d_type != DT_UNKNOWN || \ |
| 1431 | (script_dirent.d_type != DT_UNKNOWN || \ | 1430 | !is_directory(lang_path, script_dirent))) |
| 1432 | !is_directory(lang_path, &script_dirent))) | ||
| 1433 | 1431 | ||
| 1434 | 1432 | ||
| 1435 | #define RECORD_SUFFIX "-record" | 1433 | #define RECORD_SUFFIX "-record" |
| @@ -1575,7 +1573,7 @@ static int list_available_scripts(const struct option *opt __maybe_unused, | |||
| 1575 | const char *s __maybe_unused, | 1573 | const char *s __maybe_unused, |
| 1576 | int unset __maybe_unused) | 1574 | int unset __maybe_unused) |
| 1577 | { | 1575 | { |
| 1578 | struct dirent *script_next, *lang_next, script_dirent, lang_dirent; | 1576 | struct dirent *script_dirent, *lang_dirent; |
| 1579 | char scripts_path[MAXPATHLEN]; | 1577 | char scripts_path[MAXPATHLEN]; |
| 1580 | DIR *scripts_dir, *lang_dir; | 1578 | DIR *scripts_dir, *lang_dir; |
| 1581 | char script_path[MAXPATHLEN]; | 1579 | char script_path[MAXPATHLEN]; |
| @@ -1590,19 +1588,19 @@ static int list_available_scripts(const struct option *opt __maybe_unused, | |||
| 1590 | if (!scripts_dir) | 1588 | if (!scripts_dir) |
| 1591 | return -1; | 1589 | return -1; |
| 1592 | 1590 | ||
| 1593 | for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) { | 1591 | for_each_lang(scripts_path, scripts_dir, lang_dirent) { |
| 1594 | snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, | 1592 | snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, |
| 1595 | lang_dirent.d_name); | 1593 | lang_dirent->d_name); |
| 1596 | lang_dir = opendir(lang_path); | 1594 | lang_dir = opendir(lang_path); |
| 1597 | if (!lang_dir) | 1595 | if (!lang_dir) |
| 1598 | continue; | 1596 | continue; |
| 1599 | 1597 | ||
| 1600 | for_each_script(lang_path, lang_dir, script_dirent, script_next) { | 1598 | for_each_script(lang_path, lang_dir, script_dirent) { |
| 1601 | script_root = get_script_root(&script_dirent, REPORT_SUFFIX); | 1599 | script_root = get_script_root(script_dirent, REPORT_SUFFIX); |
| 1602 | if (script_root) { | 1600 | if (script_root) { |
| 1603 | desc = script_desc__findnew(script_root); | 1601 | desc = script_desc__findnew(script_root); |
| 1604 | snprintf(script_path, MAXPATHLEN, "%s/%s", | 1602 | snprintf(script_path, MAXPATHLEN, "%s/%s", |
| 1605 | lang_path, script_dirent.d_name); | 1603 | lang_path, script_dirent->d_name); |
| 1606 | read_script_info(desc, script_path); | 1604 | read_script_info(desc, script_path); |
| 1607 | free(script_root); | 1605 | free(script_root); |
| 1608 | } | 1606 | } |
| @@ -1690,7 +1688,7 @@ static int check_ev_match(char *dir_name, char *scriptname, | |||
| 1690 | */ | 1688 | */ |
| 1691 | int find_scripts(char **scripts_array, char **scripts_path_array) | 1689 | int find_scripts(char **scripts_array, char **scripts_path_array) |
| 1692 | { | 1690 | { |
| 1693 | struct dirent *script_next, *lang_next, script_dirent, lang_dirent; | 1691 | struct dirent *script_dirent, *lang_dirent; |
| 1694 | char scripts_path[MAXPATHLEN], lang_path[MAXPATHLEN]; | 1692 | char scripts_path[MAXPATHLEN], lang_path[MAXPATHLEN]; |
| 1695 | DIR *scripts_dir, *lang_dir; | 1693 | DIR *scripts_dir, *lang_dir; |
| 1696 | struct perf_session *session; | 1694 | struct perf_session *session; |
| @@ -1713,9 +1711,9 @@ int find_scripts(char **scripts_array, char **scripts_path_array) | |||
| 1713 | return -1; | 1711 | return -1; |
| 1714 | } | 1712 | } |
| 1715 | 1713 | ||
| 1716 | for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) { | 1714 | for_each_lang(scripts_path, scripts_dir, lang_dirent) { |
| 1717 | snprintf(lang_path, MAXPATHLEN, "%s/%s", scripts_path, | 1715 | snprintf(lang_path, MAXPATHLEN, "%s/%s", scripts_path, |
| 1718 | lang_dirent.d_name); | 1716 | lang_dirent->d_name); |
| 1719 | #ifdef NO_LIBPERL | 1717 | #ifdef NO_LIBPERL |
| 1720 | if (strstr(lang_path, "perl")) | 1718 | if (strstr(lang_path, "perl")) |
| 1721 | continue; | 1719 | continue; |
| @@ -1729,16 +1727,16 @@ int find_scripts(char **scripts_array, char **scripts_path_array) | |||
| 1729 | if (!lang_dir) | 1727 | if (!lang_dir) |
| 1730 | continue; | 1728 | continue; |
| 1731 | 1729 | ||
| 1732 | for_each_script(lang_path, lang_dir, script_dirent, script_next) { | 1730 | for_each_script(lang_path, lang_dir, script_dirent) { |
| 1733 | /* Skip those real time scripts: xxxtop.p[yl] */ | 1731 | /* Skip those real time scripts: xxxtop.p[yl] */ |
| 1734 | if (strstr(script_dirent.d_name, "top.")) | 1732 | if (strstr(script_dirent->d_name, "top.")) |
| 1735 | continue; | 1733 | continue; |
| 1736 | sprintf(scripts_path_array[i], "%s/%s", lang_path, | 1734 | sprintf(scripts_path_array[i], "%s/%s", lang_path, |
| 1737 | script_dirent.d_name); | 1735 | script_dirent->d_name); |
| 1738 | temp = strchr(script_dirent.d_name, '.'); | 1736 | temp = strchr(script_dirent->d_name, '.'); |
| 1739 | snprintf(scripts_array[i], | 1737 | snprintf(scripts_array[i], |
| 1740 | (temp - script_dirent.d_name) + 1, | 1738 | (temp - script_dirent->d_name) + 1, |
| 1741 | "%s", script_dirent.d_name); | 1739 | "%s", script_dirent->d_name); |
| 1742 | 1740 | ||
| 1743 | if (check_ev_match(lang_path, | 1741 | if (check_ev_match(lang_path, |
| 1744 | scripts_array[i], session)) | 1742 | scripts_array[i], session)) |
| @@ -1756,7 +1754,7 @@ int find_scripts(char **scripts_array, char **scripts_path_array) | |||
| 1756 | 1754 | ||
| 1757 | static char *get_script_path(const char *script_root, const char *suffix) | 1755 | static char *get_script_path(const char *script_root, const char *suffix) |
| 1758 | { | 1756 | { |
| 1759 | struct dirent *script_next, *lang_next, script_dirent, lang_dirent; | 1757 | struct dirent *script_dirent, *lang_dirent; |
| 1760 | char scripts_path[MAXPATHLEN]; | 1758 | char scripts_path[MAXPATHLEN]; |
| 1761 | char script_path[MAXPATHLEN]; | 1759 | char script_path[MAXPATHLEN]; |
| 1762 | DIR *scripts_dir, *lang_dir; | 1760 | DIR *scripts_dir, *lang_dir; |
| @@ -1769,21 +1767,21 @@ static char *get_script_path(const char *script_root, const char *suffix) | |||
| 1769 | if (!scripts_dir) | 1767 | if (!scripts_dir) |
| 1770 | return NULL; | 1768 | return NULL; |
| 1771 | 1769 | ||
| 1772 | for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) { | 1770 | for_each_lang(scripts_path, scripts_dir, lang_dirent) { |
| 1773 | snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, | 1771 | snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, |
| 1774 | lang_dirent.d_name); | 1772 | lang_dirent->d_name); |
| 1775 | lang_dir = opendir(lang_path); | 1773 | lang_dir = opendir(lang_path); |
| 1776 | if (!lang_dir) | 1774 | if (!lang_dir) |
| 1777 | continue; | 1775 | continue; |
| 1778 | 1776 | ||
| 1779 | for_each_script(lang_path, lang_dir, script_dirent, script_next) { | 1777 | for_each_script(lang_path, lang_dir, script_dirent) { |
| 1780 | __script_root = get_script_root(&script_dirent, suffix); | 1778 | __script_root = get_script_root(script_dirent, suffix); |
| 1781 | if (__script_root && !strcmp(script_root, __script_root)) { | 1779 | if (__script_root && !strcmp(script_root, __script_root)) { |
| 1782 | free(__script_root); | 1780 | free(__script_root); |
| 1783 | closedir(lang_dir); | 1781 | closedir(lang_dir); |
| 1784 | closedir(scripts_dir); | 1782 | closedir(scripts_dir); |
| 1785 | snprintf(script_path, MAXPATHLEN, "%s/%s", | 1783 | snprintf(script_path, MAXPATHLEN, "%s/%s", |
| 1786 | lang_path, script_dirent.d_name); | 1784 | lang_path, script_dirent->d_name); |
| 1787 | return strdup(script_path); | 1785 | return strdup(script_path); |
| 1788 | } | 1786 | } |
| 1789 | free(__script_root); | 1787 | free(__script_root); |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 833214979c4f..8846df0ec0c3 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
| @@ -886,7 +886,7 @@ static int perf_top__start_counters(struct perf_top *top) | |||
| 886 | struct perf_evlist *evlist = top->evlist; | 886 | struct perf_evlist *evlist = top->evlist; |
| 887 | struct record_opts *opts = &top->record_opts; | 887 | struct record_opts *opts = &top->record_opts; |
| 888 | 888 | ||
| 889 | perf_evlist__config(evlist, opts); | 889 | perf_evlist__config(evlist, opts, &callchain_param); |
| 890 | 890 | ||
| 891 | evlist__for_each(evlist, counter) { | 891 | evlist__for_each(evlist, counter) { |
| 892 | try_again: | 892 | try_again: |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 11290b57ce04..2ec53edcf649 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
| @@ -34,6 +34,7 @@ | |||
| 34 | #include "trace-event.h" | 34 | #include "trace-event.h" |
| 35 | #include "util/parse-events.h" | 35 | #include "util/parse-events.h" |
| 36 | #include "util/bpf-loader.h" | 36 | #include "util/bpf-loader.h" |
| 37 | #include "callchain.h" | ||
| 37 | #include "syscalltbl.h" | 38 | #include "syscalltbl.h" |
| 38 | 39 | ||
| 39 | #include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */ | 40 | #include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */ |
| @@ -158,6 +159,7 @@ struct trace { | |||
| 158 | bool show_comm; | 159 | bool show_comm; |
| 159 | bool show_tool_stats; | 160 | bool show_tool_stats; |
| 160 | bool trace_syscalls; | 161 | bool trace_syscalls; |
| 162 | bool kernel_syscallchains; | ||
| 161 | bool force; | 163 | bool force; |
| 162 | bool vfs_getname; | 164 | bool vfs_getname; |
| 163 | int trace_pgfaults; | 165 | int trace_pgfaults; |
| @@ -2190,6 +2192,22 @@ signed_print: | |||
| 2190 | goto signed_print; | 2192 | goto signed_print; |
| 2191 | 2193 | ||
| 2192 | fputc('\n', trace->output); | 2194 | fputc('\n', trace->output); |
| 2195 | |||
| 2196 | if (sample->callchain) { | ||
| 2197 | struct addr_location al; | ||
| 2198 | /* TODO: user-configurable print_opts */ | ||
| 2199 | const unsigned int print_opts = PRINT_IP_OPT_SYM | | ||
| 2200 | PRINT_IP_OPT_DSO | | ||
| 2201 | PRINT_IP_OPT_UNKNOWN_AS_ADDR; | ||
| 2202 | |||
| 2203 | if (machine__resolve(trace->host, &al, sample) < 0) { | ||
| 2204 | pr_err("problem processing %d event, skipping it.\n", | ||
| 2205 | event->header.type); | ||
| 2206 | goto out_put; | ||
| 2207 | } | ||
| 2208 | perf_evsel__fprintf_callchain(evsel, sample, &al, 38, print_opts, | ||
| 2209 | scripting_max_stack, trace->output); | ||
| 2210 | } | ||
| 2193 | out: | 2211 | out: |
| 2194 | ttrace->entry_pending = false; | 2212 | ttrace->entry_pending = false; |
| 2195 | err = 0; | 2213 | err = 0; |
| @@ -2645,6 +2663,15 @@ static int trace__add_syscall_newtp(struct trace *trace) | |||
| 2645 | perf_evlist__add(evlist, sys_enter); | 2663 | perf_evlist__add(evlist, sys_enter); |
| 2646 | perf_evlist__add(evlist, sys_exit); | 2664 | perf_evlist__add(evlist, sys_exit); |
| 2647 | 2665 | ||
| 2666 | if (trace->opts.callgraph_set && !trace->kernel_syscallchains) { | ||
| 2667 | /* | ||
| 2668 | * We're interested only in the user space callchain | ||
| 2669 | * leading to the syscall, allow overriding that for | ||
| 2670 | * debugging reasons using --kernel_syscall_callchains | ||
| 2671 | */ | ||
| 2672 | sys_exit->attr.exclude_callchain_kernel = 1; | ||
| 2673 | } | ||
| 2674 | |||
| 2648 | trace->syscalls.events.sys_enter = sys_enter; | 2675 | trace->syscalls.events.sys_enter = sys_enter; |
| 2649 | trace->syscalls.events.sys_exit = sys_exit; | 2676 | trace->syscalls.events.sys_exit = sys_exit; |
| 2650 | 2677 | ||
| @@ -2723,7 +2750,27 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
| 2723 | goto out_delete_evlist; | 2750 | goto out_delete_evlist; |
| 2724 | } | 2751 | } |
| 2725 | 2752 | ||
| 2726 | perf_evlist__config(evlist, &trace->opts); | 2753 | perf_evlist__config(evlist, &trace->opts, NULL); |
| 2754 | |||
| 2755 | if (trace->opts.callgraph_set && trace->syscalls.events.sys_exit) { | ||
| 2756 | perf_evsel__config_callchain(trace->syscalls.events.sys_exit, | ||
| 2757 | &trace->opts, &callchain_param); | ||
| 2758 | /* | ||
| 2759 | * Now we have evsels with different sample_ids, use | ||
| 2760 | * PERF_SAMPLE_IDENTIFIER to map from sample to evsel | ||
| 2761 | * from a fixed position in each ring buffer record. | ||
| 2762 | * | ||
| 2763 | * As of this the changeset introducing this comment, this | ||
| 2764 | * isn't strictly needed, as the fields that can come before | ||
| 2765 | * PERF_SAMPLE_ID are all used, but we'll probably disable | ||
| 2766 | * some of those for things like copying the payload of | ||
| 2767 | * pointer syscall arguments, and for vfs_getname we don't | ||
| 2768 | * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this | ||
| 2769 | * here as a warning we need to use PERF_SAMPLE_IDENTIFIER. | ||
| 2770 | */ | ||
| 2771 | perf_evlist__set_sample_bit(evlist, IDENTIFIER); | ||
| 2772 | perf_evlist__reset_sample_bit(evlist, ID); | ||
| 2773 | } | ||
| 2727 | 2774 | ||
| 2728 | signal(SIGCHLD, sig_handler); | 2775 | signal(SIGCHLD, sig_handler); |
| 2729 | signal(SIGINT, sig_handler); | 2776 | signal(SIGINT, sig_handler); |
| @@ -3205,6 +3252,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 3205 | .output = stderr, | 3252 | .output = stderr, |
| 3206 | .show_comm = true, | 3253 | .show_comm = true, |
| 3207 | .trace_syscalls = true, | 3254 | .trace_syscalls = true, |
| 3255 | .kernel_syscallchains = false, | ||
| 3208 | }; | 3256 | }; |
| 3209 | const char *output_name = NULL; | 3257 | const char *output_name = NULL; |
| 3210 | const char *ev_qualifier_str = NULL; | 3258 | const char *ev_qualifier_str = NULL; |
| @@ -3250,6 +3298,11 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 3250 | "Trace pagefaults", parse_pagefaults, "maj"), | 3298 | "Trace pagefaults", parse_pagefaults, "maj"), |
| 3251 | OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"), | 3299 | OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"), |
| 3252 | OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"), | 3300 | OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"), |
| 3301 | OPT_CALLBACK(0, "call-graph", &trace.opts, | ||
| 3302 | "record_mode[,record_size]", record_callchain_help, | ||
| 3303 | &record_parse_callchain_opt), | ||
| 3304 | OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains, | ||
| 3305 | "Show the kernel callchains on the syscall exit path"), | ||
| 3253 | OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout, | 3306 | OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout, |
| 3254 | "per thread proc mmap processing timeout in ms"), | 3307 | "per thread proc mmap processing timeout in ms"), |
| 3255 | OPT_END() | 3308 | OPT_END() |
| @@ -3273,11 +3326,21 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 3273 | argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands, | 3326 | argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands, |
| 3274 | trace_usage, PARSE_OPT_STOP_AT_NON_OPTION); | 3327 | trace_usage, PARSE_OPT_STOP_AT_NON_OPTION); |
| 3275 | 3328 | ||
| 3329 | err = bpf__setup_stdout(trace.evlist); | ||
| 3330 | if (err) { | ||
| 3331 | bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf)); | ||
| 3332 | pr_err("ERROR: Setup BPF stdout failed: %s\n", bf); | ||
| 3333 | goto out; | ||
| 3334 | } | ||
| 3335 | |||
| 3276 | if (trace.trace_pgfaults) { | 3336 | if (trace.trace_pgfaults) { |
| 3277 | trace.opts.sample_address = true; | 3337 | trace.opts.sample_address = true; |
| 3278 | trace.opts.sample_time = true; | 3338 | trace.opts.sample_time = true; |
| 3279 | } | 3339 | } |
| 3280 | 3340 | ||
| 3341 | if (trace.opts.callgraph_set) | ||
| 3342 | symbol_conf.use_callchain = true; | ||
| 3343 | |||
| 3281 | if (trace.evlist->nr_entries > 0) | 3344 | if (trace.evlist->nr_entries > 0) |
| 3282 | evlist__set_evsel_handler(trace.evlist, trace__event_handler); | 3345 | evlist__set_evsel_handler(trace.evlist, trace__event_handler); |
| 3283 | 3346 | ||
diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c index 199501c71e27..f31eed31c1a9 100644 --- a/tools/perf/tests/bpf.c +++ b/tools/perf/tests/bpf.c | |||
| @@ -138,7 +138,7 @@ static int do_test(struct bpf_object *obj, int (*func)(void), | |||
| 138 | perf_evlist__splice_list_tail(evlist, &parse_evlist.list); | 138 | perf_evlist__splice_list_tail(evlist, &parse_evlist.list); |
| 139 | evlist->nr_groups = parse_evlist.nr_groups; | 139 | evlist->nr_groups = parse_evlist.nr_groups; |
| 140 | 140 | ||
| 141 | perf_evlist__config(evlist, &opts); | 141 | perf_evlist__config(evlist, &opts, NULL); |
| 142 | 142 | ||
| 143 | err = perf_evlist__open(evlist); | 143 | err = perf_evlist__open(evlist); |
| 144 | if (err < 0) { | 144 | if (err < 0) { |
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index abd3f0ec0c0b..68a69a195545 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c | |||
| @@ -532,7 +532,7 @@ static int do_test_code_reading(bool try_kcore) | |||
| 532 | goto out_put; | 532 | goto out_put; |
| 533 | } | 533 | } |
| 534 | 534 | ||
| 535 | perf_evlist__config(evlist, &opts); | 535 | perf_evlist__config(evlist, &opts, NULL); |
| 536 | 536 | ||
| 537 | evsel = perf_evlist__first(evlist); | 537 | evsel = perf_evlist__first(evlist); |
| 538 | 538 | ||
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c index ddb78fae064a..614e45a3c603 100644 --- a/tools/perf/tests/keep-tracking.c +++ b/tools/perf/tests/keep-tracking.c | |||
| @@ -80,7 +80,7 @@ int test__keep_tracking(int subtest __maybe_unused) | |||
| 80 | CHECK__(parse_events(evlist, "dummy:u", NULL)); | 80 | CHECK__(parse_events(evlist, "dummy:u", NULL)); |
| 81 | CHECK__(parse_events(evlist, "cycles:u", NULL)); | 81 | CHECK__(parse_events(evlist, "cycles:u", NULL)); |
| 82 | 82 | ||
| 83 | perf_evlist__config(evlist, &opts); | 83 | perf_evlist__config(evlist, &opts, NULL); |
| 84 | 84 | ||
| 85 | evsel = perf_evlist__first(evlist); | 85 | evsel = perf_evlist__first(evlist); |
| 86 | 86 | ||
diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c index eb99a105f31c..4344fe482c1d 100644 --- a/tools/perf/tests/openat-syscall-tp-fields.c +++ b/tools/perf/tests/openat-syscall-tp-fields.c | |||
| @@ -44,7 +44,7 @@ int test__syscall_openat_tp_fields(int subtest __maybe_unused) | |||
| 44 | goto out_delete_evlist; | 44 | goto out_delete_evlist; |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | perf_evsel__config(evsel, &opts); | 47 | perf_evsel__config(evsel, &opts, NULL); |
| 48 | 48 | ||
| 49 | thread_map__set_pid(evlist->threads, 0, getpid()); | 49 | thread_map__set_pid(evlist->threads, 0, getpid()); |
| 50 | 50 | ||
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index 1cc78cefe399..b836ee6a8d9b 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c | |||
| @@ -99,7 +99,7 @@ int test__PERF_RECORD(int subtest __maybe_unused) | |||
| 99 | perf_evsel__set_sample_bit(evsel, CPU); | 99 | perf_evsel__set_sample_bit(evsel, CPU); |
| 100 | perf_evsel__set_sample_bit(evsel, TID); | 100 | perf_evsel__set_sample_bit(evsel, TID); |
| 101 | perf_evsel__set_sample_bit(evsel, TIME); | 101 | perf_evsel__set_sample_bit(evsel, TIME); |
| 102 | perf_evlist__config(evlist, &opts); | 102 | perf_evlist__config(evlist, &opts, NULL); |
| 103 | 103 | ||
| 104 | err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); | 104 | err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); |
| 105 | if (err < 0) { | 105 | if (err < 0) { |
diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c index ebd80168d51e..39a689bf7574 100644 --- a/tools/perf/tests/switch-tracking.c +++ b/tools/perf/tests/switch-tracking.c | |||
| @@ -417,7 +417,7 @@ int test__switch_tracking(int subtest __maybe_unused) | |||
| 417 | perf_evsel__set_sample_bit(tracking_evsel, TIME); | 417 | perf_evsel__set_sample_bit(tracking_evsel, TIME); |
| 418 | 418 | ||
| 419 | /* Config events */ | 419 | /* Config events */ |
| 420 | perf_evlist__config(evlist, &opts); | 420 | perf_evlist__config(evlist, &opts, NULL); |
| 421 | 421 | ||
| 422 | /* Check moved event is still at the front */ | 422 | /* Check moved event is still at the front */ |
| 423 | if (cycles_evsel != perf_evlist__first(evlist)) { | 423 | if (cycles_evsel != perf_evlist__first(evlist)) { |
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 0967ce601931..493307d1414c 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c | |||
| @@ -842,6 +842,58 @@ bpf_map_op__new(struct parse_events_term *term) | |||
| 842 | return op; | 842 | return op; |
| 843 | } | 843 | } |
| 844 | 844 | ||
| 845 | static struct bpf_map_op * | ||
| 846 | bpf_map_op__clone(struct bpf_map_op *op) | ||
| 847 | { | ||
| 848 | struct bpf_map_op *newop; | ||
| 849 | |||
| 850 | newop = memdup(op, sizeof(*op)); | ||
| 851 | if (!newop) { | ||
| 852 | pr_debug("Failed to alloc bpf_map_op\n"); | ||
| 853 | return NULL; | ||
| 854 | } | ||
| 855 | |||
| 856 | INIT_LIST_HEAD(&newop->list); | ||
| 857 | if (op->key_type == BPF_MAP_KEY_RANGES) { | ||
| 858 | size_t memsz = op->k.array.nr_ranges * | ||
| 859 | sizeof(op->k.array.ranges[0]); | ||
| 860 | |||
| 861 | newop->k.array.ranges = memdup(op->k.array.ranges, memsz); | ||
| 862 | if (!newop->k.array.ranges) { | ||
| 863 | pr_debug("Failed to alloc indices for map\n"); | ||
| 864 | free(newop); | ||
| 865 | return NULL; | ||
| 866 | } | ||
| 867 | } | ||
| 868 | |||
| 869 | return newop; | ||
| 870 | } | ||
| 871 | |||
| 872 | static struct bpf_map_priv * | ||
| 873 | bpf_map_priv__clone(struct bpf_map_priv *priv) | ||
| 874 | { | ||
| 875 | struct bpf_map_priv *newpriv; | ||
| 876 | struct bpf_map_op *pos, *newop; | ||
| 877 | |||
| 878 | newpriv = zalloc(sizeof(*newpriv)); | ||
| 879 | if (!newpriv) { | ||
| 880 | pr_debug("No enough memory to alloc map private\n"); | ||
| 881 | return NULL; | ||
| 882 | } | ||
| 883 | INIT_LIST_HEAD(&newpriv->ops_list); | ||
| 884 | |||
| 885 | list_for_each_entry(pos, &priv->ops_list, list) { | ||
| 886 | newop = bpf_map_op__clone(pos); | ||
| 887 | if (!newop) { | ||
| 888 | bpf_map_priv__purge(newpriv); | ||
| 889 | return NULL; | ||
| 890 | } | ||
| 891 | list_add_tail(&newop->list, &newpriv->ops_list); | ||
| 892 | } | ||
| 893 | |||
| 894 | return newpriv; | ||
| 895 | } | ||
| 896 | |||
| 845 | static int | 897 | static int |
| 846 | bpf_map__add_op(struct bpf_map *map, struct bpf_map_op *op) | 898 | bpf_map__add_op(struct bpf_map *map, struct bpf_map_op *op) |
| 847 | { | 899 | { |
| @@ -1417,6 +1469,89 @@ int bpf__apply_obj_config(void) | |||
| 1417 | return 0; | 1469 | return 0; |
| 1418 | } | 1470 | } |
| 1419 | 1471 | ||
| 1472 | #define bpf__for_each_map(pos, obj, objtmp) \ | ||
| 1473 | bpf_object__for_each_safe(obj, objtmp) \ | ||
| 1474 | bpf_map__for_each(pos, obj) | ||
| 1475 | |||
| 1476 | #define bpf__for_each_stdout_map(pos, obj, objtmp) \ | ||
| 1477 | bpf__for_each_map(pos, obj, objtmp) \ | ||
| 1478 | if (bpf_map__get_name(pos) && \ | ||
| 1479 | (strcmp("__bpf_stdout__", \ | ||
| 1480 | bpf_map__get_name(pos)) == 0)) | ||
| 1481 | |||
| 1482 | int bpf__setup_stdout(struct perf_evlist *evlist __maybe_unused) | ||
| 1483 | { | ||
| 1484 | struct bpf_map_priv *tmpl_priv = NULL; | ||
| 1485 | struct bpf_object *obj, *tmp; | ||
| 1486 | struct perf_evsel *evsel = NULL; | ||
| 1487 | struct bpf_map *map; | ||
| 1488 | int err; | ||
| 1489 | bool need_init = false; | ||
| 1490 | |||
| 1491 | bpf__for_each_stdout_map(map, obj, tmp) { | ||
| 1492 | struct bpf_map_priv *priv; | ||
| 1493 | |||
| 1494 | err = bpf_map__get_private(map, (void **)&priv); | ||
| 1495 | if (err) | ||
| 1496 | return -BPF_LOADER_ERRNO__INTERNAL; | ||
| 1497 | |||
| 1498 | /* | ||
| 1499 | * No need to check map type: type should have been | ||
| 1500 | * verified by kernel. | ||
| 1501 | */ | ||
| 1502 | if (!need_init && !priv) | ||
| 1503 | need_init = !priv; | ||
| 1504 | if (!tmpl_priv && priv) | ||
| 1505 | tmpl_priv = priv; | ||
| 1506 | } | ||
| 1507 | |||
| 1508 | if (!need_init) | ||
| 1509 | return 0; | ||
| 1510 | |||
| 1511 | if (!tmpl_priv) { | ||
| 1512 | err = parse_events(evlist, "bpf-output/no-inherit=1,name=__bpf_stdout__/", | ||
| 1513 | NULL); | ||
| 1514 | if (err) { | ||
| 1515 | pr_debug("ERROR: failed to create bpf-output event\n"); | ||
| 1516 | return -err; | ||
| 1517 | } | ||
| 1518 | |||
| 1519 | evsel = perf_evlist__last(evlist); | ||
| 1520 | } | ||
| 1521 | |||
| 1522 | bpf__for_each_stdout_map(map, obj, tmp) { | ||
| 1523 | struct bpf_map_priv *priv; | ||
| 1524 | |||
| 1525 | err = bpf_map__get_private(map, (void **)&priv); | ||
| 1526 | if (err) | ||
| 1527 | return -BPF_LOADER_ERRNO__INTERNAL; | ||
| 1528 | if (priv) | ||
| 1529 | continue; | ||
| 1530 | |||
| 1531 | if (tmpl_priv) { | ||
| 1532 | priv = bpf_map_priv__clone(tmpl_priv); | ||
| 1533 | if (!priv) | ||
| 1534 | return -ENOMEM; | ||
| 1535 | |||
| 1536 | err = bpf_map__set_private(map, priv, bpf_map_priv__clear); | ||
| 1537 | if (err) { | ||
| 1538 | bpf_map_priv__clear(map, priv); | ||
| 1539 | return err; | ||
| 1540 | } | ||
| 1541 | } else if (evsel) { | ||
| 1542 | struct bpf_map_op *op; | ||
| 1543 | |||
| 1544 | op = bpf_map__add_newop(map, NULL); | ||
| 1545 | if (IS_ERR(op)) | ||
| 1546 | return PTR_ERR(op); | ||
| 1547 | op->op_type = BPF_MAP_OP_SET_EVSEL; | ||
| 1548 | op->v.evsel = evsel; | ||
| 1549 | } | ||
| 1550 | } | ||
| 1551 | |||
| 1552 | return 0; | ||
| 1553 | } | ||
| 1554 | |||
| 1420 | #define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START) | 1555 | #define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START) |
| 1421 | #define ERRCODE_OFFSET(c) ERRNO_OFFSET(BPF_LOADER_ERRNO__##c) | 1556 | #define ERRCODE_OFFSET(c) ERRNO_OFFSET(BPF_LOADER_ERRNO__##c) |
| 1422 | #define NR_ERRNO (__BPF_LOADER_ERRNO__END - __BPF_LOADER_ERRNO__START) | 1557 | #define NR_ERRNO (__BPF_LOADER_ERRNO__END - __BPF_LOADER_ERRNO__START) |
| @@ -1590,3 +1725,11 @@ int bpf__strerror_apply_obj_config(int err, char *buf, size_t size) | |||
| 1590 | bpf__strerror_end(buf, size); | 1725 | bpf__strerror_end(buf, size); |
| 1591 | return 0; | 1726 | return 0; |
| 1592 | } | 1727 | } |
| 1728 | |||
| 1729 | int bpf__strerror_setup_stdout(struct perf_evlist *evlist __maybe_unused, | ||
| 1730 | int err, char *buf, size_t size) | ||
| 1731 | { | ||
| 1732 | bpf__strerror_head(err, buf, size); | ||
| 1733 | bpf__strerror_end(buf, size); | ||
| 1734 | return 0; | ||
| 1735 | } | ||
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h index be4311944e3d..941e17275aa7 100644 --- a/tools/perf/util/bpf-loader.h +++ b/tools/perf/util/bpf-loader.h | |||
| @@ -79,6 +79,11 @@ int bpf__strerror_config_obj(struct bpf_object *obj, | |||
| 79 | size_t size); | 79 | size_t size); |
| 80 | int bpf__apply_obj_config(void); | 80 | int bpf__apply_obj_config(void); |
| 81 | int bpf__strerror_apply_obj_config(int err, char *buf, size_t size); | 81 | int bpf__strerror_apply_obj_config(int err, char *buf, size_t size); |
| 82 | |||
| 83 | int bpf__setup_stdout(struct perf_evlist *evlist); | ||
| 84 | int bpf__strerror_setup_stdout(struct perf_evlist *evlist, int err, | ||
| 85 | char *buf, size_t size); | ||
| 86 | |||
| 82 | #else | 87 | #else |
| 83 | static inline struct bpf_object * | 88 | static inline struct bpf_object * |
| 84 | bpf__prepare_load(const char *filename __maybe_unused, | 89 | bpf__prepare_load(const char *filename __maybe_unused, |
| @@ -125,6 +130,12 @@ bpf__apply_obj_config(void) | |||
| 125 | } | 130 | } |
| 126 | 131 | ||
| 127 | static inline int | 132 | static inline int |
| 133 | bpf__setup_stdout(struct perf_evlist *evlist __maybe_unused) | ||
| 134 | { | ||
| 135 | return 0; | ||
| 136 | } | ||
| 137 | |||
| 138 | static inline int | ||
| 128 | __bpf_strerror(char *buf, size_t size) | 139 | __bpf_strerror(char *buf, size_t size) |
| 129 | { | 140 | { |
| 130 | if (!size) | 141 | if (!size) |
| @@ -177,5 +188,13 @@ bpf__strerror_apply_obj_config(int err __maybe_unused, | |||
| 177 | { | 188 | { |
| 178 | return __bpf_strerror(buf, size); | 189 | return __bpf_strerror(buf, size); |
| 179 | } | 190 | } |
| 191 | |||
| 192 | static inline int | ||
| 193 | bpf__strerror_setup_stdout(struct perf_evlist *evlist __maybe_unused, | ||
| 194 | int err __maybe_unused, char *buf, | ||
| 195 | size_t size) | ||
| 196 | { | ||
| 197 | return __bpf_strerror(buf, size); | ||
| 198 | } | ||
| 180 | #endif | 199 | #endif |
| 181 | #endif | 200 | #endif |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index b68959037688..f6fcc6832949 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
| @@ -434,7 +434,7 @@ static int __event__synthesize_thread(union perf_event *comm_event, | |||
| 434 | { | 434 | { |
| 435 | char filename[PATH_MAX]; | 435 | char filename[PATH_MAX]; |
| 436 | DIR *tasks; | 436 | DIR *tasks; |
| 437 | struct dirent dirent, *next; | 437 | struct dirent *dirent; |
| 438 | pid_t tgid, ppid; | 438 | pid_t tgid, ppid; |
| 439 | int rc = 0; | 439 | int rc = 0; |
| 440 | 440 | ||
| @@ -463,11 +463,11 @@ static int __event__synthesize_thread(union perf_event *comm_event, | |||
| 463 | return 0; | 463 | return 0; |
| 464 | } | 464 | } |
| 465 | 465 | ||
| 466 | while (!readdir_r(tasks, &dirent, &next) && next) { | 466 | while ((dirent = readdir(tasks)) != NULL) { |
| 467 | char *end; | 467 | char *end; |
| 468 | pid_t _pid; | 468 | pid_t _pid; |
| 469 | 469 | ||
| 470 | _pid = strtol(dirent.d_name, &end, 10); | 470 | _pid = strtol(dirent->d_name, &end, 10); |
| 471 | if (*end) | 471 | if (*end) |
| 472 | continue; | 472 | continue; |
| 473 | 473 | ||
| @@ -576,7 +576,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool, | |||
| 576 | { | 576 | { |
| 577 | DIR *proc; | 577 | DIR *proc; |
| 578 | char proc_path[PATH_MAX]; | 578 | char proc_path[PATH_MAX]; |
| 579 | struct dirent dirent, *next; | 579 | struct dirent *dirent; |
| 580 | union perf_event *comm_event, *mmap_event, *fork_event; | 580 | union perf_event *comm_event, *mmap_event, *fork_event; |
| 581 | int err = -1; | 581 | int err = -1; |
| 582 | 582 | ||
| @@ -601,9 +601,9 @@ int perf_event__synthesize_threads(struct perf_tool *tool, | |||
| 601 | if (proc == NULL) | 601 | if (proc == NULL) |
| 602 | goto out_free_fork; | 602 | goto out_free_fork; |
| 603 | 603 | ||
| 604 | while (!readdir_r(proc, &dirent, &next) && next) { | 604 | while ((dirent = readdir(proc)) != NULL) { |
| 605 | char *end; | 605 | char *end; |
| 606 | pid_t pid = strtol(dirent.d_name, &end, 10); | 606 | pid_t pid = strtol(dirent->d_name, &end, 10); |
| 607 | 607 | ||
| 608 | if (*end) /* only interested in proper numerical dirents */ | 608 | if (*end) /* only interested in proper numerical dirents */ |
| 609 | continue; | 609 | continue; |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 86a03836a83f..4c9f510ae18d 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
| @@ -1192,6 +1192,24 @@ void perf_evlist__set_maps(struct perf_evlist *evlist, struct cpu_map *cpus, | |||
| 1192 | perf_evlist__propagate_maps(evlist); | 1192 | perf_evlist__propagate_maps(evlist); |
| 1193 | } | 1193 | } |
| 1194 | 1194 | ||
| 1195 | void __perf_evlist__set_sample_bit(struct perf_evlist *evlist, | ||
| 1196 | enum perf_event_sample_format bit) | ||
| 1197 | { | ||
| 1198 | struct perf_evsel *evsel; | ||
| 1199 | |||
| 1200 | evlist__for_each(evlist, evsel) | ||
| 1201 | __perf_evsel__set_sample_bit(evsel, bit); | ||
| 1202 | } | ||
| 1203 | |||
| 1204 | void __perf_evlist__reset_sample_bit(struct perf_evlist *evlist, | ||
| 1205 | enum perf_event_sample_format bit) | ||
| 1206 | { | ||
| 1207 | struct perf_evsel *evsel; | ||
| 1208 | |||
| 1209 | evlist__for_each(evlist, evsel) | ||
| 1210 | __perf_evsel__reset_sample_bit(evsel, bit); | ||
| 1211 | } | ||
| 1212 | |||
| 1195 | int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **err_evsel) | 1213 | int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **err_evsel) |
| 1196 | { | 1214 | { |
| 1197 | struct perf_evsel *evsel; | 1215 | struct perf_evsel *evsel; |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index a0d15221db6e..da46423998e8 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
| @@ -87,6 +87,17 @@ int perf_evlist__add_dummy(struct perf_evlist *evlist); | |||
| 87 | int perf_evlist__add_newtp(struct perf_evlist *evlist, | 87 | int perf_evlist__add_newtp(struct perf_evlist *evlist, |
| 88 | const char *sys, const char *name, void *handler); | 88 | const char *sys, const char *name, void *handler); |
| 89 | 89 | ||
| 90 | void __perf_evlist__set_sample_bit(struct perf_evlist *evlist, | ||
| 91 | enum perf_event_sample_format bit); | ||
| 92 | void __perf_evlist__reset_sample_bit(struct perf_evlist *evlist, | ||
| 93 | enum perf_event_sample_format bit); | ||
| 94 | |||
| 95 | #define perf_evlist__set_sample_bit(evlist, bit) \ | ||
| 96 | __perf_evlist__set_sample_bit(evlist, PERF_SAMPLE_##bit) | ||
| 97 | |||
| 98 | #define perf_evlist__reset_sample_bit(evlist, bit) \ | ||
| 99 | __perf_evlist__reset_sample_bit(evlist, PERF_SAMPLE_##bit) | ||
| 100 | |||
| 90 | int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter); | 101 | int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter); |
| 91 | int perf_evlist__set_filter_pid(struct perf_evlist *evlist, pid_t pid); | 102 | int perf_evlist__set_filter_pid(struct perf_evlist *evlist, pid_t pid); |
| 92 | int perf_evlist__set_filter_pids(struct perf_evlist *evlist, size_t npids, pid_t *pids); | 103 | int perf_evlist__set_filter_pids(struct perf_evlist *evlist, size_t npids, pid_t *pids); |
| @@ -123,11 +134,14 @@ void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx); | |||
| 123 | int perf_evlist__open(struct perf_evlist *evlist); | 134 | int perf_evlist__open(struct perf_evlist *evlist); |
| 124 | void perf_evlist__close(struct perf_evlist *evlist); | 135 | void perf_evlist__close(struct perf_evlist *evlist); |
| 125 | 136 | ||
| 137 | struct callchain_param; | ||
| 138 | |||
| 126 | void perf_evlist__set_id_pos(struct perf_evlist *evlist); | 139 | void perf_evlist__set_id_pos(struct perf_evlist *evlist); |
| 127 | bool perf_can_sample_identifier(void); | 140 | bool perf_can_sample_identifier(void); |
| 128 | bool perf_can_record_switch_events(void); | 141 | bool perf_can_record_switch_events(void); |
| 129 | bool perf_can_record_cpu_wide(void); | 142 | bool perf_can_record_cpu_wide(void); |
| 130 | void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts); | 143 | void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, |
| 144 | struct callchain_param *callchain); | ||
| 131 | int record_opts__config(struct record_opts *opts); | 145 | int record_opts__config(struct record_opts *opts); |
| 132 | 146 | ||
| 133 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, | 147 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 3fd7c2c72f4a..d475a4ec8b57 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
| @@ -562,10 +562,9 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size) | |||
| 562 | return ret; | 562 | return ret; |
| 563 | } | 563 | } |
| 564 | 564 | ||
| 565 | static void | 565 | void perf_evsel__config_callchain(struct perf_evsel *evsel, |
| 566 | perf_evsel__config_callgraph(struct perf_evsel *evsel, | 566 | struct record_opts *opts, |
| 567 | struct record_opts *opts, | 567 | struct callchain_param *param) |
| 568 | struct callchain_param *param) | ||
| 569 | { | 568 | { |
| 570 | bool function = perf_evsel__is_function_event(evsel); | 569 | bool function = perf_evsel__is_function_event(evsel); |
| 571 | struct perf_event_attr *attr = &evsel->attr; | 570 | struct perf_event_attr *attr = &evsel->attr; |
| @@ -705,7 +704,7 @@ static void apply_config_terms(struct perf_evsel *evsel, | |||
| 705 | 704 | ||
| 706 | /* set perf-event callgraph */ | 705 | /* set perf-event callgraph */ |
| 707 | if (param.enabled) | 706 | if (param.enabled) |
| 708 | perf_evsel__config_callgraph(evsel, opts, ¶m); | 707 | perf_evsel__config_callchain(evsel, opts, ¶m); |
| 709 | } | 708 | } |
| 710 | } | 709 | } |
| 711 | 710 | ||
| @@ -737,7 +736,8 @@ static void apply_config_terms(struct perf_evsel *evsel, | |||
| 737 | * enable/disable events specifically, as there's no | 736 | * enable/disable events specifically, as there's no |
| 738 | * initial traced exec call. | 737 | * initial traced exec call. |
| 739 | */ | 738 | */ |
| 740 | void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) | 739 | void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, |
| 740 | struct callchain_param *callchain) | ||
| 741 | { | 741 | { |
| 742 | struct perf_evsel *leader = evsel->leader; | 742 | struct perf_evsel *leader = evsel->leader; |
| 743 | struct perf_event_attr *attr = &evsel->attr; | 743 | struct perf_event_attr *attr = &evsel->attr; |
| @@ -812,8 +812,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) | |||
| 812 | if (perf_evsel__is_function_event(evsel)) | 812 | if (perf_evsel__is_function_event(evsel)) |
| 813 | evsel->attr.exclude_callchain_user = 1; | 813 | evsel->attr.exclude_callchain_user = 1; |
| 814 | 814 | ||
| 815 | if (callchain_param.enabled && !evsel->no_aux_samples) | 815 | if (callchain && callchain->enabled && !evsel->no_aux_samples) |
| 816 | perf_evsel__config_callgraph(evsel, opts, &callchain_param); | 816 | perf_evsel__config_callchain(evsel, opts, callchain); |
| 817 | 817 | ||
| 818 | if (opts->sample_intr_regs) { | 818 | if (opts->sample_intr_regs) { |
| 819 | attr->sample_regs_intr = opts->sample_intr_regs; | 819 | attr->sample_regs_intr = opts->sample_intr_regs; |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 501ea6e565f1..1bd6c2e02dfa 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
| @@ -178,8 +178,14 @@ void perf_evsel__init(struct perf_evsel *evsel, | |||
| 178 | void perf_evsel__exit(struct perf_evsel *evsel); | 178 | void perf_evsel__exit(struct perf_evsel *evsel); |
| 179 | void perf_evsel__delete(struct perf_evsel *evsel); | 179 | void perf_evsel__delete(struct perf_evsel *evsel); |
| 180 | 180 | ||
| 181 | struct callchain_param; | ||
| 182 | |||
| 181 | void perf_evsel__config(struct perf_evsel *evsel, | 183 | void perf_evsel__config(struct perf_evsel *evsel, |
| 182 | struct record_opts *opts); | 184 | struct record_opts *opts, |
| 185 | struct callchain_param *callchain); | ||
| 186 | void perf_evsel__config_callchain(struct perf_evsel *evsel, | ||
| 187 | struct record_opts *opts, | ||
| 188 | struct callchain_param *callchain); | ||
| 183 | 189 | ||
| 184 | int __perf_evsel__sample_size(u64 sample_type); | 190 | int __perf_evsel__sample_size(u64 sample_type); |
| 185 | void perf_evsel__calc_id_pos(struct perf_evsel *evsel); | 191 | void perf_evsel__calc_id_pos(struct perf_evsel *evsel); |
| @@ -381,6 +387,12 @@ struct perf_attr_details { | |||
| 381 | int perf_evsel__fprintf(struct perf_evsel *evsel, | 387 | int perf_evsel__fprintf(struct perf_evsel *evsel, |
| 382 | struct perf_attr_details *details, FILE *fp); | 388 | struct perf_attr_details *details, FILE *fp); |
| 383 | 389 | ||
| 390 | int perf_evsel__fprintf_callchain(struct perf_evsel *evsel, | ||
| 391 | struct perf_sample *sample, | ||
| 392 | struct addr_location *al, int left_alignment, | ||
| 393 | unsigned int print_opts, | ||
| 394 | unsigned int stack_depth, FILE *fp); | ||
| 395 | |||
| 384 | bool perf_evsel__fallback(struct perf_evsel *evsel, int err, | 396 | bool perf_evsel__fallback(struct perf_evsel *evsel, int err, |
| 385 | char *msg, size_t msgsize); | 397 | char *msg, size_t msgsize); |
| 386 | int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, | 398 | int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 4c19d5e79d8c..bcbc983d4b12 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
| @@ -138,11 +138,11 @@ struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = { | |||
| 138 | #define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) | 138 | #define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) |
| 139 | #define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) | 139 | #define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) |
| 140 | 140 | ||
| 141 | #define for_each_subsystem(sys_dir, sys_dirent, sys_next) \ | 141 | #define for_each_subsystem(sys_dir, sys_dirent) \ |
| 142 | while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \ | 142 | while ((sys_dirent = readdir(sys_dir)) != NULL) \ |
| 143 | if (sys_dirent.d_type == DT_DIR && \ | 143 | if (sys_dirent->d_type == DT_DIR && \ |
| 144 | (strcmp(sys_dirent.d_name, ".")) && \ | 144 | (strcmp(sys_dirent->d_name, ".")) && \ |
| 145 | (strcmp(sys_dirent.d_name, ".."))) | 145 | (strcmp(sys_dirent->d_name, ".."))) |
| 146 | 146 | ||
| 147 | static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir) | 147 | static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir) |
| 148 | { | 148 | { |
| @@ -159,12 +159,12 @@ static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir) | |||
| 159 | return 0; | 159 | return 0; |
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | #define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) \ | 162 | #define for_each_event(sys_dirent, evt_dir, evt_dirent) \ |
| 163 | while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \ | 163 | while ((evt_dirent = readdir(evt_dir)) != NULL) \ |
| 164 | if (evt_dirent.d_type == DT_DIR && \ | 164 | if (evt_dirent->d_type == DT_DIR && \ |
| 165 | (strcmp(evt_dirent.d_name, ".")) && \ | 165 | (strcmp(evt_dirent->d_name, ".")) && \ |
| 166 | (strcmp(evt_dirent.d_name, "..")) && \ | 166 | (strcmp(evt_dirent->d_name, "..")) && \ |
| 167 | (!tp_event_has_id(&sys_dirent, &evt_dirent))) | 167 | (!tp_event_has_id(sys_dirent, evt_dirent))) |
| 168 | 168 | ||
| 169 | #define MAX_EVENT_LENGTH 512 | 169 | #define MAX_EVENT_LENGTH 512 |
| 170 | 170 | ||
| @@ -173,7 +173,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) | |||
| 173 | { | 173 | { |
| 174 | struct tracepoint_path *path = NULL; | 174 | struct tracepoint_path *path = NULL; |
| 175 | DIR *sys_dir, *evt_dir; | 175 | DIR *sys_dir, *evt_dir; |
| 176 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; | 176 | struct dirent *sys_dirent, *evt_dirent; |
| 177 | char id_buf[24]; | 177 | char id_buf[24]; |
| 178 | int fd; | 178 | int fd; |
| 179 | u64 id; | 179 | u64 id; |
| @@ -184,18 +184,18 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) | |||
| 184 | if (!sys_dir) | 184 | if (!sys_dir) |
| 185 | return NULL; | 185 | return NULL; |
| 186 | 186 | ||
| 187 | for_each_subsystem(sys_dir, sys_dirent, sys_next) { | 187 | for_each_subsystem(sys_dir, sys_dirent) { |
| 188 | 188 | ||
| 189 | snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, | 189 | snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, |
| 190 | sys_dirent.d_name); | 190 | sys_dirent->d_name); |
| 191 | evt_dir = opendir(dir_path); | 191 | evt_dir = opendir(dir_path); |
| 192 | if (!evt_dir) | 192 | if (!evt_dir) |
| 193 | continue; | 193 | continue; |
| 194 | 194 | ||
| 195 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { | 195 | for_each_event(sys_dirent, evt_dir, evt_dirent) { |
| 196 | 196 | ||
| 197 | snprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, | 197 | snprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, |
| 198 | evt_dirent.d_name); | 198 | evt_dirent->d_name); |
| 199 | fd = open(evt_path, O_RDONLY); | 199 | fd = open(evt_path, O_RDONLY); |
| 200 | if (fd < 0) | 200 | if (fd < 0) |
| 201 | continue; | 201 | continue; |
| @@ -220,9 +220,9 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) | |||
| 220 | free(path); | 220 | free(path); |
| 221 | return NULL; | 221 | return NULL; |
| 222 | } | 222 | } |
| 223 | strncpy(path->system, sys_dirent.d_name, | 223 | strncpy(path->system, sys_dirent->d_name, |
| 224 | MAX_EVENT_LENGTH); | 224 | MAX_EVENT_LENGTH); |
| 225 | strncpy(path->name, evt_dirent.d_name, | 225 | strncpy(path->name, evt_dirent->d_name, |
| 226 | MAX_EVENT_LENGTH); | 226 | MAX_EVENT_LENGTH); |
| 227 | return path; | 227 | return path; |
| 228 | } | 228 | } |
| @@ -1812,7 +1812,7 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob, | |||
| 1812 | bool name_only) | 1812 | bool name_only) |
| 1813 | { | 1813 | { |
| 1814 | DIR *sys_dir, *evt_dir; | 1814 | DIR *sys_dir, *evt_dir; |
| 1815 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; | 1815 | struct dirent *sys_dirent, *evt_dirent; |
| 1816 | char evt_path[MAXPATHLEN]; | 1816 | char evt_path[MAXPATHLEN]; |
| 1817 | char dir_path[MAXPATHLEN]; | 1817 | char dir_path[MAXPATHLEN]; |
| 1818 | char **evt_list = NULL; | 1818 | char **evt_list = NULL; |
| @@ -1830,20 +1830,20 @@ restart: | |||
| 1830 | goto out_close_sys_dir; | 1830 | goto out_close_sys_dir; |
| 1831 | } | 1831 | } |
| 1832 | 1832 | ||
| 1833 | for_each_subsystem(sys_dir, sys_dirent, sys_next) { | 1833 | for_each_subsystem(sys_dir, sys_dirent) { |
| 1834 | if (subsys_glob != NULL && | 1834 | if (subsys_glob != NULL && |
| 1835 | !strglobmatch(sys_dirent.d_name, subsys_glob)) | 1835 | !strglobmatch(sys_dirent->d_name, subsys_glob)) |
| 1836 | continue; | 1836 | continue; |
| 1837 | 1837 | ||
| 1838 | snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, | 1838 | snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, |
| 1839 | sys_dirent.d_name); | 1839 | sys_dirent->d_name); |
| 1840 | evt_dir = opendir(dir_path); | 1840 | evt_dir = opendir(dir_path); |
| 1841 | if (!evt_dir) | 1841 | if (!evt_dir) |
| 1842 | continue; | 1842 | continue; |
| 1843 | 1843 | ||
| 1844 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { | 1844 | for_each_event(sys_dirent, evt_dir, evt_dirent) { |
| 1845 | if (event_glob != NULL && | 1845 | if (event_glob != NULL && |
| 1846 | !strglobmatch(evt_dirent.d_name, event_glob)) | 1846 | !strglobmatch(evt_dirent->d_name, event_glob)) |
| 1847 | continue; | 1847 | continue; |
| 1848 | 1848 | ||
| 1849 | if (!evt_num_known) { | 1849 | if (!evt_num_known) { |
| @@ -1852,7 +1852,7 @@ restart: | |||
| 1852 | } | 1852 | } |
| 1853 | 1853 | ||
| 1854 | snprintf(evt_path, MAXPATHLEN, "%s:%s", | 1854 | snprintf(evt_path, MAXPATHLEN, "%s:%s", |
| 1855 | sys_dirent.d_name, evt_dirent.d_name); | 1855 | sys_dirent->d_name, evt_dirent->d_name); |
| 1856 | 1856 | ||
| 1857 | evt_list[evt_i] = strdup(evt_path); | 1857 | evt_list[evt_i] = strdup(evt_path); |
| 1858 | if (evt_list[evt_i] == NULL) | 1858 | if (evt_list[evt_i] == NULL) |
| @@ -1905,7 +1905,7 @@ out_close_sys_dir: | |||
| 1905 | int is_valid_tracepoint(const char *event_string) | 1905 | int is_valid_tracepoint(const char *event_string) |
| 1906 | { | 1906 | { |
| 1907 | DIR *sys_dir, *evt_dir; | 1907 | DIR *sys_dir, *evt_dir; |
| 1908 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; | 1908 | struct dirent *sys_dirent, *evt_dirent; |
| 1909 | char evt_path[MAXPATHLEN]; | 1909 | char evt_path[MAXPATHLEN]; |
| 1910 | char dir_path[MAXPATHLEN]; | 1910 | char dir_path[MAXPATHLEN]; |
| 1911 | 1911 | ||
| @@ -1913,17 +1913,17 @@ int is_valid_tracepoint(const char *event_string) | |||
| 1913 | if (!sys_dir) | 1913 | if (!sys_dir) |
| 1914 | return 0; | 1914 | return 0; |
| 1915 | 1915 | ||
| 1916 | for_each_subsystem(sys_dir, sys_dirent, sys_next) { | 1916 | for_each_subsystem(sys_dir, sys_dirent) { |
| 1917 | 1917 | ||
| 1918 | snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, | 1918 | snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, |
| 1919 | sys_dirent.d_name); | 1919 | sys_dirent->d_name); |
| 1920 | evt_dir = opendir(dir_path); | 1920 | evt_dir = opendir(dir_path); |
| 1921 | if (!evt_dir) | 1921 | if (!evt_dir) |
| 1922 | continue; | 1922 | continue; |
| 1923 | 1923 | ||
| 1924 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { | 1924 | for_each_event(sys_dirent, evt_dir, evt_dirent) { |
| 1925 | snprintf(evt_path, MAXPATHLEN, "%s:%s", | 1925 | snprintf(evt_path, MAXPATHLEN, "%s:%s", |
| 1926 | sys_dirent.d_name, evt_dirent.d_name); | 1926 | sys_dirent->d_name, evt_dirent->d_name); |
| 1927 | if (!strcmp(evt_path, event_string)) { | 1927 | if (!strcmp(evt_path, event_string)) { |
| 1928 | closedir(evt_dir); | 1928 | closedir(evt_dir); |
| 1929 | closedir(sys_dir); | 1929 | closedir(sys_dir); |
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index 0467367dc315..481792c7484b 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c | |||
| @@ -129,7 +129,8 @@ bool perf_can_record_cpu_wide(void) | |||
| 129 | return true; | 129 | return true; |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts) | 132 | void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, |
| 133 | struct callchain_param *callchain) | ||
| 133 | { | 134 | { |
| 134 | struct perf_evsel *evsel; | 135 | struct perf_evsel *evsel; |
| 135 | bool use_sample_identifier = false; | 136 | bool use_sample_identifier = false; |
| @@ -148,7 +149,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts) | |||
| 148 | use_comm_exec = perf_can_comm_exec(); | 149 | use_comm_exec = perf_can_comm_exec(); |
| 149 | 150 | ||
| 150 | evlist__for_each(evlist, evsel) { | 151 | evlist__for_each(evlist, evsel) { |
| 151 | perf_evsel__config(evsel, opts); | 152 | perf_evsel__config(evsel, opts, callchain); |
| 152 | if (evsel->tracking && use_comm_exec) | 153 | if (evsel->tracking && use_comm_exec) |
| 153 | evsel->attr.comm_exec = 1; | 154 | evsel->attr.comm_exec = 1; |
| 154 | } | 155 | } |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index ef370557fb9a..0516d06a2741 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
| @@ -1953,10 +1953,12 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | |||
| 1953 | return NULL; | 1953 | return NULL; |
| 1954 | } | 1954 | } |
| 1955 | 1955 | ||
| 1956 | void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, | 1956 | int perf_evsel__fprintf_callchain(struct perf_evsel *evsel, struct perf_sample *sample, |
| 1957 | struct addr_location *al, | 1957 | struct addr_location *al, int left_alignment, |
| 1958 | unsigned int print_opts, unsigned int stack_depth) | 1958 | unsigned int print_opts, unsigned int stack_depth, |
| 1959 | FILE *fp) | ||
| 1959 | { | 1960 | { |
| 1961 | int printed = 0; | ||
| 1960 | struct callchain_cursor_node *node; | 1962 | struct callchain_cursor_node *node; |
| 1961 | int print_ip = print_opts & PRINT_IP_OPT_IP; | 1963 | int print_ip = print_opts & PRINT_IP_OPT_IP; |
| 1962 | int print_sym = print_opts & PRINT_IP_OPT_SYM; | 1964 | int print_sym = print_opts & PRINT_IP_OPT_SYM; |
| @@ -1964,9 +1966,10 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, | |||
| 1964 | int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET; | 1966 | int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET; |
| 1965 | int print_oneline = print_opts & PRINT_IP_OPT_ONELINE; | 1967 | int print_oneline = print_opts & PRINT_IP_OPT_ONELINE; |
| 1966 | int print_srcline = print_opts & PRINT_IP_OPT_SRCLINE; | 1968 | int print_srcline = print_opts & PRINT_IP_OPT_SRCLINE; |
| 1969 | int print_unknown_as_addr = print_opts & PRINT_IP_OPT_UNKNOWN_AS_ADDR; | ||
| 1967 | char s = print_oneline ? ' ' : '\t'; | 1970 | char s = print_oneline ? ' ' : '\t'; |
| 1968 | 1971 | ||
| 1969 | if (symbol_conf.use_callchain && sample->callchain) { | 1972 | if (sample->callchain) { |
| 1970 | struct addr_location node_al; | 1973 | struct addr_location node_al; |
| 1971 | 1974 | ||
| 1972 | if (thread__resolve_callchain(al->thread, evsel, | 1975 | if (thread__resolve_callchain(al->thread, evsel, |
| @@ -1974,7 +1977,7 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, | |||
| 1974 | stack_depth) != 0) { | 1977 | stack_depth) != 0) { |
| 1975 | if (verbose) | 1978 | if (verbose) |
| 1976 | error("Failed to resolve callchain. Skipping\n"); | 1979 | error("Failed to resolve callchain. Skipping\n"); |
| 1977 | return; | 1980 | return printed; |
| 1978 | } | 1981 | } |
| 1979 | callchain_cursor_commit(&callchain_cursor); | 1982 | callchain_cursor_commit(&callchain_cursor); |
| 1980 | 1983 | ||
| @@ -1991,65 +1994,93 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, | |||
| 1991 | if (node->sym && node->sym->ignore) | 1994 | if (node->sym && node->sym->ignore) |
| 1992 | goto next; | 1995 | goto next; |
| 1993 | 1996 | ||
| 1997 | printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); | ||
| 1998 | |||
| 1994 | if (print_ip) | 1999 | if (print_ip) |
| 1995 | printf("%c%16" PRIx64, s, node->ip); | 2000 | printed += fprintf(fp, "%c%16" PRIx64, s, node->ip); |
| 1996 | 2001 | ||
| 1997 | if (node->map) | 2002 | if (node->map) |
| 1998 | addr = node->map->map_ip(node->map, node->ip); | 2003 | addr = node->map->map_ip(node->map, node->ip); |
| 1999 | 2004 | ||
| 2000 | if (print_sym) { | 2005 | if (print_sym) { |
| 2001 | printf(" "); | 2006 | printed += fprintf(fp, " "); |
| 2007 | node_al.addr = addr; | ||
| 2008 | node_al.map = node->map; | ||
| 2009 | |||
| 2002 | if (print_symoffset) { | 2010 | if (print_symoffset) { |
| 2003 | node_al.addr = addr; | 2011 | printed += __symbol__fprintf_symname_offs(node->sym, &node_al, |
| 2004 | node_al.map = node->map; | 2012 | print_unknown_as_addr, fp); |
| 2005 | symbol__fprintf_symname_offs(node->sym, &node_al, stdout); | 2013 | } else { |
| 2006 | } else | 2014 | printed += __symbol__fprintf_symname(node->sym, &node_al, |
| 2007 | symbol__fprintf_symname(node->sym, stdout); | 2015 | print_unknown_as_addr, fp); |
| 2016 | } | ||
| 2008 | } | 2017 | } |
| 2009 | 2018 | ||
| 2010 | if (print_dso) { | 2019 | if (print_dso) { |
| 2011 | printf(" ("); | 2020 | printed += fprintf(fp, " ("); |
| 2012 | map__fprintf_dsoname(node->map, stdout); | 2021 | printed += map__fprintf_dsoname(node->map, fp); |
| 2013 | printf(")"); | 2022 | printed += fprintf(fp, ")"); |
| 2014 | } | 2023 | } |
| 2015 | 2024 | ||
| 2016 | if (print_srcline) | 2025 | if (print_srcline) |
| 2017 | map__fprintf_srcline(node->map, addr, "\n ", | 2026 | printed += map__fprintf_srcline(node->map, addr, "\n ", fp); |
| 2018 | stdout); | ||
| 2019 | 2027 | ||
| 2020 | if (!print_oneline) | 2028 | if (!print_oneline) |
| 2021 | printf("\n"); | 2029 | printed += fprintf(fp, "\n"); |
| 2022 | 2030 | ||
| 2023 | stack_depth--; | 2031 | stack_depth--; |
| 2024 | next: | 2032 | next: |
| 2025 | callchain_cursor_advance(&callchain_cursor); | 2033 | callchain_cursor_advance(&callchain_cursor); |
| 2026 | } | 2034 | } |
| 2035 | } | ||
| 2036 | |||
| 2037 | return printed; | ||
| 2038 | } | ||
| 2039 | |||
| 2040 | int perf_evsel__fprintf_sym(struct perf_evsel *evsel, struct perf_sample *sample, | ||
| 2041 | struct addr_location *al, int left_alignment, | ||
| 2042 | unsigned int print_opts, unsigned int stack_depth, | ||
| 2043 | FILE *fp) | ||
| 2044 | { | ||
| 2045 | int printed = 0; | ||
| 2046 | int print_ip = print_opts & PRINT_IP_OPT_IP; | ||
| 2047 | int print_sym = print_opts & PRINT_IP_OPT_SYM; | ||
| 2048 | int print_dso = print_opts & PRINT_IP_OPT_DSO; | ||
| 2049 | int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET; | ||
| 2050 | int print_srcline = print_opts & PRINT_IP_OPT_SRCLINE; | ||
| 2051 | int print_unknown_as_addr = print_opts & PRINT_IP_OPT_UNKNOWN_AS_ADDR; | ||
| 2027 | 2052 | ||
| 2028 | } else { | 2053 | if (symbol_conf.use_callchain && sample->callchain) { |
| 2029 | if (al->sym && al->sym->ignore) | 2054 | printed += perf_evsel__fprintf_callchain(evsel, sample, al, left_alignment, |
| 2030 | return; | 2055 | print_opts, stack_depth, fp); |
| 2056 | } else if (!(al->sym && al->sym->ignore)) { | ||
| 2057 | printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); | ||
| 2031 | 2058 | ||
| 2032 | if (print_ip) | 2059 | if (print_ip) |
| 2033 | printf("%16" PRIx64, sample->ip); | 2060 | printed += fprintf(fp, "%16" PRIx64, sample->ip); |
| 2034 | 2061 | ||
| 2035 | if (print_sym) { | 2062 | if (print_sym) { |
| 2036 | printf(" "); | 2063 | printed += fprintf(fp, " "); |
| 2037 | if (print_symoffset) | 2064 | if (print_symoffset) { |
| 2038 | symbol__fprintf_symname_offs(al->sym, al, | 2065 | printed += __symbol__fprintf_symname_offs(al->sym, al, |
| 2039 | stdout); | 2066 | print_unknown_as_addr, fp); |
| 2040 | else | 2067 | } else { |
| 2041 | symbol__fprintf_symname(al->sym, stdout); | 2068 | printed += __symbol__fprintf_symname(al->sym, al, |
| 2069 | print_unknown_as_addr, fp); | ||
| 2070 | } | ||
| 2042 | } | 2071 | } |
| 2043 | 2072 | ||
| 2044 | if (print_dso) { | 2073 | if (print_dso) { |
| 2045 | printf(" ("); | 2074 | printed += fprintf(fp, " ("); |
| 2046 | map__fprintf_dsoname(al->map, stdout); | 2075 | printed += map__fprintf_dsoname(al->map, fp); |
| 2047 | printf(")"); | 2076 | printed += fprintf(fp, ")"); |
| 2048 | } | 2077 | } |
| 2049 | 2078 | ||
| 2050 | if (print_srcline) | 2079 | if (print_srcline) |
| 2051 | map__fprintf_srcline(al->map, al->addr, "\n ", stdout); | 2080 | printed += map__fprintf_srcline(al->map, al->addr, "\n ", fp); |
| 2052 | } | 2081 | } |
| 2082 | |||
| 2083 | return printed; | ||
| 2053 | } | 2084 | } |
| 2054 | 2085 | ||
| 2055 | int perf_session__cpu_bitmap(struct perf_session *session, | 2086 | int perf_session__cpu_bitmap(struct perf_session *session, |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index f96fc9e8c52e..4257fac56618 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
| @@ -42,6 +42,7 @@ struct perf_session { | |||
| 42 | #define PRINT_IP_OPT_SYMOFFSET (1<<3) | 42 | #define PRINT_IP_OPT_SYMOFFSET (1<<3) |
| 43 | #define PRINT_IP_OPT_ONELINE (1<<4) | 43 | #define PRINT_IP_OPT_ONELINE (1<<4) |
| 44 | #define PRINT_IP_OPT_SRCLINE (1<<5) | 44 | #define PRINT_IP_OPT_SRCLINE (1<<5) |
| 45 | #define PRINT_IP_OPT_UNKNOWN_AS_ADDR (1<<6) | ||
| 45 | 46 | ||
| 46 | struct perf_tool; | 47 | struct perf_tool; |
| 47 | 48 | ||
| @@ -104,9 +105,10 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp); | |||
| 104 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | 105 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, |
| 105 | unsigned int type); | 106 | unsigned int type); |
| 106 | 107 | ||
| 107 | void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, | 108 | int perf_evsel__fprintf_sym(struct perf_evsel *evsel, struct perf_sample *sample, |
| 108 | struct addr_location *al, | 109 | struct addr_location *al, int left_alignment, |
| 109 | unsigned int print_opts, unsigned int stack_depth); | 110 | unsigned int print_opts, unsigned int stack_depth, |
| 111 | FILE *fp); | ||
| 110 | 112 | ||
| 111 | int perf_session__cpu_bitmap(struct perf_session *session, | 113 | int perf_session__cpu_bitmap(struct perf_session *session, |
| 112 | const char *cpu_list, unsigned long *cpu_bitmap); | 114 | const char *cpu_list, unsigned long *cpu_bitmap); |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e7588dc91518..bb162ee433c6 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
| @@ -264,8 +264,9 @@ size_t symbol__fprintf(struct symbol *sym, FILE *fp) | |||
| 264 | sym->name); | 264 | sym->name); |
| 265 | } | 265 | } |
| 266 | 266 | ||
| 267 | size_t symbol__fprintf_symname_offs(const struct symbol *sym, | 267 | size_t __symbol__fprintf_symname_offs(const struct symbol *sym, |
| 268 | const struct addr_location *al, FILE *fp) | 268 | const struct addr_location *al, |
| 269 | bool unknown_as_addr, FILE *fp) | ||
| 269 | { | 270 | { |
| 270 | unsigned long offset; | 271 | unsigned long offset; |
| 271 | size_t length; | 272 | size_t length; |
| @@ -280,13 +281,29 @@ size_t symbol__fprintf_symname_offs(const struct symbol *sym, | |||
| 280 | length += fprintf(fp, "+0x%lx", offset); | 281 | length += fprintf(fp, "+0x%lx", offset); |
| 281 | } | 282 | } |
| 282 | return length; | 283 | return length; |
| 283 | } else | 284 | } else if (al && unknown_as_addr) |
| 285 | return fprintf(fp, "[%#" PRIx64 "]", al->addr); | ||
| 286 | else | ||
| 284 | return fprintf(fp, "[unknown]"); | 287 | return fprintf(fp, "[unknown]"); |
| 285 | } | 288 | } |
| 286 | 289 | ||
| 290 | size_t symbol__fprintf_symname_offs(const struct symbol *sym, | ||
| 291 | const struct addr_location *al, | ||
| 292 | FILE *fp) | ||
| 293 | { | ||
| 294 | return __symbol__fprintf_symname_offs(sym, al, false, fp); | ||
| 295 | } | ||
| 296 | |||
| 297 | size_t __symbol__fprintf_symname(const struct symbol *sym, | ||
| 298 | const struct addr_location *al, | ||
| 299 | bool unknown_as_addr, FILE *fp) | ||
| 300 | { | ||
| 301 | return __symbol__fprintf_symname_offs(sym, al, unknown_as_addr, fp); | ||
| 302 | } | ||
| 303 | |||
| 287 | size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp) | 304 | size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp) |
| 288 | { | 305 | { |
| 289 | return symbol__fprintf_symname_offs(sym, NULL, fp); | 306 | return __symbol__fprintf_symname_offs(sym, NULL, false, fp); |
| 290 | } | 307 | } |
| 291 | 308 | ||
| 292 | void symbols__delete(struct rb_root *symbols) | 309 | void symbols__delete(struct rb_root *symbols) |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index c8b7544d9267..e2562568418d 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
| @@ -262,8 +262,14 @@ int symbol__init(struct perf_env *env); | |||
| 262 | void symbol__exit(void); | 262 | void symbol__exit(void); |
| 263 | void symbol__elf_init(void); | 263 | void symbol__elf_init(void); |
| 264 | struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name); | 264 | struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name); |
| 265 | size_t __symbol__fprintf_symname_offs(const struct symbol *sym, | ||
| 266 | const struct addr_location *al, | ||
| 267 | bool unknown_as_addr, FILE *fp); | ||
| 265 | size_t symbol__fprintf_symname_offs(const struct symbol *sym, | 268 | size_t symbol__fprintf_symname_offs(const struct symbol *sym, |
| 266 | const struct addr_location *al, FILE *fp); | 269 | const struct addr_location *al, FILE *fp); |
| 270 | size_t __symbol__fprintf_symname(const struct symbol *sym, | ||
| 271 | const struct addr_location *al, | ||
| 272 | bool unknown_as_addr, FILE *fp); | ||
| 267 | size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp); | 273 | size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp); |
| 268 | size_t symbol__fprintf(struct symbol *sym, FILE *fp); | 274 | size_t symbol__fprintf(struct symbol *sym, FILE *fp); |
| 269 | bool symbol_type__is_a(char symbol_type, enum map_type map_type); | 275 | bool symbol_type__is_a(char symbol_type, enum map_type map_type); |
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c index 08afc6909953..267112b4e3db 100644 --- a/tools/perf/util/thread_map.c +++ b/tools/perf/util/thread_map.c | |||
| @@ -94,7 +94,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid) | |||
| 94 | DIR *proc; | 94 | DIR *proc; |
| 95 | int max_threads = 32, items, i; | 95 | int max_threads = 32, items, i; |
| 96 | char path[256]; | 96 | char path[256]; |
| 97 | struct dirent dirent, *next, **namelist = NULL; | 97 | struct dirent *dirent, **namelist = NULL; |
| 98 | struct thread_map *threads = thread_map__alloc(max_threads); | 98 | struct thread_map *threads = thread_map__alloc(max_threads); |
| 99 | 99 | ||
| 100 | if (threads == NULL) | 100 | if (threads == NULL) |
| @@ -107,16 +107,16 @@ struct thread_map *thread_map__new_by_uid(uid_t uid) | |||
| 107 | threads->nr = 0; | 107 | threads->nr = 0; |
| 108 | atomic_set(&threads->refcnt, 1); | 108 | atomic_set(&threads->refcnt, 1); |
| 109 | 109 | ||
| 110 | while (!readdir_r(proc, &dirent, &next) && next) { | 110 | while ((dirent = readdir(proc)) != NULL) { |
| 111 | char *end; | 111 | char *end; |
| 112 | bool grow = false; | 112 | bool grow = false; |
| 113 | struct stat st; | 113 | struct stat st; |
| 114 | pid_t pid = strtol(dirent.d_name, &end, 10); | 114 | pid_t pid = strtol(dirent->d_name, &end, 10); |
| 115 | 115 | ||
| 116 | if (*end) /* only interested in proper numerical dirents */ | 116 | if (*end) /* only interested in proper numerical dirents */ |
| 117 | continue; | 117 | continue; |
| 118 | 118 | ||
| 119 | snprintf(path, sizeof(path), "/proc/%s", dirent.d_name); | 119 | snprintf(path, sizeof(path), "/proc/%s", dirent->d_name); |
| 120 | 120 | ||
| 121 | if (stat(path, &st) != 0) | 121 | if (stat(path, &st) != 0) |
| 122 | continue; | 122 | continue; |
