diff options
-rw-r--r-- | tools/perf/Documentation/perf-script.txt | 16 | ||||
-rw-r--r-- | tools/perf/builtin-script.c | 31 | ||||
-rw-r--r-- | tools/perf/util/session.c | 61 | ||||
-rw-r--r-- | tools/perf/util/session.h | 4 |
4 files changed, 110 insertions, 2 deletions
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index b73cf589c109..c64118a4de49 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt | |||
@@ -115,7 +115,21 @@ OPTIONS | |||
115 | -f:: | 115 | -f:: |
116 | --fields | 116 | --fields |
117 | Comma separated list of fields to print. Options are: | 117 | Comma separated list of fields to print. Options are: |
118 | comm, tid, pid, time, cpu, event, trace | 118 | comm, tid, pid, time, cpu, event, trace, sym |
119 | |||
120 | -k:: | ||
121 | --vmlinux=<file>:: | ||
122 | vmlinux pathname | ||
123 | |||
124 | --kallsyms=<file>:: | ||
125 | kallsyms pathname | ||
126 | |||
127 | --symfs=<directory>:: | ||
128 | Look for files with symbols relative to this directory. | ||
129 | |||
130 | -G:: | ||
131 | --hide-call-graph:: | ||
132 | When printing symbols do not display call chain. | ||
119 | 133 | ||
120 | SEE ALSO | 134 | SEE ALSO |
121 | -------- | 135 | -------- |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index c046e6e8600a..b45b09c13f7a 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -19,6 +19,7 @@ static bool debug_mode; | |||
19 | static u64 last_timestamp; | 19 | static u64 last_timestamp; |
20 | static u64 nr_unordered; | 20 | static u64 nr_unordered; |
21 | extern const struct option record_options[]; | 21 | extern const struct option record_options[]; |
22 | static bool no_callchain; | ||
22 | 23 | ||
23 | enum perf_output_field { | 24 | enum perf_output_field { |
24 | PERF_OUTPUT_COMM = 1U << 0, | 25 | PERF_OUTPUT_COMM = 1U << 0, |
@@ -28,6 +29,7 @@ enum perf_output_field { | |||
28 | PERF_OUTPUT_CPU = 1U << 4, | 29 | PERF_OUTPUT_CPU = 1U << 4, |
29 | PERF_OUTPUT_EVNAME = 1U << 5, | 30 | PERF_OUTPUT_EVNAME = 1U << 5, |
30 | PERF_OUTPUT_TRACE = 1U << 6, | 31 | PERF_OUTPUT_TRACE = 1U << 6, |
32 | PERF_OUTPUT_SYM = 1U << 7, | ||
31 | }; | 33 | }; |
32 | 34 | ||
33 | struct output_option { | 35 | struct output_option { |
@@ -41,6 +43,7 @@ struct output_option { | |||
41 | {.str = "cpu", .field = PERF_OUTPUT_CPU}, | 43 | {.str = "cpu", .field = PERF_OUTPUT_CPU}, |
42 | {.str = "event", .field = PERF_OUTPUT_EVNAME}, | 44 | {.str = "event", .field = PERF_OUTPUT_EVNAME}, |
43 | {.str = "trace", .field = PERF_OUTPUT_TRACE}, | 45 | {.str = "trace", .field = PERF_OUTPUT_TRACE}, |
46 | {.str = "sym", .field = PERF_OUTPUT_SYM}, | ||
44 | }; | 47 | }; |
45 | 48 | ||
46 | /* default set to maintain compatibility with current format */ | 49 | /* default set to maintain compatibility with current format */ |
@@ -65,6 +68,8 @@ static void print_sample_start(struct perf_sample *sample, | |||
65 | if (PRINT_FIELD(COMM)) { | 68 | if (PRINT_FIELD(COMM)) { |
66 | if (latency_format) | 69 | if (latency_format) |
67 | printf("%8.8s ", thread->comm); | 70 | printf("%8.8s ", thread->comm); |
71 | else if (PRINT_FIELD(SYM) && symbol_conf.use_callchain) | ||
72 | printf("%s ", thread->comm); | ||
68 | else | 73 | else |
69 | printf("%16s ", thread->comm); | 74 | printf("%16s ", thread->comm); |
70 | } | 75 | } |
@@ -112,6 +117,14 @@ static void process_event(union perf_event *event __unused, | |||
112 | print_trace_event(sample->cpu, sample->raw_data, | 117 | print_trace_event(sample->cpu, sample->raw_data, |
113 | sample->raw_size); | 118 | sample->raw_size); |
114 | 119 | ||
120 | if (PRINT_FIELD(SYM)) { | ||
121 | if (!symbol_conf.use_callchain) | ||
122 | printf(" "); | ||
123 | else | ||
124 | printf("\n"); | ||
125 | perf_session__print_symbols(event, sample, session); | ||
126 | } | ||
127 | |||
115 | printf("\n"); | 128 | printf("\n"); |
116 | } | 129 | } |
117 | 130 | ||
@@ -190,7 +203,10 @@ static int process_sample_event(union perf_event *event, | |||
190 | 203 | ||
191 | static struct perf_event_ops event_ops = { | 204 | static struct perf_event_ops event_ops = { |
192 | .sample = process_sample_event, | 205 | .sample = process_sample_event, |
206 | .mmap = perf_event__process_mmap, | ||
193 | .comm = perf_event__process_comm, | 207 | .comm = perf_event__process_comm, |
208 | .exit = perf_event__process_task, | ||
209 | .fork = perf_event__process_task, | ||
194 | .attr = perf_event__process_attr, | 210 | .attr = perf_event__process_attr, |
195 | .event_type = perf_event__process_event_type, | 211 | .event_type = perf_event__process_event_type, |
196 | .tracing_data = perf_event__process_tracing_data, | 212 | .tracing_data = perf_event__process_tracing_data, |
@@ -722,8 +738,16 @@ static const struct option options[] = { | |||
722 | "input file name"), | 738 | "input file name"), |
723 | OPT_BOOLEAN('d', "debug-mode", &debug_mode, | 739 | OPT_BOOLEAN('d', "debug-mode", &debug_mode, |
724 | "do various checks like samples ordering and lost events"), | 740 | "do various checks like samples ordering and lost events"), |
741 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, | ||
742 | "file", "vmlinux pathname"), | ||
743 | OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, | ||
744 | "file", "kallsyms pathname"), | ||
745 | OPT_BOOLEAN('G', "hide-call-graph", &no_callchain, | ||
746 | "When printing symbols do not display call chain"), | ||
747 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", | ||
748 | "Look for files with symbols relative to this directory"), | ||
725 | OPT_CALLBACK('f', "fields", NULL, "str", | 749 | OPT_CALLBACK('f', "fields", NULL, "str", |
726 | "comma separated output fields. Options: comm,tid,pid,time,cpu,event,trace", | 750 | "comma separated output fields. Options: comm,tid,pid,time,cpu,event,trace,sym", |
727 | parse_output_fields), | 751 | parse_output_fields), |
728 | 752 | ||
729 | OPT_END() | 753 | OPT_END() |
@@ -905,6 +929,11 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) | |||
905 | if (session == NULL) | 929 | if (session == NULL) |
906 | return -ENOMEM; | 930 | return -ENOMEM; |
907 | 931 | ||
932 | if (!no_callchain && (session->sample_type & PERF_SAMPLE_CALLCHAIN)) | ||
933 | symbol_conf.use_callchain = true; | ||
934 | else | ||
935 | symbol_conf.use_callchain = false; | ||
936 | |||
908 | if (strcmp(input_name, "-") && | 937 | if (strcmp(input_name, "-") && |
909 | !perf_session__has_traces(session, "record -R")) | 938 | !perf_session__has_traces(session, "record -R")) |
910 | return -EINVAL; | 939 | return -EINVAL; |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index f26639fa0fb3..c68cf40764f9 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -1134,3 +1134,64 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) | |||
1134 | 1134 | ||
1135 | return ret; | 1135 | return ret; |
1136 | } | 1136 | } |
1137 | |||
1138 | void perf_session__print_symbols(union perf_event *event, | ||
1139 | struct perf_sample *sample, | ||
1140 | struct perf_session *session) | ||
1141 | { | ||
1142 | struct addr_location al; | ||
1143 | const char *symname, *dsoname; | ||
1144 | struct callchain_cursor *cursor = &session->callchain_cursor; | ||
1145 | struct callchain_cursor_node *node; | ||
1146 | |||
1147 | if (perf_event__preprocess_sample(event, session, &al, sample, | ||
1148 | NULL) < 0) { | ||
1149 | error("problem processing %d event, skipping it.\n", | ||
1150 | event->header.type); | ||
1151 | return; | ||
1152 | } | ||
1153 | |||
1154 | if (symbol_conf.use_callchain && sample->callchain) { | ||
1155 | |||
1156 | if (perf_session__resolve_callchain(session, al.thread, | ||
1157 | sample->callchain, NULL) != 0) { | ||
1158 | if (verbose) | ||
1159 | error("Failed to resolve callchain. Skipping\n"); | ||
1160 | return; | ||
1161 | } | ||
1162 | callchain_cursor_commit(cursor); | ||
1163 | |||
1164 | while (1) { | ||
1165 | node = callchain_cursor_current(cursor); | ||
1166 | if (!node) | ||
1167 | break; | ||
1168 | |||
1169 | if (node->sym && node->sym->name) | ||
1170 | symname = node->sym->name; | ||
1171 | else | ||
1172 | symname = ""; | ||
1173 | |||
1174 | if (node->map && node->map->dso && node->map->dso->name) | ||
1175 | dsoname = node->map->dso->name; | ||
1176 | else | ||
1177 | dsoname = ""; | ||
1178 | |||
1179 | printf("\t%16" PRIx64 " %s (%s)\n", node->ip, symname, dsoname); | ||
1180 | |||
1181 | callchain_cursor_advance(cursor); | ||
1182 | } | ||
1183 | |||
1184 | } else { | ||
1185 | if (al.sym && al.sym->name) | ||
1186 | symname = al.sym->name; | ||
1187 | else | ||
1188 | symname = ""; | ||
1189 | |||
1190 | if (al.map && al.map->dso && al.map->dso->name) | ||
1191 | dsoname = al.map->dso->name; | ||
1192 | else | ||
1193 | dsoname = ""; | ||
1194 | |||
1195 | printf("%16" PRIx64 " %s (%s)", al.addr, symname, dsoname); | ||
1196 | } | ||
1197 | } | ||
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index b5b148b0aaca..0b3c9afecaa9 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -159,4 +159,8 @@ static inline int perf_session__parse_sample(struct perf_session *session, | |||
159 | session->sample_id_all, sample); | 159 | session->sample_id_all, sample); |
160 | } | 160 | } |
161 | 161 | ||
162 | void perf_session__print_symbols(union perf_event *event, | ||
163 | struct perf_sample *sample, | ||
164 | struct perf_session *session); | ||
165 | |||
162 | #endif /* __PERF_SESSION_H */ | 166 | #endif /* __PERF_SESSION_H */ |