Blame view

tools/perf/builtin-kvm.c 39.3 KB
a1645ce12   Zhang, Yanmin   perf: 'perf kvm' ...
1
2
  #include "builtin.h"
  #include "perf.h"
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
3
  #include "util/evsel.h"
1afe1d148   David Ahern   perf kvm: Add liv...
4
  #include "util/evlist.h"
a1645ce12   Zhang, Yanmin   perf: 'perf kvm' ...
5
6
7
8
9
10
  #include "util/util.h"
  #include "util/cache.h"
  #include "util/symbol.h"
  #include "util/thread.h"
  #include "util/header.h"
  #include "util/session.h"
2e73f00fe   David Ahern   perf kvm stat rep...
11
  #include "util/intlist.h"
a1645ce12   Zhang, Yanmin   perf: 'perf kvm' ...
12
13
  #include "util/parse-options.h"
  #include "util/trace-event.h"
a1645ce12   Zhang, Yanmin   perf: 'perf kvm' ...
14
  #include "util/debug.h"
553873e1d   Borislav Petkov   tools/: Convert t...
15
  #include <api/fs/debugfs.h>
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
16
17
  #include "util/tool.h"
  #include "util/stat.h"
1afe1d148   David Ahern   perf kvm: Add liv...
18
  #include "util/top.h"
f5fc14124   Jiri Olsa   perf tools: Add d...
19
  #include "util/data.h"
a1645ce12   Zhang, Yanmin   perf: 'perf kvm' ...
20
21
  
  #include <sys/prctl.h>
87419c9af   David Ahern   perf kvm: Disable...
22
  #ifdef HAVE_TIMERFD_SUPPORT
1afe1d148   David Ahern   perf kvm: Add liv...
23
  #include <sys/timerfd.h>
87419c9af   David Ahern   perf kvm: Disable...
24
  #endif
a1645ce12   Zhang, Yanmin   perf: 'perf kvm' ...
25

1afe1d148   David Ahern   perf kvm: Add liv...
26
  #include <termios.h>
a1645ce12   Zhang, Yanmin   perf: 'perf kvm' ...
27
28
29
  #include <semaphore.h>
  #include <pthread.h>
  #include <math.h>
7321090f6   Xiao Guangrong   perf kvm: Fix bui...
30
  #if defined(__i386__) || defined(__x86_64__)
d2709c7ce   David Howells   perf: Make perf b...
31
32
33
  #include <asm/svm.h>
  #include <asm/vmx.h>
  #include <asm/kvm.h>
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
34
35
36
37
38
39
  
  struct event_key {
  	#define INVALID_KEY     (~0ULL)
  	u64 key;
  	int info;
  };
de332ac40   David Ahern   perf kvm: Move gl...
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
  struct kvm_event_stats {
  	u64 time;
  	struct stats stats;
  };
  
  struct kvm_event {
  	struct list_head hash_entry;
  	struct rb_node rb;
  
  	struct event_key key;
  
  	struct kvm_event_stats total;
  
  	#define DEFAULT_VCPU_NUM 8
  	int max_vcpu;
  	struct kvm_event_stats *vcpu;
  };
  
  typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int);
  
  struct kvm_event_key {
  	const char *name;
  	key_cmp_fun key;
  };
3786063a3   Xiao Guangrong   perf kvm: Rename ...
64
  struct perf_kvm_stat;
de332ac40   David Ahern   perf kvm: Move gl...
65

bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
66
  struct kvm_events_ops {
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
67
68
69
70
71
  	bool (*is_begin_event)(struct perf_evsel *evsel,
  			       struct perf_sample *sample,
  			       struct event_key *key);
  	bool (*is_end_event)(struct perf_evsel *evsel,
  			     struct perf_sample *sample, struct event_key *key);
3786063a3   Xiao Guangrong   perf kvm: Rename ...
72
  	void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key,
de332ac40   David Ahern   perf kvm: Move gl...
73
  			   char decode[20]);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
74
75
  	const char *name;
  };
de332ac40   David Ahern   perf kvm: Move gl...
76
77
78
79
80
81
82
  struct exit_reasons_table {
  	unsigned long exit_code;
  	const char *reason;
  };
  
  #define EVENTS_BITS		12
  #define EVENTS_CACHE_SIZE	(1UL << EVENTS_BITS)
3786063a3   Xiao Guangrong   perf kvm: Rename ...
83
  struct perf_kvm_stat {
de332ac40   David Ahern   perf kvm: Move gl...
84
  	struct perf_tool    tool;
b40067964   Arnaldo Carvalho de Melo   perf tools: Renam...
85
  	struct record_opts  opts;
1afe1d148   David Ahern   perf kvm: Add liv...
86
  	struct perf_evlist  *evlist;
de332ac40   David Ahern   perf kvm: Move gl...
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  	struct perf_session *session;
  
  	const char *file_name;
  	const char *report_event;
  	const char *sort_key;
  	int trace_vcpu;
  
  	struct exit_reasons_table *exit_reasons;
  	int exit_reasons_size;
  	const char *exit_reasons_isa;
  
  	struct kvm_events_ops *events_ops;
  	key_cmp_fun compare;
  	struct list_head kvm_events_cache[EVENTS_CACHE_SIZE];
1afe1d148   David Ahern   perf kvm: Add liv...
101

de332ac40   David Ahern   perf kvm: Move gl...
102
103
  	u64 total_time;
  	u64 total_count;
1afe1d148   David Ahern   perf kvm: Add liv...
104
  	u64 lost_events;
70f7b4a7f   David Ahern   perf kvm: Option ...
105
  	u64 duration;
de332ac40   David Ahern   perf kvm: Move gl...
106

2e73f00fe   David Ahern   perf kvm stat rep...
107
108
  	const char *pid_str;
  	struct intlist *pid_list;
de332ac40   David Ahern   perf kvm: Move gl...
109
  	struct rb_root result;
1afe1d148   David Ahern   perf kvm: Add liv...
110
111
112
113
  
  	int timerfd;
  	unsigned int display_time;
  	bool live;
de332ac40   David Ahern   perf kvm: Move gl...
114
  };
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
115
116
117
  static void exit_event_get_key(struct perf_evsel *evsel,
  			       struct perf_sample *sample,
  			       struct event_key *key)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
118
119
  {
  	key->info = 0;
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
120
  	key->key = perf_evsel__intval(evsel, sample, "exit_reason");
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
121
  }
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
122
  static bool kvm_exit_event(struct perf_evsel *evsel)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
123
  {
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
124
  	return !strcmp(evsel->name, "kvm:kvm_exit");
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
125
  }
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
126
127
  static bool exit_event_begin(struct perf_evsel *evsel,
  			     struct perf_sample *sample, struct event_key *key)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
128
  {
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
129
130
  	if (kvm_exit_event(evsel)) {
  		exit_event_get_key(evsel, sample, key);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
131
132
133
134
135
  		return true;
  	}
  
  	return false;
  }
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
136
  static bool kvm_entry_event(struct perf_evsel *evsel)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
137
  {
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
138
  	return !strcmp(evsel->name, "kvm:kvm_entry");
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
139
  }
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
140
141
142
  static bool exit_event_end(struct perf_evsel *evsel,
  			   struct perf_sample *sample __maybe_unused,
  			   struct event_key *key __maybe_unused)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
143
  {
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
144
  	return kvm_entry_event(evsel);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
145
  }
de332ac40   David Ahern   perf kvm: Move gl...
146
  static struct exit_reasons_table vmx_exit_reasons[] = {
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
147
148
  	VMX_EXIT_REASONS
  };
de332ac40   David Ahern   perf kvm: Move gl...
149
  static struct exit_reasons_table svm_exit_reasons[] = {
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
150
151
  	SVM_EXIT_REASONS
  };
3786063a3   Xiao Guangrong   perf kvm: Rename ...
152
  static const char *get_exit_reason(struct perf_kvm_stat *kvm, u64 exit_code)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
153
  {
de332ac40   David Ahern   perf kvm: Move gl...
154
155
  	int i = kvm->exit_reasons_size;
  	struct exit_reasons_table *tbl = kvm->exit_reasons;
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
156

de332ac40   David Ahern   perf kvm: Move gl...
157
158
159
160
  	while (i--) {
  		if (tbl->exit_code == exit_code)
  			return tbl->reason;
  		tbl++;
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
161
162
163
164
  	}
  
  	pr_err("unknown kvm exit code:%lld on %s
  ",
de332ac40   David Ahern   perf kvm: Move gl...
165
  		(unsigned long long)exit_code, kvm->exit_reasons_isa);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
166
167
  	return "UNKNOWN";
  }
3786063a3   Xiao Guangrong   perf kvm: Rename ...
168
  static void exit_event_decode_key(struct perf_kvm_stat *kvm,
de332ac40   David Ahern   perf kvm: Move gl...
169
170
  				  struct event_key *key,
  				  char decode[20])
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
171
  {
de332ac40   David Ahern   perf kvm: Move gl...
172
  	const char *exit_reason = get_exit_reason(kvm, key->key);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
173
174
175
176
177
178
179
180
181
182
  
  	scnprintf(decode, 20, "%s", exit_reason);
  }
  
  static struct kvm_events_ops exit_events = {
  	.is_begin_event = exit_event_begin,
  	.is_end_event = exit_event_end,
  	.decode_key = exit_event_decode_key,
  	.name = "VM-EXIT"
  };
de332ac40   David Ahern   perf kvm: Move gl...
183
184
185
186
187
  /*
   * For the mmio events, we treat:
   * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry
   * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...).
   */
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
188
189
  static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample,
  			       struct event_key *key)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
190
  {
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
191
192
  	key->key  = perf_evsel__intval(evsel, sample, "gpa");
  	key->info = perf_evsel__intval(evsel, sample, "type");
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
193
194
195
196
197
  }
  
  #define KVM_TRACE_MMIO_READ_UNSATISFIED 0
  #define KVM_TRACE_MMIO_READ 1
  #define KVM_TRACE_MMIO_WRITE 2
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
198
199
  static bool mmio_event_begin(struct perf_evsel *evsel,
  			     struct perf_sample *sample, struct event_key *key)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
200
201
  {
  	/* MMIO read begin event in kernel. */
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
202
  	if (kvm_exit_event(evsel))
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
203
204
205
  		return true;
  
  	/* MMIO write begin event in kernel. */
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
206
207
208
  	if (!strcmp(evsel->name, "kvm:kvm_mmio") &&
  	    perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_WRITE) {
  		mmio_event_get_key(evsel, sample, key);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
209
210
211
212
213
  		return true;
  	}
  
  	return false;
  }
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
214
215
  static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample,
  			   struct event_key *key)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
216
217
  {
  	/* MMIO write end event in kernel. */
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
218
  	if (kvm_entry_event(evsel))
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
219
220
221
  		return true;
  
  	/* MMIO read end event in kernel.*/
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
222
223
224
  	if (!strcmp(evsel->name, "kvm:kvm_mmio") &&
  	    perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_READ) {
  		mmio_event_get_key(evsel, sample, key);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
225
226
227
228
229
  		return true;
  	}
  
  	return false;
  }
3786063a3   Xiao Guangrong   perf kvm: Rename ...
230
  static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
de332ac40   David Ahern   perf kvm: Move gl...
231
232
  				  struct event_key *key,
  				  char decode[20])
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
233
234
235
236
237
238
239
240
241
242
243
244
245
  {
  	scnprintf(decode, 20, "%#lx:%s", (unsigned long)key->key,
  				key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R");
  }
  
  static struct kvm_events_ops mmio_events = {
  	.is_begin_event = mmio_event_begin,
  	.is_end_event = mmio_event_end,
  	.decode_key = mmio_event_decode_key,
  	.name = "MMIO Access"
  };
  
   /* The time of emulation pio access is from kvm_pio to kvm_entry. */
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
246
247
248
  static void ioport_event_get_key(struct perf_evsel *evsel,
  				 struct perf_sample *sample,
  				 struct event_key *key)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
249
  {
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
250
251
  	key->key  = perf_evsel__intval(evsel, sample, "port");
  	key->info = perf_evsel__intval(evsel, sample, "rw");
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
252
  }
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
253
254
255
  static bool ioport_event_begin(struct perf_evsel *evsel,
  			       struct perf_sample *sample,
  			       struct event_key *key)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
256
  {
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
257
258
  	if (!strcmp(evsel->name, "kvm:kvm_pio")) {
  		ioport_event_get_key(evsel, sample, key);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
259
260
261
262
263
  		return true;
  	}
  
  	return false;
  }
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
264
265
  static bool ioport_event_end(struct perf_evsel *evsel,
  			     struct perf_sample *sample __maybe_unused,
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
266
267
  			     struct event_key *key __maybe_unused)
  {
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
268
  	return kvm_entry_event(evsel);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
269
  }
3786063a3   Xiao Guangrong   perf kvm: Rename ...
270
  static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
de332ac40   David Ahern   perf kvm: Move gl...
271
272
  				    struct event_key *key,
  				    char decode[20])
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
273
274
275
276
277
278
279
280
281
282
283
  {
  	scnprintf(decode, 20, "%#llx:%s", (unsigned long long)key->key,
  				key->info ? "POUT" : "PIN");
  }
  
  static struct kvm_events_ops ioport_events = {
  	.is_begin_event = ioport_event_begin,
  	.is_end_event = ioport_event_end,
  	.decode_key = ioport_event_decode_key,
  	.name = "IO Port Access"
  };
3786063a3   Xiao Guangrong   perf kvm: Rename ...
284
  static bool register_kvm_events_ops(struct perf_kvm_stat *kvm)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
285
286
  {
  	bool ret = true;
de332ac40   David Ahern   perf kvm: Move gl...
287
288
289
290
291
292
  	if (!strcmp(kvm->report_event, "vmexit"))
  		kvm->events_ops = &exit_events;
  	else if (!strcmp(kvm->report_event, "mmio"))
  		kvm->events_ops = &mmio_events;
  	else if (!strcmp(kvm->report_event, "ioport"))
  		kvm->events_ops = &ioport_events;
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
293
  	else {
de332ac40   David Ahern   perf kvm: Move gl...
294
295
  		pr_err("Unknown report event:%s
  ", kvm->report_event);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
296
297
298
299
300
  		ret = false;
  	}
  
  	return ret;
  }
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
301
302
303
304
305
  struct vcpu_event_record {
  	int vcpu_id;
  	u64 start_time;
  	struct kvm_event *last_event;
  };
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
306

3786063a3   Xiao Guangrong   perf kvm: Rename ...
307
  static void init_kvm_event_record(struct perf_kvm_stat *kvm)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
308
  {
b880deeaf   David Ahern   perf kvm: Remove ...
309
  	unsigned int i;
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
310

b880deeaf   David Ahern   perf kvm: Remove ...
311
  	for (i = 0; i < EVENTS_CACHE_SIZE; i++)
de332ac40   David Ahern   perf kvm: Move gl...
312
  		INIT_LIST_HEAD(&kvm->kvm_events_cache[i]);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
313
  }
87419c9af   David Ahern   perf kvm: Disable...
314
  #ifdef HAVE_TIMERFD_SUPPORT
1afe1d148   David Ahern   perf kvm: Add liv...
315
316
317
318
319
  static void clear_events_cache_stats(struct list_head *kvm_events_cache)
  {
  	struct list_head *head;
  	struct kvm_event *event;
  	unsigned int i;
62d04dbf3   David Ahern   perf kvm: Add min...
320
  	int j;
1afe1d148   David Ahern   perf kvm: Add liv...
321
322
323
324
325
  
  	for (i = 0; i < EVENTS_CACHE_SIZE; i++) {
  		head = &kvm_events_cache[i];
  		list_for_each_entry(event, head, hash_entry) {
  			/* reset stats for event */
62d04dbf3   David Ahern   perf kvm: Add min...
326
327
328
329
330
331
332
  			event->total.time = 0;
  			init_stats(&event->total.stats);
  
  			for (j = 0; j < event->max_vcpu; ++j) {
  				event->vcpu[j].time = 0;
  				init_stats(&event->vcpu[j].stats);
  			}
1afe1d148   David Ahern   perf kvm: Add liv...
333
334
335
  		}
  	}
  }
87419c9af   David Ahern   perf kvm: Disable...
336
  #endif
1afe1d148   David Ahern   perf kvm: Add liv...
337

bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
338
339
340
341
342
343
344
345
  static int kvm_events_hash_fn(u64 key)
  {
  	return key & (EVENTS_CACHE_SIZE - 1);
  }
  
  static bool kvm_event_expand(struct kvm_event *event, int vcpu_id)
  {
  	int old_max_vcpu = event->max_vcpu;
6ca5f3081   David Ahern   perf kvm: Handle ...
346
  	void *prev;
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
347
348
349
350
351
352
  
  	if (vcpu_id < event->max_vcpu)
  		return true;
  
  	while (event->max_vcpu <= vcpu_id)
  		event->max_vcpu += DEFAULT_VCPU_NUM;
6ca5f3081   David Ahern   perf kvm: Handle ...
353
  	prev = event->vcpu;
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
354
355
356
  	event->vcpu = realloc(event->vcpu,
  			      event->max_vcpu * sizeof(*event->vcpu));
  	if (!event->vcpu) {
6ca5f3081   David Ahern   perf kvm: Handle ...
357
  		free(prev);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
  		pr_err("Not enough memory
  ");
  		return false;
  	}
  
  	memset(event->vcpu + old_max_vcpu, 0,
  	       (event->max_vcpu - old_max_vcpu) * sizeof(*event->vcpu));
  	return true;
  }
  
  static struct kvm_event *kvm_alloc_init_event(struct event_key *key)
  {
  	struct kvm_event *event;
  
  	event = zalloc(sizeof(*event));
  	if (!event) {
  		pr_err("Not enough memory
  ");
  		return NULL;
  	}
  
  	event->key = *key;
acb61fc8e   Alexander Yarygin   perf kvm: Fix 'Mi...
380
  	init_stats(&event->total.stats);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
381
382
  	return event;
  }
3786063a3   Xiao Guangrong   perf kvm: Rename ...
383
  static struct kvm_event *find_create_kvm_event(struct perf_kvm_stat *kvm,
de332ac40   David Ahern   perf kvm: Move gl...
384
  					       struct event_key *key)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
385
386
387
388
389
  {
  	struct kvm_event *event;
  	struct list_head *head;
  
  	BUG_ON(key->key == INVALID_KEY);
de332ac40   David Ahern   perf kvm: Move gl...
390
  	head = &kvm->kvm_events_cache[kvm_events_hash_fn(key->key)];
355afe816   David Ahern   perf kvm: Add bra...
391
  	list_for_each_entry(event, head, hash_entry) {
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
392
393
  		if (event->key.key == key->key && event->key.info == key->info)
  			return event;
355afe816   David Ahern   perf kvm: Add bra...
394
  	}
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
395
396
397
398
399
400
401
402
  
  	event = kvm_alloc_init_event(key);
  	if (!event)
  		return NULL;
  
  	list_add(&event->hash_entry, head);
  	return event;
  }
3786063a3   Xiao Guangrong   perf kvm: Rename ...
403
  static bool handle_begin_event(struct perf_kvm_stat *kvm,
de332ac40   David Ahern   perf kvm: Move gl...
404
  			       struct vcpu_event_record *vcpu_record,
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
405
406
407
408
409
  			       struct event_key *key, u64 timestamp)
  {
  	struct kvm_event *event = NULL;
  
  	if (key->key != INVALID_KEY)
de332ac40   David Ahern   perf kvm: Move gl...
410
  		event = find_create_kvm_event(kvm, key);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
  
  	vcpu_record->last_event = event;
  	vcpu_record->start_time = timestamp;
  	return true;
  }
  
  static void
  kvm_update_event_stats(struct kvm_event_stats *kvm_stats, u64 time_diff)
  {
  	kvm_stats->time += time_diff;
  	update_stats(&kvm_stats->stats, time_diff);
  }
  
  static double kvm_event_rel_stddev(int vcpu_id, struct kvm_event *event)
  {
  	struct kvm_event_stats *kvm_stats = &event->total;
  
  	if (vcpu_id != -1)
  		kvm_stats = &event->vcpu[vcpu_id];
  
  	return rel_stddev_stats(stddev_stats(&kvm_stats->stats),
  				avg_stats(&kvm_stats->stats));
  }
  
  static bool update_kvm_event(struct kvm_event *event, int vcpu_id,
  			     u64 time_diff)
  {
2aa8eab02   David Ahern   perf kvm: Only pr...
438
439
440
441
  	if (vcpu_id == -1) {
  		kvm_update_event_stats(&event->total, time_diff);
  		return true;
  	}
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
442
443
444
445
446
447
448
  
  	if (!kvm_event_expand(event, vcpu_id))
  		return false;
  
  	kvm_update_event_stats(&event->vcpu[vcpu_id], time_diff);
  	return true;
  }
3786063a3   Xiao Guangrong   perf kvm: Rename ...
449
  static bool handle_end_event(struct perf_kvm_stat *kvm,
de332ac40   David Ahern   perf kvm: Move gl...
450
451
  			     struct vcpu_event_record *vcpu_record,
  			     struct event_key *key,
70f7b4a7f   David Ahern   perf kvm: Option ...
452
  			     struct perf_sample *sample)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
453
454
455
  {
  	struct kvm_event *event;
  	u64 time_begin, time_diff;
2aa8eab02   David Ahern   perf kvm: Only pr...
456
457
458
459
460
461
  	int vcpu;
  
  	if (kvm->trace_vcpu == -1)
  		vcpu = -1;
  	else
  		vcpu = vcpu_record->vcpu_id;
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
  
  	event = vcpu_record->last_event;
  	time_begin = vcpu_record->start_time;
  
  	/* The begin event is not caught. */
  	if (!time_begin)
  		return true;
  
  	/*
  	 * In some case, the 'begin event' only records the start timestamp,
  	 * the actual event is recognized in the 'end event' (e.g. mmio-event).
  	 */
  
  	/* Both begin and end events did not get the key. */
  	if (!event && key->key == INVALID_KEY)
  		return true;
  
  	if (!event)
de332ac40   David Ahern   perf kvm: Move gl...
480
  		event = find_create_kvm_event(kvm, key);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
481
482
483
484
485
486
  
  	if (!event)
  		return false;
  
  	vcpu_record->last_event = NULL;
  	vcpu_record->start_time = 0;
1afe1d148   David Ahern   perf kvm: Add liv...
487
  	/* seems to happen once in a while during live mode */
70f7b4a7f   David Ahern   perf kvm: Option ...
488
  	if (sample->time < time_begin) {
1afe1d148   David Ahern   perf kvm: Add liv...
489
490
491
492
  		pr_debug("End time before begin time; skipping event.
  ");
  		return true;
  	}
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
493

70f7b4a7f   David Ahern   perf kvm: Option ...
494
495
496
497
498
499
500
501
502
503
504
505
506
  	time_diff = sample->time - time_begin;
  
  	if (kvm->duration && time_diff > kvm->duration) {
  		char decode[32];
  
  		kvm->events_ops->decode_key(kvm, &event->key, decode);
  		if (strcmp(decode, "HLT")) {
  			pr_info("%" PRIu64 " VM %d, vcpu %d: %s event took %" PRIu64 "usec
  ",
  				 sample->time, sample->pid, vcpu_record->vcpu_id,
  				 decode, time_diff/1000);
  		}
  	}
2aa8eab02   David Ahern   perf kvm: Only pr...
507
  	return update_kvm_event(event, vcpu, time_diff);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
508
  }
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
509
510
511
512
  static
  struct vcpu_event_record *per_vcpu_record(struct thread *thread,
  					  struct perf_evsel *evsel,
  					  struct perf_sample *sample)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
513
514
  {
  	/* Only kvm_entry records vcpu id. */
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
515
  	if (!thread->priv && kvm_entry_event(evsel)) {
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
516
  		struct vcpu_event_record *vcpu_record;
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
517
  		vcpu_record = zalloc(sizeof(*vcpu_record));
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
518
  		if (!vcpu_record) {
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
519
520
  			pr_err("%s: Not enough memory
  ", __func__);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
521
522
  			return NULL;
  		}
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
523
  		vcpu_record->vcpu_id = perf_evsel__intval(evsel, sample, "vcpu_id");
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
524
525
  		thread->priv = vcpu_record;
  	}
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
526
  	return thread->priv;
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
527
  }
3786063a3   Xiao Guangrong   perf kvm: Rename ...
528
  static bool handle_kvm_event(struct perf_kvm_stat *kvm,
de332ac40   David Ahern   perf kvm: Move gl...
529
530
  			     struct thread *thread,
  			     struct perf_evsel *evsel,
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
531
  			     struct perf_sample *sample)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
532
533
534
  {
  	struct vcpu_event_record *vcpu_record;
  	struct event_key key = {.key = INVALID_KEY};
14907e738   Arnaldo Carvalho de Melo   perf kvm: Use per...
535
  	vcpu_record = per_vcpu_record(thread, evsel, sample);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
536
537
  	if (!vcpu_record)
  		return true;
2aa8eab02   David Ahern   perf kvm: Only pr...
538
539
540
541
  	/* only process events for vcpus user cares about */
  	if ((kvm->trace_vcpu != -1) &&
  	    (kvm->trace_vcpu != vcpu_record->vcpu_id))
  		return true;
de332ac40   David Ahern   perf kvm: Move gl...
542
543
  	if (kvm->events_ops->is_begin_event(evsel, sample, &key))
  		return handle_begin_event(kvm, vcpu_record, &key, sample->time);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
544

de332ac40   David Ahern   perf kvm: Move gl...
545
  	if (kvm->events_ops->is_end_event(evsel, sample, &key))
70f7b4a7f   David Ahern   perf kvm: Option ...
546
  		return handle_end_event(kvm, vcpu_record, &key, sample);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
547
548
549
  
  	return true;
  }
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
  #define GET_EVENT_KEY(func, field)					\
  static u64 get_event_ ##func(struct kvm_event *event, int vcpu)		\
  {									\
  	if (vcpu == -1)							\
  		return event->total.field;				\
  									\
  	if (vcpu >= event->max_vcpu)					\
  		return 0;						\
  									\
  	return event->vcpu[vcpu].field;					\
  }
  
  #define COMPARE_EVENT_KEY(func, field)					\
  GET_EVENT_KEY(func, field)						\
  static int compare_kvm_event_ ## func(struct kvm_event *one,		\
  					struct kvm_event *two, int vcpu)\
  {									\
  	return get_event_ ##func(one, vcpu) >				\
  				get_event_ ##func(two, vcpu);		\
  }
  
  GET_EVENT_KEY(time, time);
  COMPARE_EVENT_KEY(count, stats.n);
  COMPARE_EVENT_KEY(mean, stats.mean);
62d04dbf3   David Ahern   perf kvm: Add min...
574
575
  GET_EVENT_KEY(max, stats.max);
  GET_EVENT_KEY(min, stats.min);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
576
577
578
579
580
581
582
583
584
  
  #define DEF_SORT_NAME_KEY(name, compare_key)				\
  	{ #name, compare_kvm_event_ ## compare_key }
  
  static struct kvm_event_key keys[] = {
  	DEF_SORT_NAME_KEY(sample, count),
  	DEF_SORT_NAME_KEY(time, mean),
  	{ NULL, NULL }
  };
3786063a3   Xiao Guangrong   perf kvm: Rename ...
585
  static bool select_key(struct perf_kvm_stat *kvm)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
586
587
588
589
  {
  	int i;
  
  	for (i = 0; keys[i].name; i++) {
de332ac40   David Ahern   perf kvm: Move gl...
590
591
  		if (!strcmp(keys[i].name, kvm->sort_key)) {
  			kvm->compare = keys[i].key;
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
592
593
594
  			return true;
  		}
  	}
de332ac40   David Ahern   perf kvm: Move gl...
595
596
  	pr_err("Unknown compare key:%s
  ", kvm->sort_key);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
597
598
  	return false;
  }
de332ac40   David Ahern   perf kvm: Move gl...
599
600
  static void insert_to_result(struct rb_root *result, struct kvm_event *event,
  			     key_cmp_fun bigger, int vcpu)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
601
  {
de332ac40   David Ahern   perf kvm: Move gl...
602
  	struct rb_node **rb = &result->rb_node;
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
603
604
605
606
607
608
609
610
611
612
613
614
615
616
  	struct rb_node *parent = NULL;
  	struct kvm_event *p;
  
  	while (*rb) {
  		p = container_of(*rb, struct kvm_event, rb);
  		parent = *rb;
  
  		if (bigger(event, p, vcpu))
  			rb = &(*rb)->rb_left;
  		else
  			rb = &(*rb)->rb_right;
  	}
  
  	rb_link_node(&event->rb, parent, rb);
de332ac40   David Ahern   perf kvm: Move gl...
617
  	rb_insert_color(&event->rb, result);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
618
  }
3786063a3   Xiao Guangrong   perf kvm: Rename ...
619
620
  static void
  update_total_count(struct perf_kvm_stat *kvm, struct kvm_event *event)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
621
  {
de332ac40   David Ahern   perf kvm: Move gl...
622
623
624
625
  	int vcpu = kvm->trace_vcpu;
  
  	kvm->total_count += get_event_count(event, vcpu);
  	kvm->total_time += get_event_time(event, vcpu);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
626
627
628
629
630
631
  }
  
  static bool event_is_valid(struct kvm_event *event, int vcpu)
  {
  	return !!get_event_count(event, vcpu);
  }
3786063a3   Xiao Guangrong   perf kvm: Rename ...
632
  static void sort_result(struct perf_kvm_stat *kvm)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
633
634
  {
  	unsigned int i;
de332ac40   David Ahern   perf kvm: Move gl...
635
  	int vcpu = kvm->trace_vcpu;
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
636
  	struct kvm_event *event;
355afe816   David Ahern   perf kvm: Add bra...
637
638
  	for (i = 0; i < EVENTS_CACHE_SIZE; i++) {
  		list_for_each_entry(event, &kvm->kvm_events_cache[i], hash_entry) {
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
639
  			if (event_is_valid(event, vcpu)) {
de332ac40   David Ahern   perf kvm: Move gl...
640
641
642
  				update_total_count(kvm, event);
  				insert_to_result(&kvm->result, event,
  						 kvm->compare, vcpu);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
643
  			}
355afe816   David Ahern   perf kvm: Add bra...
644
645
  		}
  	}
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
646
647
648
  }
  
  /* returns left most element of result, and erase it */
de332ac40   David Ahern   perf kvm: Move gl...
649
  static struct kvm_event *pop_from_result(struct rb_root *result)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
650
  {
de332ac40   David Ahern   perf kvm: Move gl...
651
  	struct rb_node *node = rb_first(result);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
652
653
654
  
  	if (!node)
  		return NULL;
de332ac40   David Ahern   perf kvm: Move gl...
655
  	rb_erase(node, result);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
656
657
  	return container_of(node, struct kvm_event, rb);
  }
1afe1d148   David Ahern   perf kvm: Add liv...
658
  static void print_vcpu_info(struct perf_kvm_stat *kvm)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
659
  {
1afe1d148   David Ahern   perf kvm: Add liv...
660
  	int vcpu = kvm->trace_vcpu;
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
661
  	pr_info("Analyze events for ");
1afe1d148   David Ahern   perf kvm: Add liv...
662
663
664
665
666
667
668
669
  	if (kvm->live) {
  		if (kvm->opts.target.system_wide)
  			pr_info("all VMs, ");
  		else if (kvm->opts.target.pid)
  			pr_info("pid(s) %s, ", kvm->opts.target.pid);
  		else
  			pr_info("dazed and confused on what is monitored, ");
  	}
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
670
671
672
673
674
675
676
677
678
  	if (vcpu == -1)
  		pr_info("all VCPUs:
  
  ");
  	else
  		pr_info("VCPU %d:
  
  ", vcpu);
  }
1afe1d148   David Ahern   perf kvm: Add liv...
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
  static void show_timeofday(void)
  {
  	char date[64];
  	struct timeval tv;
  	struct tm ltime;
  
  	gettimeofday(&tv, NULL);
  	if (localtime_r(&tv.tv_sec, &ltime)) {
  		strftime(date, sizeof(date), "%H:%M:%S", &ltime);
  		pr_info("%s.%06ld", date, tv.tv_usec);
  	} else
  		pr_info("00:00:00.000000");
  
  	return;
  }
3786063a3   Xiao Guangrong   perf kvm: Rename ...
694
  static void print_result(struct perf_kvm_stat *kvm)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
695
696
697
  {
  	char decode[20];
  	struct kvm_event *event;
de332ac40   David Ahern   perf kvm: Move gl...
698
  	int vcpu = kvm->trace_vcpu;
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
699

1afe1d148   David Ahern   perf kvm: Add liv...
700
701
702
703
  	if (kvm->live) {
  		puts(CONSOLE_CLEAR);
  		show_timeofday();
  	}
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
704
705
706
  	pr_info("
  
  ");
1afe1d148   David Ahern   perf kvm: Add liv...
707
  	print_vcpu_info(kvm);
de332ac40   David Ahern   perf kvm: Move gl...
708
  	pr_info("%20s ", kvm->events_ops->name);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
709
710
711
712
  	pr_info("%10s ", "Samples");
  	pr_info("%9s ", "Samples%");
  
  	pr_info("%9s ", "Time%");
62d04dbf3   David Ahern   perf kvm: Add min...
713
714
  	pr_info("%10s ", "Min Time");
  	pr_info("%10s ", "Max Time");
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
715
716
717
718
  	pr_info("%16s ", "Avg time");
  	pr_info("
  
  ");
de332ac40   David Ahern   perf kvm: Move gl...
719
  	while ((event = pop_from_result(&kvm->result))) {
62d04dbf3   David Ahern   perf kvm: Add min...
720
  		u64 ecount, etime, max, min;
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
721
722
723
  
  		ecount = get_event_count(event, vcpu);
  		etime = get_event_time(event, vcpu);
62d04dbf3   David Ahern   perf kvm: Add min...
724
725
  		max = get_event_max(event, vcpu);
  		min = get_event_min(event, vcpu);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
726

de332ac40   David Ahern   perf kvm: Move gl...
727
  		kvm->events_ops->decode_key(kvm, &event->key, decode);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
728
729
  		pr_info("%20s ", decode);
  		pr_info("%10llu ", (unsigned long long)ecount);
de332ac40   David Ahern   perf kvm: Move gl...
730
731
  		pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100);
  		pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100);
62d04dbf3   David Ahern   perf kvm: Add min...
732
733
  		pr_info("%8" PRIu64 "us ", min / 1000);
  		pr_info("%8" PRIu64 "us ", max / 1000);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
734
735
736
737
738
  		pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3,
  			kvm_event_rel_stddev(vcpu, event));
  		pr_info("
  ");
  	}
e4f7637f8   David Ahern   perf kvm: Total c...
739
740
741
742
743
  	pr_info("
  Total Samples:%" PRIu64 ", Total events handled time:%.2fus.
  
  ",
  		kvm->total_count, kvm->total_time / 1e3);
1afe1d148   David Ahern   perf kvm: Add liv...
744
745
746
747
748
749
750
  
  	if (kvm->lost_events)
  		pr_info("
  Lost events: %" PRIu64 "
  
  ", kvm->lost_events);
  }
87419c9af   David Ahern   perf kvm: Disable...
751
  #ifdef HAVE_TIMERFD_SUPPORT
1afe1d148   David Ahern   perf kvm: Add liv...
752
753
754
755
756
757
758
759
760
  static int process_lost_event(struct perf_tool *tool,
  			      union perf_event *event __maybe_unused,
  			      struct perf_sample *sample __maybe_unused,
  			      struct machine *machine __maybe_unused)
  {
  	struct perf_kvm_stat *kvm = container_of(tool, struct perf_kvm_stat, tool);
  
  	kvm->lost_events++;
  	return 0;
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
761
  }
87419c9af   David Ahern   perf kvm: Disable...
762
  #endif
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
763

2e73f00fe   David Ahern   perf kvm stat rep...
764
765
766
767
768
769
770
771
  static bool skip_sample(struct perf_kvm_stat *kvm,
  			struct perf_sample *sample)
  {
  	if (kvm->pid_list && intlist__find(kvm->pid_list, sample->pid) == NULL)
  		return true;
  
  	return false;
  }
de332ac40   David Ahern   perf kvm: Move gl...
772
  static int process_sample_event(struct perf_tool *tool,
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
773
774
775
776
777
  				union perf_event *event,
  				struct perf_sample *sample,
  				struct perf_evsel *evsel,
  				struct machine *machine)
  {
2e73f00fe   David Ahern   perf kvm stat rep...
778
  	struct thread *thread;
3786063a3   Xiao Guangrong   perf kvm: Rename ...
779
780
  	struct perf_kvm_stat *kvm = container_of(tool, struct perf_kvm_stat,
  						 tool);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
781

2e73f00fe   David Ahern   perf kvm stat rep...
782
783
  	if (skip_sample(kvm, sample))
  		return 0;
314add6b1   Adrian Hunter   perf tools: chang...
784
  	thread = machine__findnew_thread(machine, sample->pid, sample->tid);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
785
786
787
788
789
790
  	if (thread == NULL) {
  		pr_debug("problem processing %d event, skipping it.
  ",
  			event->header.type);
  		return -1;
  	}
de332ac40   David Ahern   perf kvm: Move gl...
791
  	if (!handle_kvm_event(kvm, thread, evsel, sample))
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
792
793
794
795
  		return -1;
  
  	return 0;
  }
1afe1d148   David Ahern   perf kvm: Add liv...
796
  static int cpu_isa_config(struct perf_kvm_stat *kvm)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
797
  {
1afe1d148   David Ahern   perf kvm: Add liv...
798
799
800
801
802
803
804
805
806
807
808
809
810
  	char buf[64], *cpuid;
  	int err, isa;
  
  	if (kvm->live) {
  		err = get_cpuid(buf, sizeof(buf));
  		if (err != 0) {
  			pr_err("Failed to look up CPU type (Intel or AMD)
  ");
  			return err;
  		}
  		cpuid = buf;
  	} else
  		cpuid = kvm->session->header.env.cpuid;
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
811

bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
812
813
814
815
816
817
818
  	if (strstr(cpuid, "Intel"))
  		isa = 1;
  	else if (strstr(cpuid, "AMD"))
  		isa = 0;
  	else {
  		pr_err("CPU %s is not supported.
  ", cpuid);
1afe1d148   David Ahern   perf kvm: Add liv...
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
  		return -ENOTSUP;
  	}
  
  	if (isa == 1) {
  		kvm->exit_reasons = vmx_exit_reasons;
  		kvm->exit_reasons_size = ARRAY_SIZE(vmx_exit_reasons);
  		kvm->exit_reasons_isa = "VMX";
  	}
  
  	return 0;
  }
  
  static bool verify_vcpu(int vcpu)
  {
  	if (vcpu != -1 && vcpu < 0) {
  		pr_err("Invalid vcpu:%d.
  ", vcpu);
  		return false;
  	}
  
  	return true;
  }
87419c9af   David Ahern   perf kvm: Disable...
841
  #ifdef HAVE_TIMERFD_SUPPORT
1afe1d148   David Ahern   perf kvm: Add liv...
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
  /* keeping the max events to a modest level to keep
   * the processing of samples per mmap smooth.
   */
  #define PERF_KVM__MAX_EVENTS_PER_MMAP  25
  
  static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx,
  				   u64 *mmap_time)
  {
  	union perf_event *event;
  	struct perf_sample sample;
  	s64 n = 0;
  	int err;
  
  	*mmap_time = ULLONG_MAX;
  	while ((event = perf_evlist__mmap_read(kvm->evlist, idx)) != NULL) {
  		err = perf_evlist__parse_sample(kvm->evlist, event, &sample);
  		if (err) {
8e50d384c   Zhouyi Zhou   perf tools: Fixup...
859
  			perf_evlist__mmap_consume(kvm->evlist, idx);
1afe1d148   David Ahern   perf kvm: Add liv...
860
861
862
863
864
865
  			pr_err("Failed to parse sample
  ");
  			return -1;
  		}
  
  		err = perf_session_queue_event(kvm->session, event, &sample, 0);
8e50d384c   Zhouyi Zhou   perf tools: Fixup...
866
867
868
869
870
  		/*
  		 * FIXME: Here we can't consume the event, as perf_session_queue_event will
  		 *        point to it, and it'll get possibly overwritten by the kernel.
  		 */
  		perf_evlist__mmap_consume(kvm->evlist, idx);
1afe1d148   David Ahern   perf kvm: Add liv...
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
  		if (err) {
  			pr_err("Failed to enqueue sample: %d
  ", err);
  			return -1;
  		}
  
  		/* save time stamp of our first sample for this mmap */
  		if (n == 0)
  			*mmap_time = sample.time;
  
  		/* limit events per mmap handled all at once */
  		n++;
  		if (n == PERF_KVM__MAX_EVENTS_PER_MMAP)
  			break;
  	}
  
  	return n;
  }
  
  static int perf_kvm__mmap_read(struct perf_kvm_stat *kvm)
  {
  	int i, err, throttled = 0;
  	s64 n, ntotal = 0;
  	u64 flush_time = ULLONG_MAX, mmap_time;
  
  	for (i = 0; i < kvm->evlist->nr_mmaps; i++) {
  		n = perf_kvm__mmap_read_idx(kvm, i, &mmap_time);
  		if (n < 0)
  			return -1;
  
  		/* flush time is going to be the minimum of all the individual
  		 * mmap times. Essentially, we flush all the samples queued up
  		 * from the last pass under our minimal start time -- that leaves
  		 * a very small race for samples to come in with a lower timestamp.
  		 * The ioctl to return the perf_clock timestamp should close the
  		 * race entirely.
  		 */
  		if (mmap_time < flush_time)
  			flush_time = mmap_time;
  
  		ntotal += n;
  		if (n == PERF_KVM__MAX_EVENTS_PER_MMAP)
  			throttled = 1;
  	}
  
  	/* flush queue after each round in which we processed events */
  	if (ntotal) {
  		kvm->session->ordered_samples.next_flush = flush_time;
  		err = kvm->tool.finished_round(&kvm->tool, NULL, kvm->session);
  		if (err) {
  			if (kvm->lost_events)
  				pr_info("
  Lost events: %" PRIu64 "
  
  ",
  					kvm->lost_events);
  			return err;
  		}
  	}
  
  	return throttled;
  }
  
  static volatile int done;
  
  static void sig_handler(int sig __maybe_unused)
  {
  	done = 1;
  }
  
  static int perf_kvm__timerfd_create(struct perf_kvm_stat *kvm)
  {
  	struct itimerspec new_value;
  	int rc = -1;
  
  	kvm->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
  	if (kvm->timerfd < 0) {
  		pr_err("timerfd_create failed
  ");
  		goto out;
  	}
  
  	new_value.it_value.tv_sec = kvm->display_time;
  	new_value.it_value.tv_nsec = 0;
  	new_value.it_interval.tv_sec = kvm->display_time;
  	new_value.it_interval.tv_nsec = 0;
  
  	if (timerfd_settime(kvm->timerfd, 0, &new_value, NULL) != 0) {
  		pr_err("timerfd_settime failed: %d
  ", errno);
  		close(kvm->timerfd);
  		goto out;
  	}
  
  	rc = 0;
  out:
  	return rc;
  }
  
  static int perf_kvm__handle_timerfd(struct perf_kvm_stat *kvm)
  {
  	uint64_t c;
  	int rc;
  
  	rc = read(kvm->timerfd, &c, sizeof(uint64_t));
  	if (rc < 0) {
  		if (errno == EAGAIN)
  			return 0;
  
  		pr_err("Failed to read timer fd: %d
  ", errno);
  		return -1;
  	}
  
  	if (rc != sizeof(uint64_t)) {
  		pr_err("Error reading timer fd - invalid size returned
  ");
  		return -1;
  	}
  
  	if (c != 1)
  		pr_debug("Missed timer beats: %" PRIu64 "
  ", c-1);
  
  	/* update display */
  	sort_result(kvm);
  	print_result(kvm);
  
  	/* reset counts */
  	clear_events_cache_stats(kvm->kvm_events_cache);
  	kvm->total_count = 0;
  	kvm->total_time = 0;
  	kvm->lost_events = 0;
  
  	return 0;
  }
  
  static int fd_set_nonblock(int fd)
  {
  	long arg = 0;
  
  	arg = fcntl(fd, F_GETFL);
  	if (arg < 0) {
  		pr_err("Failed to get current flags for fd %d
  ", fd);
  		return -1;
  	}
  
  	if (fcntl(fd, F_SETFL, arg | O_NONBLOCK) < 0) {
  		pr_err("Failed to set non-block option on fd %d
  ", fd);
  		return -1;
  	}
  
  	return 0;
  }
  
  static
  int perf_kvm__handle_stdin(struct termios *tc_now, struct termios *tc_save)
  {
  	int c;
  
  	tcsetattr(0, TCSANOW, tc_now);
  	c = getc(stdin);
  	tcsetattr(0, TCSAFLUSH, tc_save);
  
  	if (c == 'q')
  		return 1;
  
  	return 0;
  }
  
  static int kvm_events_live_report(struct perf_kvm_stat *kvm)
  {
  	struct pollfd *pollfds = NULL;
  	int nr_fds, nr_stdin, ret, err = -EINVAL;
  	struct termios tc, save;
  
  	/* live flag must be set first */
  	kvm->live = true;
  
  	ret = cpu_isa_config(kvm);
  	if (ret < 0)
  		return ret;
  
  	if (!verify_vcpu(kvm->trace_vcpu) ||
  	    !select_key(kvm) ||
  	    !register_kvm_events_ops(kvm)) {
  		goto out;
  	}
  
  	init_kvm_event_record(kvm);
  
  	tcgetattr(0, &save);
  	tc = save;
  	tc.c_lflag &= ~(ICANON | ECHO);
  	tc.c_cc[VMIN] = 0;
  	tc.c_cc[VTIME] = 0;
  
  	signal(SIGINT, sig_handler);
  	signal(SIGTERM, sig_handler);
  
  	/* copy pollfds -- need to add timerfd and stdin */
  	nr_fds = kvm->evlist->nr_fds;
  	pollfds = zalloc(sizeof(struct pollfd) * (nr_fds + 2));
  	if (!pollfds) {
  		err = -ENOMEM;
  		goto out;
  	}
  	memcpy(pollfds, kvm->evlist->pollfd,
  		sizeof(struct pollfd) * kvm->evlist->nr_fds);
  
  	/* add timer fd */
  	if (perf_kvm__timerfd_create(kvm) < 0) {
  		err = -1;
  		goto out;
  	}
  
  	pollfds[nr_fds].fd = kvm->timerfd;
  	pollfds[nr_fds].events = POLLIN;
  	nr_fds++;
  
  	pollfds[nr_fds].fd = fileno(stdin);
  	pollfds[nr_fds].events = POLLIN;
  	nr_stdin = nr_fds;
  	nr_fds++;
  	if (fd_set_nonblock(fileno(stdin)) != 0)
  		goto out;
  
  	/* everything is good - enable the events and process */
  	perf_evlist__enable(kvm->evlist);
  
  	while (!done) {
  		int rc;
  
  		rc = perf_kvm__mmap_read(kvm);
  		if (rc < 0)
  			break;
  
  		err = perf_kvm__handle_timerfd(kvm);
  		if (err)
  			goto out;
  
  		if (pollfds[nr_stdin].revents & POLLIN)
  			done = perf_kvm__handle_stdin(&tc, &save);
  
  		if (!rc && !done)
  			err = poll(pollfds, nr_fds, 100);
  	}
  
  	perf_evlist__disable(kvm->evlist);
  
  	if (err == 0) {
  		sort_result(kvm);
  		print_result(kvm);
  	}
  
  out:
  	if (kvm->timerfd >= 0)
  		close(kvm->timerfd);
f5385650c   Arnaldo Carvalho de Melo   perf tools: No ne...
1131
  	free(pollfds);
1afe1d148   David Ahern   perf kvm: Add liv...
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
  	return err;
  }
  
  static int kvm_live_open_events(struct perf_kvm_stat *kvm)
  {
  	int err, rc = -1;
  	struct perf_evsel *pos;
  	struct perf_evlist *evlist = kvm->evlist;
  
  	perf_evlist__config(evlist, &kvm->opts);
  
  	/*
  	 * Note: exclude_{guest,host} do not apply here.
  	 *       This command processes KVM tracepoints from host only
  	 */
0050f7aa1   Arnaldo Carvalho de Melo   perf evlist: Intr...
1147
  	evlist__for_each(evlist, pos) {
1afe1d148   David Ahern   perf kvm: Add liv...
1148
1149
1150
  		struct perf_event_attr *attr = &pos->attr;
  
  		/* make sure these *are* set */
e71aa2831   Adrian Hunter   perf kvm: Fix sam...
1151
1152
1153
1154
  		perf_evsel__set_sample_bit(pos, TID);
  		perf_evsel__set_sample_bit(pos, TIME);
  		perf_evsel__set_sample_bit(pos, CPU);
  		perf_evsel__set_sample_bit(pos, RAW);
1afe1d148   David Ahern   perf kvm: Add liv...
1155
  		/* make sure these are *not*; want as small a sample as possible */
e71aa2831   Adrian Hunter   perf kvm: Fix sam...
1156
1157
1158
1159
1160
  		perf_evsel__reset_sample_bit(pos, PERIOD);
  		perf_evsel__reset_sample_bit(pos, IP);
  		perf_evsel__reset_sample_bit(pos, CALLCHAIN);
  		perf_evsel__reset_sample_bit(pos, ADDR);
  		perf_evsel__reset_sample_bit(pos, READ);
1afe1d148   David Ahern   perf kvm: Add liv...
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
  		attr->mmap = 0;
  		attr->comm = 0;
  		attr->task = 0;
  
  		attr->sample_period = 1;
  
  		attr->watermark = 0;
  		attr->wakeup_events = 1000;
  
  		/* will enable all once we are ready */
  		attr->disabled = 1;
  	}
  
  	err = perf_evlist__open(evlist);
  	if (err < 0) {
  		printf("Couldn't create the events: %s
  ", strerror(errno));
  		goto out;
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1179
  	}
1afe1d148   David Ahern   perf kvm: Add liv...
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
  	if (perf_evlist__mmap(evlist, kvm->opts.mmap_pages, false) < 0) {
  		ui__error("Failed to mmap the events: %s
  ", strerror(errno));
  		perf_evlist__close(evlist);
  		goto out;
  	}
  
  	rc = 0;
  
  out:
  	return rc;
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1191
  }
87419c9af   David Ahern   perf kvm: Disable...
1192
  #endif
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1193

3786063a3   Xiao Guangrong   perf kvm: Rename ...
1194
  static int read_events(struct perf_kvm_stat *kvm)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1195
  {
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1196
  	int ret;
de332ac40   David Ahern   perf kvm: Move gl...
1197
1198
1199
1200
1201
  	struct perf_tool eops = {
  		.sample			= process_sample_event,
  		.comm			= perf_event__process_comm,
  		.ordered_samples	= true,
  	};
f5fc14124   Jiri Olsa   perf tools: Add d...
1202
  	struct perf_data_file file = {
476b3a865   Dongsheng Yang   perf kvm: Fix bug...
1203
  		.path = kvm->file_name,
f5fc14124   Jiri Olsa   perf tools: Add d...
1204
1205
  		.mode = PERF_DATA_MODE_READ,
  	};
de332ac40   David Ahern   perf kvm: Move gl...
1206
1207
  
  	kvm->tool = eops;
f5fc14124   Jiri Olsa   perf tools: Add d...
1208
  	kvm->session = perf_session__new(&file, false, &kvm->tool);
de332ac40   David Ahern   perf kvm: Move gl...
1209
  	if (!kvm->session) {
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1210
1211
1212
1213
  		pr_err("Initializing perf session failed
  ");
  		return -EINVAL;
  	}
de332ac40   David Ahern   perf kvm: Move gl...
1214
  	if (!perf_session__has_traces(kvm->session, "kvm record"))
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1215
1216
1217
1218
1219
1220
  		return -EINVAL;
  
  	/*
  	 * Do not use 'isa' recorded in kvm_exit tracepoint since it is not
  	 * traced in the old kernel.
  	 */
1afe1d148   David Ahern   perf kvm: Add liv...
1221
  	ret = cpu_isa_config(kvm);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1222
1223
  	if (ret < 0)
  		return ret;
de332ac40   David Ahern   perf kvm: Move gl...
1224
  	return perf_session__process_events(kvm->session, &kvm->tool);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1225
  }
2e73f00fe   David Ahern   perf kvm stat rep...
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
  static int parse_target_str(struct perf_kvm_stat *kvm)
  {
  	if (kvm->pid_str) {
  		kvm->pid_list = intlist__new(kvm->pid_str);
  		if (kvm->pid_list == NULL) {
  			pr_err("Error parsing process id string
  ");
  			return -EINVAL;
  		}
  	}
  
  	return 0;
  }
3786063a3   Xiao Guangrong   perf kvm: Rename ...
1239
  static int kvm_events_report_vcpu(struct perf_kvm_stat *kvm)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1240
1241
  {
  	int ret = -EINVAL;
de332ac40   David Ahern   perf kvm: Move gl...
1242
  	int vcpu = kvm->trace_vcpu;
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1243

2e73f00fe   David Ahern   perf kvm stat rep...
1244
1245
  	if (parse_target_str(kvm) != 0)
  		goto exit;
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1246
1247
  	if (!verify_vcpu(vcpu))
  		goto exit;
de332ac40   David Ahern   perf kvm: Move gl...
1248
  	if (!select_key(kvm))
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1249
  		goto exit;
de332ac40   David Ahern   perf kvm: Move gl...
1250
  	if (!register_kvm_events_ops(kvm))
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1251
  		goto exit;
de332ac40   David Ahern   perf kvm: Move gl...
1252
  	init_kvm_event_record(kvm);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1253
  	setup_pager();
de332ac40   David Ahern   perf kvm: Move gl...
1254
  	ret = read_events(kvm);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1255
1256
  	if (ret)
  		goto exit;
de332ac40   David Ahern   perf kvm: Move gl...
1257
1258
  	sort_result(kvm);
  	print_result(kvm);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1259
1260
1261
  exit:
  	return ret;
  }
8fdd84c44   David Ahern   perf kvm: Split o...
1262
1263
1264
1265
1266
  static const char * const kvm_events_tp[] = {
  	"kvm:kvm_entry",
  	"kvm:kvm_exit",
  	"kvm:kvm_mmio",
  	"kvm:kvm_pio",
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1267
1268
1269
1270
1271
1272
1273
1274
1275
  };
  
  #define STRDUP_FAIL_EXIT(s)		\
  	({	char *_p;		\
  	_p = strdup(s);		\
  		if (!_p)		\
  			return -ENOMEM;	\
  		_p;			\
  	})
3786063a3   Xiao Guangrong   perf kvm: Rename ...
1276
1277
  static int
  kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1278
1279
1280
  {
  	unsigned int rec_argc, i, j;
  	const char **rec_argv;
8fdd84c44   David Ahern   perf kvm: Split o...
1281
1282
1283
  	const char * const record_args[] = {
  		"record",
  		"-R",
8fdd84c44   David Ahern   perf kvm: Split o...
1284
1285
1286
  		"-m", "1024",
  		"-c", "1",
  	};
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1287

8fdd84c44   David Ahern   perf kvm: Split o...
1288
1289
  	rec_argc = ARRAY_SIZE(record_args) + argc + 2 +
  		   2 * ARRAY_SIZE(kvm_events_tp);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1290
1291
1292
1293
1294
1295
1296
  	rec_argv = calloc(rec_argc + 1, sizeof(char *));
  
  	if (rec_argv == NULL)
  		return -ENOMEM;
  
  	for (i = 0; i < ARRAY_SIZE(record_args); i++)
  		rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]);
8fdd84c44   David Ahern   perf kvm: Split o...
1297
1298
1299
1300
  	for (j = 0; j < ARRAY_SIZE(kvm_events_tp); j++) {
  		rec_argv[i++] = "-e";
  		rec_argv[i++] = STRDUP_FAIL_EXIT(kvm_events_tp[j]);
  	}
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1301
  	rec_argv[i++] = STRDUP_FAIL_EXIT("-o");
de332ac40   David Ahern   perf kvm: Move gl...
1302
  	rec_argv[i++] = STRDUP_FAIL_EXIT(kvm->file_name);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1303
1304
1305
1306
1307
1308
  
  	for (j = 1; j < (unsigned int)argc; j++, i++)
  		rec_argv[i] = argv[j];
  
  	return cmd_record(i, rec_argv, NULL);
  }
3786063a3   Xiao Guangrong   perf kvm: Rename ...
1309
1310
  static int
  kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
de332ac40   David Ahern   perf kvm: Move gl...
1311
1312
1313
1314
1315
1316
1317
1318
1319
  {
  	const struct option kvm_events_report_options[] = {
  		OPT_STRING(0, "event", &kvm->report_event, "report event",
  			    "event for reporting: vmexit, mmio, ioport"),
  		OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu,
  			    "vcpu id to report"),
  		OPT_STRING('k', "key", &kvm->sort_key, "sort-key",
  			    "key for sorting: sample(sort by samples number)"
  			    " time (sort by avg time)"),
2e73f00fe   David Ahern   perf kvm stat rep...
1320
1321
  		OPT_STRING('p', "pid", &kvm->pid_str, "pid",
  			   "analyze events only for given process id(s)"),
de332ac40   David Ahern   perf kvm: Move gl...
1322
1323
  		OPT_END()
  	};
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1324

de332ac40   David Ahern   perf kvm: Move gl...
1325
1326
1327
1328
  	const char * const kvm_events_report_usage[] = {
  		"perf kvm stat report [<options>]",
  		NULL
  	};
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1329

bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
  	symbol__init();
  
  	if (argc) {
  		argc = parse_options(argc, argv,
  				     kvm_events_report_options,
  				     kvm_events_report_usage, 0);
  		if (argc)
  			usage_with_options(kvm_events_report_usage,
  					   kvm_events_report_options);
  	}
de332ac40   David Ahern   perf kvm: Move gl...
1340
  	return kvm_events_report_vcpu(kvm);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1341
  }
87419c9af   David Ahern   perf kvm: Disable...
1342
  #ifdef HAVE_TIMERFD_SUPPORT
1afe1d148   David Ahern   perf kvm: Add liv...
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
  static struct perf_evlist *kvm_live_event_list(void)
  {
  	struct perf_evlist *evlist;
  	char *tp, *name, *sys;
  	unsigned int j;
  	int err = -1;
  
  	evlist = perf_evlist__new();
  	if (evlist == NULL)
  		return NULL;
  
  	for (j = 0; j < ARRAY_SIZE(kvm_events_tp); j++) {
  
  		tp = strdup(kvm_events_tp[j]);
  		if (tp == NULL)
  			goto out;
  
  		/* split tracepoint into subsystem and name */
  		sys = tp;
  		name = strchr(tp, ':');
  		if (name == NULL) {
  			pr_err("Error parsing %s tracepoint: subsystem delimiter not found
  ",
  				kvm_events_tp[j]);
  			free(tp);
  			goto out;
  		}
  		*name = '\0';
  		name++;
  
  		if (perf_evlist__add_newtp(evlist, sys, name, NULL)) {
  			pr_err("Failed to add %s tracepoint to the list
  ", kvm_events_tp[j]);
  			free(tp);
  			goto out;
  		}
  
  		free(tp);
  	}
  
  	err = 0;
  
  out:
  	if (err) {
  		perf_evlist__delete(evlist);
  		evlist = NULL;
  	}
  
  	return evlist;
  }
  
  static int kvm_events_live(struct perf_kvm_stat *kvm,
  			   int argc, const char **argv)
  {
  	char errbuf[BUFSIZ];
  	int err;
  
  	const struct option live_options[] = {
  		OPT_STRING('p', "pid", &kvm->opts.target.pid, "pid",
  			"record events on existing process id"),
994a1f78b   Jiri Olsa   perf tools: Check...
1403
1404
1405
  		OPT_CALLBACK('m', "mmap-pages", &kvm->opts.mmap_pages, "pages",
  			"number of mmap data pages",
  			perf_evlist__parse_mmap_pages),
1afe1d148   David Ahern   perf kvm: Add liv...
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
  		OPT_INCR('v', "verbose", &verbose,
  			"be more verbose (show counter open errors, etc)"),
  		OPT_BOOLEAN('a', "all-cpus", &kvm->opts.target.system_wide,
  			"system-wide collection from all CPUs"),
  		OPT_UINTEGER('d', "display", &kvm->display_time,
  			"time in seconds between display updates"),
  		OPT_STRING(0, "event", &kvm->report_event, "report event",
  			"event for reporting: vmexit, mmio, ioport"),
  		OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu,
  			"vcpu id to report"),
  		OPT_STRING('k', "key", &kvm->sort_key, "sort-key",
  			"key for sorting: sample(sort by samples number)"
  			" time (sort by avg time)"),
70f7b4a7f   David Ahern   perf kvm: Option ...
1419
1420
  		OPT_U64(0, "duration", &kvm->duration,
  		    "show events other than HALT that take longer than duration usecs"),
1afe1d148   David Ahern   perf kvm: Add liv...
1421
1422
1423
1424
1425
1426
  		OPT_END()
  	};
  	const char * const live_usage[] = {
  		"perf kvm stat live [<options>]",
  		NULL
  	};
f5fc14124   Jiri Olsa   perf tools: Add d...
1427
1428
1429
  	struct perf_data_file file = {
  		.mode = PERF_DATA_MODE_WRITE,
  	};
1afe1d148   David Ahern   perf kvm: Add liv...
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
  
  
  	/* event handling */
  	kvm->tool.sample = process_sample_event;
  	kvm->tool.comm   = perf_event__process_comm;
  	kvm->tool.exit   = perf_event__process_exit;
  	kvm->tool.fork   = perf_event__process_fork;
  	kvm->tool.lost   = process_lost_event;
  	kvm->tool.ordered_samples = true;
  	perf_tool__fill_defaults(&kvm->tool);
  
  	/* set defaults */
  	kvm->display_time = 1;
  	kvm->opts.user_interval = 1;
  	kvm->opts.mmap_pages = 512;
  	kvm->opts.target.uses_mmap = false;
  	kvm->opts.target.uid_str = NULL;
  	kvm->opts.target.uid = UINT_MAX;
  
  	symbol__init();
  	disable_buildid_cache();
  
  	use_browser = 0;
  	setup_browser(false);
  
  	if (argc) {
  		argc = parse_options(argc, argv, live_options,
  				     live_usage, 0);
  		if (argc)
  			usage_with_options(live_usage, live_options);
  	}
70f7b4a7f   David Ahern   perf kvm: Option ...
1461
  	kvm->duration *= NSEC_PER_USEC;   /* convert usec to nsec */
1afe1d148   David Ahern   perf kvm: Add liv...
1462
1463
1464
  	/*
  	 * target related setups
  	 */
602ad878d   Arnaldo Carvalho de Melo   perf target: Shor...
1465
  	err = target__validate(&kvm->opts.target);
1afe1d148   David Ahern   perf kvm: Add liv...
1466
  	if (err) {
602ad878d   Arnaldo Carvalho de Melo   perf target: Shor...
1467
  		target__strerror(&kvm->opts.target, err, errbuf, BUFSIZ);
1afe1d148   David Ahern   perf kvm: Add liv...
1468
1469
  		ui__warning("%s", errbuf);
  	}
602ad878d   Arnaldo Carvalho de Melo   perf target: Shor...
1470
  	if (target__none(&kvm->opts.target))
1afe1d148   David Ahern   perf kvm: Add liv...
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
  		kvm->opts.target.system_wide = true;
  
  
  	/*
  	 * generate the event list
  	 */
  	kvm->evlist = kvm_live_event_list();
  	if (kvm->evlist == NULL) {
  		err = -1;
  		goto out;
  	}
  
  	symbol_conf.nr_events = kvm->evlist->nr_entries;
  
  	if (perf_evlist__create_maps(kvm->evlist, &kvm->opts.target) < 0)
  		usage_with_options(live_usage, live_options);
  
  	/*
  	 * perf session
  	 */
f5fc14124   Jiri Olsa   perf tools: Add d...
1491
  	kvm->session = perf_session__new(&file, false, &kvm->tool);
1afe1d148   David Ahern   perf kvm: Add liv...
1492
1493
1494
1495
1496
1497
  	if (kvm->session == NULL) {
  		err = -ENOMEM;
  		goto out;
  	}
  	kvm->session->evlist = kvm->evlist;
  	perf_session__set_id_hdr_size(kvm->session);
a33fbd56e   Arnaldo Carvalho de Melo   perf machine: Sim...
1498
1499
  	machine__synthesize_threads(&kvm->session->machines.host, &kvm->opts.target,
  				    kvm->evlist->threads, false);
1afe1d148   David Ahern   perf kvm: Add liv...
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
  	err = kvm_live_open_events(kvm);
  	if (err)
  		goto out;
  
  	err = kvm_events_live_report(kvm);
  
  out:
  	exit_browser(0);
  
  	if (kvm->session)
  		perf_session__delete(kvm->session);
  	kvm->session = NULL;
03ad9747c   Arnaldo Carvalho de Melo   perf evlist: Move...
1512
  	if (kvm->evlist)
1afe1d148   David Ahern   perf kvm: Add liv...
1513
  		perf_evlist__delete(kvm->evlist);
1afe1d148   David Ahern   perf kvm: Add liv...
1514
1515
1516
  
  	return err;
  }
87419c9af   David Ahern   perf kvm: Disable...
1517
  #endif
1afe1d148   David Ahern   perf kvm: Add liv...
1518

bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
  static void print_kvm_stat_usage(void)
  {
  	printf("Usage: perf kvm stat <command>
  
  ");
  
  	printf("# Available commands:
  ");
  	printf("\trecord: record kvm events
  ");
  	printf("\treport: report statistical data of kvm events
  ");
1afe1d148   David Ahern   perf kvm: Add liv...
1531
1532
  	printf("\tlive:   live reporting of statistical data of kvm events
  ");
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1533
1534
1535
1536
1537
  
  	printf("
  Otherwise, it is the alias of 'perf stat':
  ");
  }
3786063a3   Xiao Guangrong   perf kvm: Rename ...
1538
  static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1539
  {
3786063a3   Xiao Guangrong   perf kvm: Rename ...
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
  	struct perf_kvm_stat kvm = {
  		.file_name = file_name,
  
  		.trace_vcpu	= -1,
  		.report_event	= "vmexit",
  		.sort_key	= "sample",
  
  		.exit_reasons = svm_exit_reasons,
  		.exit_reasons_size = ARRAY_SIZE(svm_exit_reasons),
  		.exit_reasons_isa = "SVM",
  	};
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1551
1552
1553
1554
1555
1556
  	if (argc == 1) {
  		print_kvm_stat_usage();
  		goto perf_stat;
  	}
  
  	if (!strncmp(argv[1], "rec", 3))
3786063a3   Xiao Guangrong   perf kvm: Rename ...
1557
  		return kvm_events_record(&kvm, argc - 1, argv + 1);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1558
1559
  
  	if (!strncmp(argv[1], "rep", 3))
3786063a3   Xiao Guangrong   perf kvm: Rename ...
1560
  		return kvm_events_report(&kvm, argc - 1 , argv + 1);
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1561

87419c9af   David Ahern   perf kvm: Disable...
1562
  #ifdef HAVE_TIMERFD_SUPPORT
1afe1d148   David Ahern   perf kvm: Add liv...
1563
1564
  	if (!strncmp(argv[1], "live", 4))
  		return kvm_events_live(&kvm, argc - 1 , argv + 1);
87419c9af   David Ahern   perf kvm: Disable...
1565
  #endif
1afe1d148   David Ahern   perf kvm: Add liv...
1566

bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1567
1568
1569
  perf_stat:
  	return cmd_stat(argc, argv, NULL);
  }
7321090f6   Xiao Guangrong   perf kvm: Fix bui...
1570
  #endif
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1571

3786063a3   Xiao Guangrong   perf kvm: Rename ...
1572
  static int __cmd_record(const char *file_name, int argc, const char **argv)
a1645ce12   Zhang, Yanmin   perf: 'perf kvm' ...
1573
1574
1575
1576
1577
1578
1579
1580
  {
  	int rec_argc, i = 0, j;
  	const char **rec_argv;
  
  	rec_argc = argc + 2;
  	rec_argv = calloc(rec_argc + 1, sizeof(char *));
  	rec_argv[i++] = strdup("record");
  	rec_argv[i++] = strdup("-o");
3786063a3   Xiao Guangrong   perf kvm: Rename ...
1581
  	rec_argv[i++] = strdup(file_name);
a1645ce12   Zhang, Yanmin   perf: 'perf kvm' ...
1582
1583
1584
1585
1586
1587
1588
  	for (j = 1; j < argc; j++, i++)
  		rec_argv[i] = argv[j];
  
  	BUG_ON(i != rec_argc);
  
  	return cmd_record(i, rec_argv, NULL);
  }
3786063a3   Xiao Guangrong   perf kvm: Rename ...
1589
  static int __cmd_report(const char *file_name, int argc, const char **argv)
a1645ce12   Zhang, Yanmin   perf: 'perf kvm' ...
1590
1591
1592
1593
1594
1595
1596
1597
  {
  	int rec_argc, i = 0, j;
  	const char **rec_argv;
  
  	rec_argc = argc + 2;
  	rec_argv = calloc(rec_argc + 1, sizeof(char *));
  	rec_argv[i++] = strdup("report");
  	rec_argv[i++] = strdup("-i");
3786063a3   Xiao Guangrong   perf kvm: Rename ...
1598
  	rec_argv[i++] = strdup(file_name);
a1645ce12   Zhang, Yanmin   perf: 'perf kvm' ...
1599
1600
1601
1602
1603
1604
1605
  	for (j = 1; j < argc; j++, i++)
  		rec_argv[i] = argv[j];
  
  	BUG_ON(i != rec_argc);
  
  	return cmd_report(i, rec_argv, NULL);
  }
3786063a3   Xiao Guangrong   perf kvm: Rename ...
1606
1607
  static int
  __cmd_buildid_list(const char *file_name, int argc, const char **argv)
a1645ce12   Zhang, Yanmin   perf: 'perf kvm' ...
1608
1609
1610
1611
1612
1613
1614
1615
  {
  	int rec_argc, i = 0, j;
  	const char **rec_argv;
  
  	rec_argc = argc + 2;
  	rec_argv = calloc(rec_argc + 1, sizeof(char *));
  	rec_argv[i++] = strdup("buildid-list");
  	rec_argv[i++] = strdup("-i");
3786063a3   Xiao Guangrong   perf kvm: Rename ...
1616
  	rec_argv[i++] = strdup(file_name);
a1645ce12   Zhang, Yanmin   perf: 'perf kvm' ...
1617
1618
1619
1620
1621
1622
1623
  	for (j = 1; j < argc; j++, i++)
  		rec_argv[i] = argv[j];
  
  	BUG_ON(i != rec_argc);
  
  	return cmd_buildid_list(i, rec_argv, NULL);
  }
1d037ca16   Irina Tirdea   perf tools: Use _...
1624
  int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
a1645ce12   Zhang, Yanmin   perf: 'perf kvm' ...
1625
  {
20914ce5b   Arnaldo Carvalho de Melo   perf kvm: Initial...
1626
  	const char *file_name = NULL;
de332ac40   David Ahern   perf kvm: Move gl...
1627
  	const struct option kvm_options[] = {
3786063a3   Xiao Guangrong   perf kvm: Rename ...
1628
  		OPT_STRING('i', "input", &file_name, "file",
de332ac40   David Ahern   perf kvm: Move gl...
1629
  			   "Input file name"),
3786063a3   Xiao Guangrong   perf kvm: Rename ...
1630
  		OPT_STRING('o', "output", &file_name, "file",
de332ac40   David Ahern   perf kvm: Move gl...
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
  			   "Output file name"),
  		OPT_BOOLEAN(0, "guest", &perf_guest,
  			    "Collect guest os data"),
  		OPT_BOOLEAN(0, "host", &perf_host,
  			    "Collect host os data"),
  		OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory",
  			   "guest mount directory under which every guest os"
  			   " instance has a subdir"),
  		OPT_STRING(0, "guestvmlinux", &symbol_conf.default_guest_vmlinux_name,
  			   "file", "file saving guest os vmlinux"),
  		OPT_STRING(0, "guestkallsyms", &symbol_conf.default_guest_kallsyms,
  			   "file", "file saving guest os /proc/kallsyms"),
  		OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules,
  			   "file", "file saving guest os /proc/modules"),
100b90735   Dongsheng Yang   perf kvm: Introdu...
1645
1646
  		OPT_INCR('v', "verbose", &verbose,
  			    "be more verbose (show counter open errors, etc)"),
de332ac40   David Ahern   perf kvm: Move gl...
1647
1648
  		OPT_END()
  	};
09a71b97c   Ramkumar Ramachandra   perf kvm: introdu...
1649
1650
1651
  	const char *const kvm_subcommands[] = { "top", "record", "report", "diff",
  						"buildid-list", "stat", NULL };
  	const char *kvm_usage[] = { NULL, NULL };
de332ac40   David Ahern   perf kvm: Move gl...
1652

1aed26717   Joerg Roedel   perf kvm: Do gues...
1653
1654
  	perf_host  = 0;
  	perf_guest = 1;
a1645ce12   Zhang, Yanmin   perf: 'perf kvm' ...
1655

09a71b97c   Ramkumar Ramachandra   perf kvm: introdu...
1656
1657
  	argc = parse_options_subcommand(argc, argv, kvm_options, kvm_subcommands, kvm_usage,
  					PARSE_OPT_STOP_AT_NON_OPTION);
a1645ce12   Zhang, Yanmin   perf: 'perf kvm' ...
1658
1659
1660
1661
1662
  	if (!argc)
  		usage_with_options(kvm_usage, kvm_options);
  
  	if (!perf_host)
  		perf_guest = 1;
3786063a3   Xiao Guangrong   perf kvm: Rename ...
1663
  	if (!file_name) {
e1a2b174d   Dongsheng Yang   perf kvm: Move co...
1664
  		file_name = get_filename_for_perf_kvm();
de332ac40   David Ahern   perf kvm: Move gl...
1665

3786063a3   Xiao Guangrong   perf kvm: Rename ...
1666
  		if (!file_name) {
de332ac40   David Ahern   perf kvm: Move gl...
1667
1668
1669
1670
  			pr_err("Failed to allocate memory for filename
  ");
  			return -ENOMEM;
  		}
a1645ce12   Zhang, Yanmin   perf: 'perf kvm' ...
1671
1672
1673
  	}
  
  	if (!strncmp(argv[0], "rec", 3))
3786063a3   Xiao Guangrong   perf kvm: Rename ...
1674
  		return __cmd_record(file_name, argc, argv);
a1645ce12   Zhang, Yanmin   perf: 'perf kvm' ...
1675
  	else if (!strncmp(argv[0], "rep", 3))
3786063a3   Xiao Guangrong   perf kvm: Rename ...
1676
  		return __cmd_report(file_name, argc, argv);
a1645ce12   Zhang, Yanmin   perf: 'perf kvm' ...
1677
1678
1679
1680
1681
  	else if (!strncmp(argv[0], "diff", 4))
  		return cmd_diff(argc, argv, NULL);
  	else if (!strncmp(argv[0], "top", 3))
  		return cmd_top(argc, argv, NULL);
  	else if (!strncmp(argv[0], "buildid-list", 12))
3786063a3   Xiao Guangrong   perf kvm: Rename ...
1682
  		return __cmd_buildid_list(file_name, argc, argv);
7321090f6   Xiao Guangrong   perf kvm: Fix bui...
1683
  #if defined(__i386__) || defined(__x86_64__)
bcf6edcd6   Xiao Guangrong   perf kvm: Events ...
1684
  	else if (!strncmp(argv[0], "stat", 4))
3786063a3   Xiao Guangrong   perf kvm: Rename ...
1685
  		return kvm_cmd_stat(file_name, argc, argv);
7321090f6   Xiao Guangrong   perf kvm: Fix bui...
1686
  #endif
a1645ce12   Zhang, Yanmin   perf: 'perf kvm' ...
1687
1688
1689
1690
1691
  	else
  		usage_with_options(kvm_usage, kvm_options);
  
  	return 0;
  }