Blame view
tools/perf/builtin-diff.c
6.41 KB
86a9eee04 perf diff: Introd... |
1 2 3 4 5 6 7 8 9 10 11 |
/* * builtin-diff.c * * Builtin diff command: Analyze two perf.data input files, look up and read * DSOs and symbol information, sort them and produce a diff. */ #include "builtin.h" #include "util/debug.h" #include "util/event.h" #include "util/hist.h" |
743eb8686 perf tools: Resol... |
12 |
#include "util/evsel.h" |
86a9eee04 perf diff: Introd... |
13 |
#include "util/session.h" |
45694aa77 perf tools: Renam... |
14 |
#include "util/tool.h" |
86a9eee04 perf diff: Introd... |
15 16 17 18 19 |
#include "util/sort.h" #include "util/symbol.h" #include "util/util.h" #include <stdlib.h> |
c351c2816 perf diff: Use pe... |
20 21 |
static char const *input_old = "perf.data.old", *input_new = "perf.data"; |
604c5c929 perf diff: Change... |
22 |
static char diff__default_sort_order[] = "dso,symbol"; |
c05556421 perf: Fix endiann... |
23 |
static bool force; |
c351c2816 perf diff: Use pe... |
24 |
static bool show_displacement; |
86a9eee04 perf diff: Introd... |
25 |
|
1c02c4d2e perf hist: Introd... |
26 |
static int hists__add_entry(struct hists *self, |
c82ee828a perf report: Repo... |
27 |
struct addr_location *al, u64 period) |
86a9eee04 perf diff: Introd... |
28 |
{ |
c82ee828a perf report: Repo... |
29 |
if (__hists__add_entry(self, al, NULL, period) != NULL) |
28e2a106d perf hist: Simpli... |
30 31 |
return 0; return -ENOMEM; |
86a9eee04 perf diff: Introd... |
32 |
} |
45694aa77 perf tools: Renam... |
33 |
static int diff__process_sample_event(struct perf_tool *tool __used, |
d20deb64e perf tools: Pass ... |
34 |
union perf_event *event, |
8d50e5b41 perf tools: Renam... |
35 |
struct perf_sample *sample, |
9e69c2108 perf session: Pas... |
36 |
struct perf_evsel *evsel __used, |
743eb8686 perf tools: Resol... |
37 |
struct machine *machine) |
86a9eee04 perf diff: Introd... |
38 39 |
{ struct addr_location al; |
86a9eee04 perf diff: Introd... |
40 |
|
743eb8686 perf tools: Resol... |
41 |
if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) { |
86a9eee04 perf diff: Introd... |
42 43 44 45 46 |
pr_warning("problem processing %d event, skipping it. ", event->header.type); return -1; } |
cdbae3140 perf diff: Don't ... |
47 |
if (al.filtered || al.sym == NULL) |
c410a3388 perf symbols: Mov... |
48 |
return 0; |
743eb8686 perf tools: Resol... |
49 |
if (hists__add_entry(&evsel->hists, &al, sample->period)) { |
c82ee828a perf report: Repo... |
50 51 |
pr_warning("problem incrementing symbol period, skipping event "); |
86a9eee04 perf diff: Introd... |
52 53 |
return -1; } |
743eb8686 perf tools: Resol... |
54 |
evsel->hists.stats.total_period += sample->period; |
86a9eee04 perf diff: Introd... |
55 56 |
return 0; } |
45694aa77 perf tools: Renam... |
57 |
static struct perf_tool perf_diff = { |
55aa640f5 perf session: Rem... |
58 |
.sample = diff__process_sample_event, |
8115d60c3 perf tools: Kill ... |
59 60 61 62 63 |
.mmap = perf_event__process_mmap, .comm = perf_event__process_comm, .exit = perf_event__process_task, .fork = perf_event__process_task, .lost = perf_event__process_lost, |
eac23d1c3 perf record,repor... |
64 65 |
.ordered_samples = true, .ordering_requires_timestamps = true, |
86a9eee04 perf diff: Introd... |
66 67 68 69 70 71 72 73 74 75 |
}; static void perf_session__insert_hist_entry_by_name(struct rb_root *root, struct hist_entry *he) { struct rb_node **p = &root->rb_node; struct rb_node *parent = NULL; struct hist_entry *iter; while (*p != NULL) { |
86a9eee04 perf diff: Introd... |
76 77 |
parent = *p; iter = rb_entry(parent, struct hist_entry, rb_node); |
9c443dfdd perf diff: Fix su... |
78 |
if (hist_entry__cmp(he, iter) < 0) |
86a9eee04 perf diff: Introd... |
79 |
p = &(*p)->rb_left; |
9c443dfdd perf diff: Fix su... |
80 |
else |
86a9eee04 perf diff: Introd... |
81 |
p = &(*p)->rb_right; |
86a9eee04 perf diff: Introd... |
82 83 84 85 86 |
} rb_link_node(&he->rb_node, parent, p); rb_insert_color(&he->rb_node, root); } |
1c02c4d2e perf hist: Introd... |
87 |
static void hists__resort_entries(struct hists *self) |
86a9eee04 perf diff: Introd... |
88 89 90 |
{ unsigned long position = 1; struct rb_root tmp = RB_ROOT; |
1c02c4d2e perf hist: Introd... |
91 |
struct rb_node *next = rb_first(&self->entries); |
86a9eee04 perf diff: Introd... |
92 93 94 95 96 |
while (next != NULL) { struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node); next = rb_next(&n->rb_node); |
1c02c4d2e perf hist: Introd... |
97 |
rb_erase(&n->rb_node, &self->entries); |
86a9eee04 perf diff: Introd... |
98 99 100 |
n->position = position++; perf_session__insert_hist_entry_by_name(&tmp, n); } |
1c02c4d2e perf hist: Introd... |
101 |
self->entries = tmp; |
86a9eee04 perf diff: Introd... |
102 |
} |
1c02c4d2e perf hist: Introd... |
103 |
static void hists__set_positions(struct hists *self) |
9c443dfdd perf diff: Fix su... |
104 |
{ |
1c02c4d2e perf hist: Introd... |
105 106 |
hists__output_resort(self); hists__resort_entries(self); |
9c443dfdd perf diff: Fix su... |
107 |
} |
1c02c4d2e perf hist: Introd... |
108 109 |
static struct hist_entry *hists__find_entry(struct hists *self, struct hist_entry *he) |
86a9eee04 perf diff: Introd... |
110 |
{ |
1c02c4d2e perf hist: Introd... |
111 |
struct rb_node *n = self->entries.rb_node; |
86a9eee04 perf diff: Introd... |
112 113 114 |
while (n) { struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node); |
9c443dfdd perf diff: Fix su... |
115 |
int64_t cmp = hist_entry__cmp(he, iter); |
86a9eee04 perf diff: Introd... |
116 |
|
9c443dfdd perf diff: Fix su... |
117 |
if (cmp < 0) |
86a9eee04 perf diff: Introd... |
118 |
n = n->rb_left; |
9c443dfdd perf diff: Fix su... |
119 |
else if (cmp > 0) |
86a9eee04 perf diff: Introd... |
120 |
n = n->rb_right; |
9c443dfdd perf diff: Fix su... |
121 122 |
else return iter; |
86a9eee04 perf diff: Introd... |
123 124 125 126 |
} return NULL; } |
1c02c4d2e perf hist: Introd... |
127 |
static void hists__match(struct hists *older, struct hists *newer) |
86a9eee04 perf diff: Introd... |
128 129 |
{ struct rb_node *nd; |
1c02c4d2e perf hist: Introd... |
130 |
for (nd = rb_first(&newer->entries); nd; nd = rb_next(nd)) { |
86a9eee04 perf diff: Introd... |
131 |
struct hist_entry *pos = rb_entry(nd, struct hist_entry, rb_node); |
1c02c4d2e perf hist: Introd... |
132 |
pos->pair = hists__find_entry(older, pos); |
86a9eee04 perf diff: Introd... |
133 134 |
} } |
86a9eee04 perf diff: Introd... |
135 136 137 138 |
static int __cmd_diff(void) { int ret, i; struct perf_session *session[2]; |
45694aa77 perf tools: Renam... |
139 140 |
session[0] = perf_session__new(input_old, O_RDONLY, force, false, &perf_diff); session[1] = perf_session__new(input_new, O_RDONLY, force, false, &perf_diff); |
86a9eee04 perf diff: Introd... |
141 142 143 144 |
if (session[0] == NULL || session[1] == NULL) return -ENOMEM; for (i = 0; i < 2; ++i) { |
45694aa77 perf tools: Renam... |
145 |
ret = perf_session__process_events(session[i], &perf_diff); |
86a9eee04 perf diff: Introd... |
146 147 |
if (ret) goto out_delete; |
86a9eee04 perf diff: Introd... |
148 |
} |
1c02c4d2e perf hist: Introd... |
149 |
hists__output_resort(&session[1]->hists); |
9c443dfdd perf diff: Fix su... |
150 |
if (show_displacement) |
1c02c4d2e perf hist: Introd... |
151 |
hists__set_positions(&session[0]->hists); |
9c443dfdd perf diff: Fix su... |
152 |
|
1c02c4d2e perf hist: Introd... |
153 154 |
hists__match(&session[0]->hists, &session[1]->hists); hists__fprintf(&session[1]->hists, &session[0]->hists, |
ef9dfe6ec perf hists: Allow... |
155 |
show_displacement, true, 0, 0, stdout); |
86a9eee04 perf diff: Introd... |
156 157 158 159 160 |
out_delete: for (i = 0; i < 2; ++i) perf_session__delete(session[i]); return ret; } |
0422a4fc2 perf diff: Fix us... |
161 |
static const char * const diff_usage[] = { |
86a9eee04 perf diff: Introd... |
162 |
"perf diff [<options>] [old_file] [new_file]", |
0422a4fc2 perf diff: Fix us... |
163 |
NULL, |
86a9eee04 perf diff: Introd... |
164 165 166 |
}; static const struct option options[] = { |
c05556421 perf: Fix endiann... |
167 |
OPT_INCR('v', "verbose", &verbose, |
86a9eee04 perf diff: Introd... |
168 |
"be more verbose (show symbol address, etc)"), |
342955593 perf diff: Fix di... |
169 |
OPT_BOOLEAN('M', "displacement", &show_displacement, |
c351c2816 perf diff: Use pe... |
170 |
"Show position displacement relative to baseline"), |
86a9eee04 perf diff: Introd... |
171 172 173 174 175 |
OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, "load module symbols - WARNING: use only with -k and LIVE kernel"), |
c410a3388 perf symbols: Mov... |
176 177 178 179 180 181 |
OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", "only consider symbols in these dsos"), OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", "only consider symbols in these comms"), OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", "only consider these symbols"), |
c351c2816 perf diff: Use pe... |
182 183 184 185 186 |
OPT_STRING('s', "sort", &sort_order, "key[,key2...]", "sort by key(s): pid, comm, dso, symbol, parent"), OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator", "separator for columns, no spaces will be added between " "columns '.' is reserved."), |
ec5761eab perf symbols: Add... |
187 188 |
OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", "Look for files with symbols relative to this directory"), |
86a9eee04 perf diff: Introd... |
189 190 191 192 193 |
OPT_END() }; int cmd_diff(int argc, const char **argv, const char *prefix __used) { |
604c5c929 perf diff: Change... |
194 |
sort_order = diff__default_sort_order; |
86a9eee04 perf diff: Introd... |
195 196 197 198 199 200 201 202 203 |
argc = parse_options(argc, argv, options, diff_usage, 0); if (argc) { if (argc > 2) usage_with_options(diff_usage, options); if (argc == 2) { input_old = argv[0]; input_new = argv[1]; } else input_new = argv[0]; |
a1645ce12 perf: 'perf kvm' ... |
204 205 206 207 |
} else if (symbol_conf.default_guest_vmlinux_name || symbol_conf.default_guest_kallsyms) { input_old = "perf.data.host"; input_new = "perf.data.guest"; |
86a9eee04 perf diff: Introd... |
208 |
} |
c351c2816 perf diff: Use pe... |
209 |
symbol_conf.exclude_other = false; |
655000e7c perf symbols: Ado... |
210 211 212 213 |
if (symbol__init() < 0) return -1; setup_sorting(diff_usage, options); |
86a9eee04 perf diff: Introd... |
214 |
setup_pager(); |
c351c2816 perf diff: Use pe... |
215 216 217 218 |
sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL); sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", NULL); sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", NULL); |
86a9eee04 perf diff: Introd... |
219 220 |
return __cmd_diff(); } |