Blame view

tools/perf/builtin-diff.c 6.41 KB
86a9eee04   Arnaldo Carvalho de Melo   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   Arnaldo Carvalho de Melo   perf tools: Resol...
12
  #include "util/evsel.h"
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
13
  #include "util/session.h"
45694aa77   Arnaldo Carvalho de Melo   perf tools: Renam...
14
  #include "util/tool.h"
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
15
16
17
18
19
  #include "util/sort.h"
  #include "util/symbol.h"
  #include "util/util.h"
  
  #include <stdlib.h>
c351c2816   Arnaldo Carvalho de Melo   perf diff: Use pe...
20
21
  static char const *input_old = "perf.data.old",
  		  *input_new = "perf.data";
604c5c929   Arnaldo Carvalho de Melo   perf diff: Change...
22
  static char	  diff__default_sort_order[] = "dso,symbol";
c05556421   Ian Munsie   perf: Fix endiann...
23
  static bool  force;
c351c2816   Arnaldo Carvalho de Melo   perf diff: Use pe...
24
  static bool show_displacement;
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
25

1c02c4d2e   Arnaldo Carvalho de Melo   perf hist: Introd...
26
  static int hists__add_entry(struct hists *self,
c82ee828a   Arnaldo Carvalho de Melo   perf report: Repo...
27
  			    struct addr_location *al, u64 period)
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
28
  {
c82ee828a   Arnaldo Carvalho de Melo   perf report: Repo...
29
  	if (__hists__add_entry(self, al, NULL, period) != NULL)
28e2a106d   Arnaldo Carvalho de Melo   perf hist: Simpli...
30
31
  		return 0;
  	return -ENOMEM;
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
32
  }
45694aa77   Arnaldo Carvalho de Melo   perf tools: Renam...
33
  static int diff__process_sample_event(struct perf_tool *tool __used,
d20deb64e   Arnaldo Carvalho de Melo   perf tools: Pass ...
34
  				      union perf_event *event,
8d50e5b41   Arnaldo Carvalho de Melo   perf tools: Renam...
35
  				      struct perf_sample *sample,
9e69c2108   Arnaldo Carvalho de Melo   perf session: Pas...
36
  				      struct perf_evsel *evsel __used,
743eb8686   Arnaldo Carvalho de Melo   perf tools: Resol...
37
  				      struct machine *machine)
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
38
39
  {
  	struct addr_location al;
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
40

743eb8686   Arnaldo Carvalho de Melo   perf tools: Resol...
41
  	if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) {
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
42
43
44
45
46
  		pr_warning("problem processing %d event, skipping it.
  ",
  			   event->header.type);
  		return -1;
  	}
cdbae3140   Arnaldo Carvalho de Melo   perf diff: Don't ...
47
  	if (al.filtered || al.sym == NULL)
c410a3388   Arnaldo Carvalho de Melo   perf symbols: Mov...
48
  		return 0;
743eb8686   Arnaldo Carvalho de Melo   perf tools: Resol...
49
  	if (hists__add_entry(&evsel->hists, &al, sample->period)) {
c82ee828a   Arnaldo Carvalho de Melo   perf report: Repo...
50
51
  		pr_warning("problem incrementing symbol period, skipping event
  ");
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
52
53
  		return -1;
  	}
743eb8686   Arnaldo Carvalho de Melo   perf tools: Resol...
54
  	evsel->hists.stats.total_period += sample->period;
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
55
56
  	return 0;
  }
45694aa77   Arnaldo Carvalho de Melo   perf tools: Renam...
57
  static struct perf_tool perf_diff = {
55aa640f5   Arnaldo Carvalho de Melo   perf session: Rem...
58
  	.sample	= diff__process_sample_event,
8115d60c3   Arnaldo Carvalho de Melo   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   Ian Munsie   perf record,repor...
64
65
  	.ordered_samples = true,
  	.ordering_requires_timestamps = true,
86a9eee04   Arnaldo Carvalho de Melo   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   Arnaldo Carvalho de Melo   perf diff: Introd...
76
77
  		parent = *p;
  		iter = rb_entry(parent, struct hist_entry, rb_node);
9c443dfdd   Arnaldo Carvalho de Melo   perf diff: Fix su...
78
  		if (hist_entry__cmp(he, iter) < 0)
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
79
  			p = &(*p)->rb_left;
9c443dfdd   Arnaldo Carvalho de Melo   perf diff: Fix su...
80
  		else
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
81
  			p = &(*p)->rb_right;
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
82
83
84
85
86
  	}
  
  	rb_link_node(&he->rb_node, parent, p);
  	rb_insert_color(&he->rb_node, root);
  }
1c02c4d2e   Arnaldo Carvalho de Melo   perf hist: Introd...
87
  static void hists__resort_entries(struct hists *self)
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
88
89
90
  {
  	unsigned long position = 1;
  	struct rb_root tmp = RB_ROOT;
1c02c4d2e   Arnaldo Carvalho de Melo   perf hist: Introd...
91
  	struct rb_node *next = rb_first(&self->entries);
86a9eee04   Arnaldo Carvalho de Melo   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   Arnaldo Carvalho de Melo   perf hist: Introd...
97
  		rb_erase(&n->rb_node, &self->entries);
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
98
99
100
  		n->position = position++;
  		perf_session__insert_hist_entry_by_name(&tmp, n);
  	}
1c02c4d2e   Arnaldo Carvalho de Melo   perf hist: Introd...
101
  	self->entries = tmp;
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
102
  }
1c02c4d2e   Arnaldo Carvalho de Melo   perf hist: Introd...
103
  static void hists__set_positions(struct hists *self)
9c443dfdd   Arnaldo Carvalho de Melo   perf diff: Fix su...
104
  {
1c02c4d2e   Arnaldo Carvalho de Melo   perf hist: Introd...
105
106
  	hists__output_resort(self);
  	hists__resort_entries(self);
9c443dfdd   Arnaldo Carvalho de Melo   perf diff: Fix su...
107
  }
1c02c4d2e   Arnaldo Carvalho de Melo   perf hist: Introd...
108
109
  static struct hist_entry *hists__find_entry(struct hists *self,
  					    struct hist_entry *he)
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
110
  {
1c02c4d2e   Arnaldo Carvalho de Melo   perf hist: Introd...
111
  	struct rb_node *n = self->entries.rb_node;
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
112
113
114
  
  	while (n) {
  		struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node);
9c443dfdd   Arnaldo Carvalho de Melo   perf diff: Fix su...
115
  		int64_t cmp = hist_entry__cmp(he, iter);
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
116

9c443dfdd   Arnaldo Carvalho de Melo   perf diff: Fix su...
117
  		if (cmp < 0)
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
118
  			n = n->rb_left;
9c443dfdd   Arnaldo Carvalho de Melo   perf diff: Fix su...
119
  		else if (cmp > 0)
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
120
  			n = n->rb_right;
9c443dfdd   Arnaldo Carvalho de Melo   perf diff: Fix su...
121
122
  		else 
  			return iter;
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
123
124
125
126
  	}
  
  	return NULL;
  }
1c02c4d2e   Arnaldo Carvalho de Melo   perf hist: Introd...
127
  static void hists__match(struct hists *older, struct hists *newer)
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
128
129
  {
  	struct rb_node *nd;
1c02c4d2e   Arnaldo Carvalho de Melo   perf hist: Introd...
130
  	for (nd = rb_first(&newer->entries); nd; nd = rb_next(nd)) {
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
131
  		struct hist_entry *pos = rb_entry(nd, struct hist_entry, rb_node);
1c02c4d2e   Arnaldo Carvalho de Melo   perf hist: Introd...
132
  		pos->pair = hists__find_entry(older, pos);
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
133
134
  	}
  }
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
135
136
137
138
  static int __cmd_diff(void)
  {
  	int ret, i;
  	struct perf_session *session[2];
45694aa77   Arnaldo Carvalho de Melo   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   Arnaldo Carvalho de Melo   perf diff: Introd...
141
142
143
144
  	if (session[0] == NULL || session[1] == NULL)
  		return -ENOMEM;
  
  	for (i = 0; i < 2; ++i) {
45694aa77   Arnaldo Carvalho de Melo   perf tools: Renam...
145
  		ret = perf_session__process_events(session[i], &perf_diff);
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
146
147
  		if (ret)
  			goto out_delete;
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
148
  	}
1c02c4d2e   Arnaldo Carvalho de Melo   perf hist: Introd...
149
  	hists__output_resort(&session[1]->hists);
9c443dfdd   Arnaldo Carvalho de Melo   perf diff: Fix su...
150
  	if (show_displacement)
1c02c4d2e   Arnaldo Carvalho de Melo   perf hist: Introd...
151
  		hists__set_positions(&session[0]->hists);
9c443dfdd   Arnaldo Carvalho de Melo   perf diff: Fix su...
152

1c02c4d2e   Arnaldo Carvalho de Melo   perf hist: Introd...
153
154
  	hists__match(&session[0]->hists, &session[1]->hists);
  	hists__fprintf(&session[1]->hists, &session[0]->hists,
ef9dfe6ec   Arnaldo Carvalho de Melo   perf hists: Allow...
155
  		       show_displacement, true, 0, 0, stdout);
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
156
157
158
159
160
  out_delete:
  	for (i = 0; i < 2; ++i)
  		perf_session__delete(session[i]);
  	return ret;
  }
0422a4fc2   Arnaldo Carvalho de Melo   perf diff: Fix us...
161
  static const char * const diff_usage[] = {
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
162
  	"perf diff [<options>] [old_file] [new_file]",
0422a4fc2   Arnaldo Carvalho de Melo   perf diff: Fix us...
163
  	NULL,
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
164
165
166
  };
  
  static const struct option options[] = {
c05556421   Ian Munsie   perf: Fix endiann...
167
  	OPT_INCR('v', "verbose", &verbose,
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
168
  		    "be more verbose (show symbol address, etc)"),
342955593   Shawn Bohrer   perf diff: Fix di...
169
  	OPT_BOOLEAN('M', "displacement", &show_displacement,
c351c2816   Arnaldo Carvalho de Melo   perf diff: Use pe...
170
  		    "Show position displacement relative to baseline"),
86a9eee04   Arnaldo Carvalho de Melo   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   Arnaldo Carvalho de Melo   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   Arnaldo Carvalho de Melo   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   David Ahern   perf symbols: Add...
187
188
  	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
  		    "Look for files with symbols relative to this directory"),
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
189
190
191
192
193
  	OPT_END()
  };
  
  int cmd_diff(int argc, const char **argv, const char *prefix __used)
  {
604c5c929   Arnaldo Carvalho de Melo   perf diff: Change...
194
  	sort_order = diff__default_sort_order;
86a9eee04   Arnaldo Carvalho de Melo   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   Zhang, Yanmin   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   Arnaldo Carvalho de Melo   perf diff: Introd...
208
  	}
c351c2816   Arnaldo Carvalho de Melo   perf diff: Use pe...
209
  	symbol_conf.exclude_other = false;
655000e7c   Arnaldo Carvalho de Melo   perf symbols: Ado...
210
211
212
213
  	if (symbol__init() < 0)
  		return -1;
  
  	setup_sorting(diff_usage, options);
86a9eee04   Arnaldo Carvalho de Melo   perf diff: Introd...
214
  	setup_pager();
c351c2816   Arnaldo Carvalho de Melo   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   Arnaldo Carvalho de Melo   perf diff: Introd...
219
220
  	return __cmd_diff();
  }