diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2009-12-16 10:49:27 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-12-16 10:53:37 -0500 |
commit | c351c2816177eb7d2979ec874b9b895abe9d6e5c (patch) | |
tree | b6dd7fb4a5e048168319111e18082025c2e93f1b /tools/perf/builtin-diff.c | |
parent | 125c4fad1e60751ceaab1ee2a73bddf31213e5ca (diff) |
perf diff: Use perf_session__fprintf_hists just like 'perf record'
That means that almost everything you can do with 'perf report'
can be done with 'perf diff', for instance:
$ perf record -f find / > /dev/null
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.062 MB perf.data (~2699
samples) ] $ perf record -f find / > /dev/null
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.062 MB perf.data (~2687
samples) ] perf diff | head -8
9.02% +1.00% find libc-2.10.1.so [.] _IO_vfprintf_internal
2.91% -1.00% find [kernel] [k] __kmalloc
2.85% -1.00% find [kernel] [k] ext4_htree_store_dirent
1.99% -1.00% find [kernel] [k] _atomic_dec_and_lock
2.44% find [kernel] [k] half_md4_transform
$
So if you want to zoom into libc:
$ perf diff --dsos libc-2.10.1.so | head -8
37.34% find [.] _IO_vfprintf_internal
10.34% find [.] __GI_memmove
8.25% +2.00% find [.] _int_malloc
5.07% -1.00% find [.] __GI_mempcpy
7.62% +2.00% find [.] _int_free
$
And if there were multiple commands using libc, it is also
possible to aggregate them all by using --sort symbol:
$ perf diff --dsos libc-2.10.1.so --sort symbol | head -8
37.34% [.] _IO_vfprintf_internal
10.34% [.] __GI_memmove
8.25% +2.00% [.] _int_malloc
5.07% -1.00% [.] __GI_mempcpy
7.62% +2.00% [.] _int_free
$
The displacement column now is off by default, to use it:
perf diff -m --dsos libc-2.10.1.so --sort symbol | head -8
37.34% [.] _IO_vfprintf_internal
10.34% [.] __GI_memmove
8.25% +2.00% [.] _int_malloc
5.07% -1.00% +2 [.] __GI_mempcpy
7.62% +2.00% -1 [.] _int_free
$
Using -t/--field-separator can be used for scripting:
$ perf diff -t, -m --dsos libc-2.10.1.so --sort symbol | head -8
37.34, , ,[.] _IO_vfprintf_internal
10.34, , ,[.] __GI_memmove
8.25,+2.00%, ,[.] _int_malloc
5.07,-1.00%, +2,[.] __GI_mempcpy
7.62,+2.00%, -1,[.] _int_free
6.99,+1.00%, -1,[.] _IO_new_file_xsputn
1.89,-2.00%, +4,[.] __readdir64
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <1260978567-550-1-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/builtin-diff.c')
-rw-r--r-- | tools/perf/builtin-diff.c | 90 |
1 files changed, 19 insertions, 71 deletions
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index ff91e9c291bb..66f100d249a8 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -16,10 +16,10 @@ | |||
16 | 16 | ||
17 | #include <stdlib.h> | 17 | #include <stdlib.h> |
18 | 18 | ||
19 | static char const *input_old = "perf.data.old", | 19 | static char const *input_old = "perf.data.old", |
20 | *input_new = "perf.data"; | 20 | *input_new = "perf.data"; |
21 | static int force; | 21 | static int force; |
22 | static bool show_percent; | 22 | static bool show_displacement; |
23 | 23 | ||
24 | static int perf_session__add_hist_entry(struct perf_session *self, | 24 | static int perf_session__add_hist_entry(struct perf_session *self, |
25 | struct addr_location *al, u64 count) | 25 | struct addr_location *al, u64 count) |
@@ -162,70 +162,6 @@ static void perf_session__match_hists(struct perf_session *old_session, | |||
162 | } | 162 | } |
163 | } | 163 | } |
164 | 164 | ||
165 | static size_t hist_entry__fprintf_matched(struct hist_entry *self, | ||
166 | unsigned long pos, | ||
167 | struct perf_session *session, | ||
168 | struct perf_session *pair_session, | ||
169 | FILE *fp) | ||
170 | { | ||
171 | u64 old_count = 0; | ||
172 | char displacement[16]; | ||
173 | size_t printed; | ||
174 | |||
175 | if (self->pair != NULL) { | ||
176 | long pdiff = (long)self->pair->position - (long)pos; | ||
177 | old_count = self->pair->count; | ||
178 | if (pdiff == 0) | ||
179 | goto blank; | ||
180 | snprintf(displacement, sizeof(displacement), "%+4ld", pdiff); | ||
181 | } else { | ||
182 | blank: memset(displacement, ' ', sizeof(displacement)); | ||
183 | } | ||
184 | |||
185 | printed = fprintf(fp, "%4lu %5.5s ", pos, displacement); | ||
186 | |||
187 | if (show_percent) { | ||
188 | double old_percent = 0, new_percent = 0, diff; | ||
189 | |||
190 | if (pair_session->events_stats.total > 0) | ||
191 | old_percent = (old_count * 100) / pair_session->events_stats.total; | ||
192 | if (session->events_stats.total > 0) | ||
193 | new_percent = (self->count * 100) / session->events_stats.total; | ||
194 | |||
195 | diff = old_percent - new_percent; | ||
196 | if (verbose) | ||
197 | printed += fprintf(fp, " %3.2f%% %3.2f%%", old_percent, new_percent); | ||
198 | |||
199 | if ((u64)diff != 0) | ||
200 | printed += fprintf(fp, " %+4.2F%%", diff); | ||
201 | else | ||
202 | printed += fprintf(fp, " "); | ||
203 | } else { | ||
204 | if (verbose) | ||
205 | printed += fprintf(fp, " %9Lu %9Lu", old_count, self->count); | ||
206 | printed += fprintf(fp, " %+9Ld", (s64)self->count - (s64)old_count); | ||
207 | } | ||
208 | |||
209 | return printed + fprintf(fp, " %25.25s %s\n", | ||
210 | self->map->dso->name, self->sym->name); | ||
211 | } | ||
212 | |||
213 | static size_t perf_session__fprintf_matched_hists(struct perf_session *self, | ||
214 | struct perf_session *pair, | ||
215 | FILE *fp) | ||
216 | { | ||
217 | struct rb_node *nd; | ||
218 | size_t printed = 0; | ||
219 | unsigned long pos = 1; | ||
220 | |||
221 | for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) { | ||
222 | struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); | ||
223 | printed += hist_entry__fprintf_matched(he, pos++, self, pair, fp); | ||
224 | } | ||
225 | |||
226 | return printed; | ||
227 | } | ||
228 | |||
229 | static int __cmd_diff(void) | 165 | static int __cmd_diff(void) |
230 | { | 166 | { |
231 | int ret, i; | 167 | int ret, i; |
@@ -244,7 +180,8 @@ static int __cmd_diff(void) | |||
244 | } | 180 | } |
245 | 181 | ||
246 | perf_session__match_hists(session[0], session[1]); | 182 | perf_session__match_hists(session[0], session[1]); |
247 | perf_session__fprintf_matched_hists(session[1], session[0], stdout); | 183 | perf_session__fprintf_hists(session[1], session[0], |
184 | show_displacement, stdout); | ||
248 | out_delete: | 185 | out_delete: |
249 | for (i = 0; i < 2; ++i) | 186 | for (i = 0; i < 2; ++i) |
250 | perf_session__delete(session[i]); | 187 | perf_session__delete(session[i]); |
@@ -258,13 +195,13 @@ static const char *const diff_usage[] = { | |||
258 | static const struct option options[] = { | 195 | static const struct option options[] = { |
259 | OPT_BOOLEAN('v', "verbose", &verbose, | 196 | OPT_BOOLEAN('v', "verbose", &verbose, |
260 | "be more verbose (show symbol address, etc)"), | 197 | "be more verbose (show symbol address, etc)"), |
198 | OPT_BOOLEAN('m', "displacement", &show_displacement, | ||
199 | "Show position displacement relative to baseline"), | ||
261 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, | 200 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, |
262 | "dump raw trace in ASCII"), | 201 | "dump raw trace in ASCII"), |
263 | OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), | 202 | OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), |
264 | OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, | 203 | OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, |
265 | "load module symbols - WARNING: use only with -k and LIVE kernel"), | 204 | "load module symbols - WARNING: use only with -k and LIVE kernel"), |
266 | OPT_BOOLEAN('p', "percentages", &show_percent, | ||
267 | "Don't shorten the pathnames taking into account the cwd"), | ||
268 | OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths, | 205 | OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths, |
269 | "Don't shorten the pathnames taking into account the cwd"), | 206 | "Don't shorten the pathnames taking into account the cwd"), |
270 | OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", | 207 | OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", |
@@ -273,6 +210,11 @@ static const struct option options[] = { | |||
273 | "only consider symbols in these comms"), | 210 | "only consider symbols in these comms"), |
274 | OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", | 211 | OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", |
275 | "only consider these symbols"), | 212 | "only consider these symbols"), |
213 | OPT_STRING('s', "sort", &sort_order, "key[,key2...]", | ||
214 | "sort by key(s): pid, comm, dso, symbol, parent"), | ||
215 | OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator", | ||
216 | "separator for columns, no spaces will be added between " | ||
217 | "columns '.' is reserved."), | ||
276 | OPT_END() | 218 | OPT_END() |
277 | }; | 219 | }; |
278 | 220 | ||
@@ -289,10 +231,16 @@ int cmd_diff(int argc, const char **argv, const char *prefix __used) | |||
289 | input_new = argv[0]; | 231 | input_new = argv[0]; |
290 | } | 232 | } |
291 | 233 | ||
234 | symbol_conf.exclude_other = false; | ||
292 | if (symbol__init() < 0) | 235 | if (symbol__init() < 0) |
293 | return -1; | 236 | return -1; |
294 | 237 | ||
295 | setup_sorting(diff_usage, options); | 238 | setup_sorting(diff_usage, options); |
296 | setup_pager(); | 239 | setup_pager(); |
240 | |||
241 | sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL); | ||
242 | sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", NULL); | ||
243 | sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", NULL); | ||
244 | |||
297 | return __cmd_diff(); | 245 | return __cmd_diff(); |
298 | } | 246 | } |