diff options
Diffstat (limited to 'tools/perf/builtin-diff.c')
| -rw-r--r-- | tools/perf/builtin-diff.c | 96 |
1 files changed, 63 insertions, 33 deletions
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index d29d350fb2b7..761f4197a9e2 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include "util/event.h" | 10 | #include "util/event.h" |
| 11 | #include "util/hist.h" | 11 | #include "util/hist.h" |
| 12 | #include "util/evsel.h" | 12 | #include "util/evsel.h" |
| 13 | #include "util/evlist.h" | ||
| 13 | #include "util/session.h" | 14 | #include "util/session.h" |
| 14 | #include "util/tool.h" | 15 | #include "util/tool.h" |
| 15 | #include "util/sort.h" | 16 | #include "util/sort.h" |
| @@ -24,11 +25,6 @@ static char diff__default_sort_order[] = "dso,symbol"; | |||
| 24 | static bool force; | 25 | static bool force; |
| 25 | static bool show_displacement; | 26 | static bool show_displacement; |
| 26 | 27 | ||
| 27 | struct perf_diff { | ||
| 28 | struct perf_tool tool; | ||
| 29 | struct perf_session *session; | ||
| 30 | }; | ||
| 31 | |||
| 32 | static int hists__add_entry(struct hists *self, | 28 | static int hists__add_entry(struct hists *self, |
| 33 | struct addr_location *al, u64 period) | 29 | struct addr_location *al, u64 period) |
| 34 | { | 30 | { |
| @@ -37,14 +33,12 @@ static int hists__add_entry(struct hists *self, | |||
| 37 | return -ENOMEM; | 33 | return -ENOMEM; |
| 38 | } | 34 | } |
| 39 | 35 | ||
| 40 | static int diff__process_sample_event(struct perf_tool *tool, | 36 | static int diff__process_sample_event(struct perf_tool *tool __maybe_unused, |
| 41 | union perf_event *event, | 37 | union perf_event *event, |
| 42 | struct perf_sample *sample, | 38 | struct perf_sample *sample, |
| 43 | struct perf_evsel *evsel __used, | 39 | struct perf_evsel *evsel, |
| 44 | struct machine *machine) | 40 | struct machine *machine) |
| 45 | { | 41 | { |
| 46 | struct perf_diff *_diff = container_of(tool, struct perf_diff, tool); | ||
| 47 | struct perf_session *session = _diff->session; | ||
| 48 | struct addr_location al; | 42 | struct addr_location al; |
| 49 | 43 | ||
| 50 | if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) { | 44 | if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) { |
| @@ -56,26 +50,24 @@ static int diff__process_sample_event(struct perf_tool *tool, | |||
| 56 | if (al.filtered || al.sym == NULL) | 50 | if (al.filtered || al.sym == NULL) |
| 57 | return 0; | 51 | return 0; |
| 58 | 52 | ||
| 59 | if (hists__add_entry(&session->hists, &al, sample->period)) { | 53 | if (hists__add_entry(&evsel->hists, &al, sample->period)) { |
| 60 | pr_warning("problem incrementing symbol period, skipping event\n"); | 54 | pr_warning("problem incrementing symbol period, skipping event\n"); |
| 61 | return -1; | 55 | return -1; |
| 62 | } | 56 | } |
| 63 | 57 | ||
| 64 | session->hists.stats.total_period += sample->period; | 58 | evsel->hists.stats.total_period += sample->period; |
| 65 | return 0; | 59 | return 0; |
| 66 | } | 60 | } |
| 67 | 61 | ||
| 68 | static struct perf_diff diff = { | 62 | static struct perf_tool tool = { |
| 69 | .tool = { | 63 | .sample = diff__process_sample_event, |
| 70 | .sample = diff__process_sample_event, | 64 | .mmap = perf_event__process_mmap, |
| 71 | .mmap = perf_event__process_mmap, | 65 | .comm = perf_event__process_comm, |
| 72 | .comm = perf_event__process_comm, | 66 | .exit = perf_event__process_task, |
| 73 | .exit = perf_event__process_task, | 67 | .fork = perf_event__process_task, |
| 74 | .fork = perf_event__process_task, | 68 | .lost = perf_event__process_lost, |
| 75 | .lost = perf_event__process_lost, | 69 | .ordered_samples = true, |
| 76 | .ordered_samples = true, | 70 | .ordering_requires_timestamps = true, |
| 77 | .ordering_requires_timestamps = true, | ||
| 78 | }, | ||
| 79 | }; | 71 | }; |
| 80 | 72 | ||
| 81 | static void perf_session__insert_hist_entry_by_name(struct rb_root *root, | 73 | static void perf_session__insert_hist_entry_by_name(struct rb_root *root, |
| @@ -146,34 +138,71 @@ static void hists__match(struct hists *older, struct hists *newer) | |||
| 146 | } | 138 | } |
| 147 | } | 139 | } |
| 148 | 140 | ||
| 141 | static struct perf_evsel *evsel_match(struct perf_evsel *evsel, | ||
| 142 | struct perf_evlist *evlist) | ||
| 143 | { | ||
| 144 | struct perf_evsel *e; | ||
| 145 | |||
| 146 | list_for_each_entry(e, &evlist->entries, node) | ||
| 147 | if (perf_evsel__match2(evsel, e)) | ||
| 148 | return e; | ||
| 149 | |||
| 150 | return NULL; | ||
| 151 | } | ||
| 152 | |||
| 149 | static int __cmd_diff(void) | 153 | static int __cmd_diff(void) |
| 150 | { | 154 | { |
| 151 | int ret, i; | 155 | int ret, i; |
| 152 | #define older (session[0]) | 156 | #define older (session[0]) |
| 153 | #define newer (session[1]) | 157 | #define newer (session[1]) |
| 154 | struct perf_session *session[2]; | 158 | struct perf_session *session[2]; |
| 159 | struct perf_evlist *evlist_new, *evlist_old; | ||
| 160 | struct perf_evsel *evsel; | ||
| 161 | bool first = true; | ||
| 155 | 162 | ||
| 156 | older = perf_session__new(input_old, O_RDONLY, force, false, | 163 | older = perf_session__new(input_old, O_RDONLY, force, false, |
| 157 | &diff.tool); | 164 | &tool); |
| 158 | newer = perf_session__new(input_new, O_RDONLY, force, false, | 165 | newer = perf_session__new(input_new, O_RDONLY, force, false, |
| 159 | &diff.tool); | 166 | &tool); |
| 160 | if (session[0] == NULL || session[1] == NULL) | 167 | if (session[0] == NULL || session[1] == NULL) |
| 161 | return -ENOMEM; | 168 | return -ENOMEM; |
| 162 | 169 | ||
| 163 | for (i = 0; i < 2; ++i) { | 170 | for (i = 0; i < 2; ++i) { |
| 164 | diff.session = session[i]; | 171 | ret = perf_session__process_events(session[i], &tool); |
| 165 | ret = perf_session__process_events(session[i], &diff.tool); | ||
| 166 | if (ret) | 172 | if (ret) |
| 167 | goto out_delete; | 173 | goto out_delete; |
| 168 | hists__output_resort(&session[i]->hists); | ||
| 169 | } | 174 | } |
| 170 | 175 | ||
| 171 | if (show_displacement) | 176 | evlist_old = older->evlist; |
| 172 | hists__resort_entries(&older->hists); | 177 | evlist_new = newer->evlist; |
| 178 | |||
| 179 | list_for_each_entry(evsel, &evlist_new->entries, node) | ||
| 180 | hists__output_resort(&evsel->hists); | ||
| 181 | |||
| 182 | list_for_each_entry(evsel, &evlist_old->entries, node) { | ||
| 183 | hists__output_resort(&evsel->hists); | ||
| 184 | |||
| 185 | if (show_displacement) | ||
| 186 | hists__resort_entries(&evsel->hists); | ||
| 187 | } | ||
| 188 | |||
| 189 | list_for_each_entry(evsel, &evlist_new->entries, node) { | ||
| 190 | struct perf_evsel *evsel_old; | ||
| 191 | |||
| 192 | evsel_old = evsel_match(evsel, evlist_old); | ||
| 193 | if (!evsel_old) | ||
| 194 | continue; | ||
| 195 | |||
| 196 | fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n", | ||
| 197 | perf_evsel__name(evsel)); | ||
| 198 | |||
| 199 | first = false; | ||
| 200 | |||
| 201 | hists__match(&evsel_old->hists, &evsel->hists); | ||
| 202 | hists__fprintf(&evsel->hists, &evsel_old->hists, | ||
| 203 | show_displacement, true, 0, 0, stdout); | ||
| 204 | } | ||
| 173 | 205 | ||
| 174 | hists__match(&older->hists, &newer->hists); | ||
| 175 | hists__fprintf(&newer->hists, &older->hists, | ||
| 176 | show_displacement, true, 0, 0, stdout); | ||
| 177 | out_delete: | 206 | out_delete: |
| 178 | for (i = 0; i < 2; ++i) | 207 | for (i = 0; i < 2; ++i) |
| 179 | perf_session__delete(session[i]); | 208 | perf_session__delete(session[i]); |
| @@ -213,7 +242,7 @@ static const struct option options[] = { | |||
| 213 | OPT_END() | 242 | OPT_END() |
| 214 | }; | 243 | }; |
| 215 | 244 | ||
| 216 | int cmd_diff(int argc, const char **argv, const char *prefix __used) | 245 | int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) |
| 217 | { | 246 | { |
| 218 | sort_order = diff__default_sort_order; | 247 | sort_order = diff__default_sort_order; |
| 219 | argc = parse_options(argc, argv, options, diff_usage, 0); | 248 | argc = parse_options(argc, argv, options, diff_usage, 0); |
| @@ -235,6 +264,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix __used) | |||
| 235 | if (symbol__init() < 0) | 264 | if (symbol__init() < 0) |
| 236 | return -1; | 265 | return -1; |
| 237 | 266 | ||
| 267 | perf_hpp__init(true, show_displacement); | ||
| 238 | setup_sorting(diff_usage, options); | 268 | setup_sorting(diff_usage, options); |
| 239 | setup_pager(); | 269 | setup_pager(); |
| 240 | 270 | ||
