diff options
-rw-r--r-- | tools/perf/Documentation/perf-diff.txt | 3 | ||||
-rw-r--r-- | tools/perf/builtin-diff.c | 93 | ||||
-rw-r--r-- | tools/perf/util/evsel.h | 7 | ||||
-rw-r--r-- | tools/perf/util/session.h | 4 |
4 files changed, 72 insertions, 35 deletions
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt index 74d7481ed7a..ab7f667de1b 100644 --- a/tools/perf/Documentation/perf-diff.txt +++ b/tools/perf/Documentation/perf-diff.txt | |||
@@ -17,6 +17,9 @@ captured via perf record. | |||
17 | 17 | ||
18 | If no parameters are passed it will assume perf.data.old and perf.data. | 18 | If no parameters are passed it will assume perf.data.old and perf.data. |
19 | 19 | ||
20 | The differential profile is displayed only for events matching both | ||
21 | specified perf.data files. | ||
22 | |||
20 | OPTIONS | 23 | OPTIONS |
21 | ------- | 24 | ------- |
22 | -M:: | 25 | -M:: |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index d29d350fb2b..e9933fdd256 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 __used, |
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]); |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index a3f562cec43..390690eb878 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -124,6 +124,13 @@ void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads); | |||
124 | (evsel->attr.type == PERF_TYPE_##t && \ | 124 | (evsel->attr.type == PERF_TYPE_##t && \ |
125 | evsel->attr.config == PERF_COUNT_##c) | 125 | evsel->attr.config == PERF_COUNT_##c) |
126 | 126 | ||
127 | static inline bool perf_evsel__match2(struct perf_evsel *e1, | ||
128 | struct perf_evsel *e2) | ||
129 | { | ||
130 | return (e1->attr.type == e2->attr.type) && | ||
131 | (e1->attr.config == e2->attr.config); | ||
132 | } | ||
133 | |||
127 | int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, | 134 | int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, |
128 | int cpu, int thread, bool scale); | 135 | int cpu, int thread, bool scale); |
129 | 136 | ||
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 176a60902f5..aab414fbb64 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -36,9 +36,7 @@ struct perf_session { | |||
36 | struct pevent *pevent; | 36 | struct pevent *pevent; |
37 | /* | 37 | /* |
38 | * FIXME: Need to split this up further, we need global | 38 | * FIXME: Need to split this up further, we need global |
39 | * stats + per event stats. 'perf diff' also needs | 39 | * stats + per event stats. |
40 | * to properly support multiple events in a single | ||
41 | * perf.data file. | ||
42 | */ | 40 | */ |
43 | struct hists hists; | 41 | struct hists hists; |
44 | int fd; | 42 | int fd; |