Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
builtin-kvm.c
Go to the documentation of this file.
1 #include "builtin.h"
2 #include "perf.h"
3 
4 #include "util/evsel.h"
5 #include "util/util.h"
6 #include "util/cache.h"
7 #include "util/symbol.h"
8 #include "util/thread.h"
9 #include "util/header.h"
10 #include "util/session.h"
11 
12 #include "util/parse-options.h"
13 #include "util/trace-event.h"
14 #include "util/debug.h"
15 #include "util/debugfs.h"
16 #include "util/tool.h"
17 #include "util/stat.h"
18 
19 #include <sys/prctl.h>
20 
21 #include <semaphore.h>
22 #include <pthread.h>
23 #include <math.h>
24 
25 #if defined(__i386__) || defined(__x86_64__)
26 #include <asm/svm.h>
27 #include <asm/vmx.h>
28 #include <asm/kvm.h>
29 
30 struct event_key {
31  #define INVALID_KEY (~0ULL)
32  u64 key;
33  int info;
34 };
35 
36 struct kvm_event_stats {
37  u64 time;
38  struct stats stats;
39 };
40 
41 struct kvm_event {
42  struct list_head hash_entry;
43  struct rb_node rb;
44 
45  struct event_key key;
46 
47  struct kvm_event_stats total;
48 
49  #define DEFAULT_VCPU_NUM 8
50  int max_vcpu;
51  struct kvm_event_stats *vcpu;
52 };
53 
54 typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int);
55 
56 struct kvm_event_key {
57  const char *name;
58  key_cmp_fun key;
59 };
60 
61 
62 struct perf_kvm_stat;
63 
64 struct kvm_events_ops {
65  bool (*is_begin_event)(struct perf_evsel *evsel,
66  struct perf_sample *sample,
67  struct event_key *key);
68  bool (*is_end_event)(struct perf_evsel *evsel,
69  struct perf_sample *sample, struct event_key *key);
70  void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key,
71  char decode[20]);
72  const char *name;
73 };
74 
75 struct exit_reasons_table {
76  unsigned long exit_code;
77  const char *reason;
78 };
79 
80 #define EVENTS_BITS 12
81 #define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS)
82 
83 struct perf_kvm_stat {
84  struct perf_tool tool;
85  struct perf_session *session;
86 
87  const char *file_name;
88  const char *report_event;
89  const char *sort_key;
90  int trace_vcpu;
91 
92  struct exit_reasons_table *exit_reasons;
93  int exit_reasons_size;
94  const char *exit_reasons_isa;
95 
96  struct kvm_events_ops *events_ops;
97  key_cmp_fun compare;
98  struct list_head kvm_events_cache[EVENTS_CACHE_SIZE];
99  u64 total_time;
100  u64 total_count;
101 
102  struct rb_root result;
103 };
104 
105 
106 static void exit_event_get_key(struct perf_evsel *evsel,
107  struct perf_sample *sample,
108  struct event_key *key)
109 {
110  key->info = 0;
111  key->key = perf_evsel__intval(evsel, sample, "exit_reason");
112 }
113 
114 static bool kvm_exit_event(struct perf_evsel *evsel)
115 {
116  return !strcmp(evsel->name, "kvm:kvm_exit");
117 }
118 
119 static bool exit_event_begin(struct perf_evsel *evsel,
120  struct perf_sample *sample, struct event_key *key)
121 {
122  if (kvm_exit_event(evsel)) {
123  exit_event_get_key(evsel, sample, key);
124  return true;
125  }
126 
127  return false;
128 }
129 
130 static bool kvm_entry_event(struct perf_evsel *evsel)
131 {
132  return !strcmp(evsel->name, "kvm:kvm_entry");
133 }
134 
135 static bool exit_event_end(struct perf_evsel *evsel,
136  struct perf_sample *sample __maybe_unused,
137  struct event_key *key __maybe_unused)
138 {
139  return kvm_entry_event(evsel);
140 }
141 
142 static struct exit_reasons_table vmx_exit_reasons[] = {
144 };
145 
146 static struct exit_reasons_table svm_exit_reasons[] = {
148 };
149 
150 static const char *get_exit_reason(struct perf_kvm_stat *kvm, u64 exit_code)
151 {
152  int i = kvm->exit_reasons_size;
153  struct exit_reasons_table *tbl = kvm->exit_reasons;
154 
155  while (i--) {
156  if (tbl->exit_code == exit_code)
157  return tbl->reason;
158  tbl++;
159  }
160 
161  pr_err("unknown kvm exit code:%lld on %s\n",
162  (unsigned long long)exit_code, kvm->exit_reasons_isa);
163  return "UNKNOWN";
164 }
165 
166 static void exit_event_decode_key(struct perf_kvm_stat *kvm,
167  struct event_key *key,
168  char decode[20])
169 {
170  const char *exit_reason = get_exit_reason(kvm, key->key);
171 
172  scnprintf(decode, 20, "%s", exit_reason);
173 }
174 
175 static struct kvm_events_ops exit_events = {
176  .is_begin_event = exit_event_begin,
177  .is_end_event = exit_event_end,
178  .decode_key = exit_event_decode_key,
179  .name = "VM-EXIT"
180 };
181 
182 /*
183  * For the mmio events, we treat:
184  * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry
185  * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...).
186  */
187 static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample,
188  struct event_key *key)
189 {
190  key->key = perf_evsel__intval(evsel, sample, "gpa");
191  key->info = perf_evsel__intval(evsel, sample, "type");
192 }
193 
194 #define KVM_TRACE_MMIO_READ_UNSATISFIED 0
195 #define KVM_TRACE_MMIO_READ 1
196 #define KVM_TRACE_MMIO_WRITE 2
197 
198 static bool mmio_event_begin(struct perf_evsel *evsel,
199  struct perf_sample *sample, struct event_key *key)
200 {
201  /* MMIO read begin event in kernel. */
202  if (kvm_exit_event(evsel))
203  return true;
204 
205  /* MMIO write begin event in kernel. */
206  if (!strcmp(evsel->name, "kvm:kvm_mmio") &&
207  perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_WRITE) {
208  mmio_event_get_key(evsel, sample, key);
209  return true;
210  }
211 
212  return false;
213 }
214 
215 static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample,
216  struct event_key *key)
217 {
218  /* MMIO write end event in kernel. */
219  if (kvm_entry_event(evsel))
220  return true;
221 
222  /* MMIO read end event in kernel.*/
223  if (!strcmp(evsel->name, "kvm:kvm_mmio") &&
224  perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_READ) {
225  mmio_event_get_key(evsel, sample, key);
226  return true;
227  }
228 
229  return false;
230 }
231 
232 static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
233  struct event_key *key,
234  char decode[20])
235 {
236  scnprintf(decode, 20, "%#lx:%s", (unsigned long)key->key,
237  key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R");
238 }
239 
240 static struct kvm_events_ops mmio_events = {
241  .is_begin_event = mmio_event_begin,
242  .is_end_event = mmio_event_end,
243  .decode_key = mmio_event_decode_key,
244  .name = "MMIO Access"
245 };
246 
247  /* The time of emulation pio access is from kvm_pio to kvm_entry. */
248 static void ioport_event_get_key(struct perf_evsel *evsel,
249  struct perf_sample *sample,
250  struct event_key *key)
251 {
252  key->key = perf_evsel__intval(evsel, sample, "port");
253  key->info = perf_evsel__intval(evsel, sample, "rw");
254 }
255 
256 static bool ioport_event_begin(struct perf_evsel *evsel,
257  struct perf_sample *sample,
258  struct event_key *key)
259 {
260  if (!strcmp(evsel->name, "kvm:kvm_pio")) {
261  ioport_event_get_key(evsel, sample, key);
262  return true;
263  }
264 
265  return false;
266 }
267 
268 static bool ioport_event_end(struct perf_evsel *evsel,
269  struct perf_sample *sample __maybe_unused,
270  struct event_key *key __maybe_unused)
271 {
272  return kvm_entry_event(evsel);
273 }
274 
275 static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
276  struct event_key *key,
277  char decode[20])
278 {
279  scnprintf(decode, 20, "%#llx:%s", (unsigned long long)key->key,
280  key->info ? "POUT" : "PIN");
281 }
282 
283 static struct kvm_events_ops ioport_events = {
284  .is_begin_event = ioport_event_begin,
285  .is_end_event = ioport_event_end,
286  .decode_key = ioport_event_decode_key,
287  .name = "IO Port Access"
288 };
289 
290 static bool register_kvm_events_ops(struct perf_kvm_stat *kvm)
291 {
292  bool ret = true;
293 
294  if (!strcmp(kvm->report_event, "vmexit"))
295  kvm->events_ops = &exit_events;
296  else if (!strcmp(kvm->report_event, "mmio"))
297  kvm->events_ops = &mmio_events;
298  else if (!strcmp(kvm->report_event, "ioport"))
299  kvm->events_ops = &ioport_events;
300  else {
301  pr_err("Unknown report event:%s\n", kvm->report_event);
302  ret = false;
303  }
304 
305  return ret;
306 }
307 
308 struct vcpu_event_record {
309  int vcpu_id;
310  u64 start_time;
311  struct kvm_event *last_event;
312 };
313 
314 
315 static void init_kvm_event_record(struct perf_kvm_stat *kvm)
316 {
317  int i;
318 
319  for (i = 0; i < (int)EVENTS_CACHE_SIZE; i++)
320  INIT_LIST_HEAD(&kvm->kvm_events_cache[i]);
321 }
322 
323 static int kvm_events_hash_fn(u64 key)
324 {
325  return key & (EVENTS_CACHE_SIZE - 1);
326 }
327 
328 static bool kvm_event_expand(struct kvm_event *event, int vcpu_id)
329 {
330  int old_max_vcpu = event->max_vcpu;
331 
332  if (vcpu_id < event->max_vcpu)
333  return true;
334 
335  while (event->max_vcpu <= vcpu_id)
336  event->max_vcpu += DEFAULT_VCPU_NUM;
337 
338  event->vcpu = realloc(event->vcpu,
339  event->max_vcpu * sizeof(*event->vcpu));
340  if (!event->vcpu) {
341  pr_err("Not enough memory\n");
342  return false;
343  }
344 
345  memset(event->vcpu + old_max_vcpu, 0,
346  (event->max_vcpu - old_max_vcpu) * sizeof(*event->vcpu));
347  return true;
348 }
349 
350 static struct kvm_event *kvm_alloc_init_event(struct event_key *key)
351 {
352  struct kvm_event *event;
353 
354  event = zalloc(sizeof(*event));
355  if (!event) {
356  pr_err("Not enough memory\n");
357  return NULL;
358  }
359 
360  event->key = *key;
361  return event;
362 }
363 
364 static struct kvm_event *find_create_kvm_event(struct perf_kvm_stat *kvm,
365  struct event_key *key)
366 {
367  struct kvm_event *event;
368  struct list_head *head;
369 
370  BUG_ON(key->key == INVALID_KEY);
371 
372  head = &kvm->kvm_events_cache[kvm_events_hash_fn(key->key)];
373  list_for_each_entry(event, head, hash_entry)
374  if (event->key.key == key->key && event->key.info == key->info)
375  return event;
376 
377  event = kvm_alloc_init_event(key);
378  if (!event)
379  return NULL;
380 
381  list_add(&event->hash_entry, head);
382  return event;
383 }
384 
385 static bool handle_begin_event(struct perf_kvm_stat *kvm,
386  struct vcpu_event_record *vcpu_record,
387  struct event_key *key, u64 timestamp)
388 {
389  struct kvm_event *event = NULL;
390 
391  if (key->key != INVALID_KEY)
392  event = find_create_kvm_event(kvm, key);
393 
394  vcpu_record->last_event = event;
395  vcpu_record->start_time = timestamp;
396  return true;
397 }
398 
399 static void
400 kvm_update_event_stats(struct kvm_event_stats *kvm_stats, u64 time_diff)
401 {
402  kvm_stats->time += time_diff;
403  update_stats(&kvm_stats->stats, time_diff);
404 }
405 
406 static double kvm_event_rel_stddev(int vcpu_id, struct kvm_event *event)
407 {
408  struct kvm_event_stats *kvm_stats = &event->total;
409 
410  if (vcpu_id != -1)
411  kvm_stats = &event->vcpu[vcpu_id];
412 
413  return rel_stddev_stats(stddev_stats(&kvm_stats->stats),
414  avg_stats(&kvm_stats->stats));
415 }
416 
417 static bool update_kvm_event(struct kvm_event *event, int vcpu_id,
418  u64 time_diff)
419 {
420  kvm_update_event_stats(&event->total, time_diff);
421 
422  if (!kvm_event_expand(event, vcpu_id))
423  return false;
424 
425  kvm_update_event_stats(&event->vcpu[vcpu_id], time_diff);
426  return true;
427 }
428 
429 static bool handle_end_event(struct perf_kvm_stat *kvm,
430  struct vcpu_event_record *vcpu_record,
431  struct event_key *key,
432  u64 timestamp)
433 {
434  struct kvm_event *event;
435  u64 time_begin, time_diff;
436 
437  event = vcpu_record->last_event;
438  time_begin = vcpu_record->start_time;
439 
440  /* The begin event is not caught. */
441  if (!time_begin)
442  return true;
443 
444  /*
445  * In some case, the 'begin event' only records the start timestamp,
446  * the actual event is recognized in the 'end event' (e.g. mmio-event).
447  */
448 
449  /* Both begin and end events did not get the key. */
450  if (!event && key->key == INVALID_KEY)
451  return true;
452 
453  if (!event)
454  event = find_create_kvm_event(kvm, key);
455 
456  if (!event)
457  return false;
458 
459  vcpu_record->last_event = NULL;
460  vcpu_record->start_time = 0;
461 
462  BUG_ON(timestamp < time_begin);
463 
464  time_diff = timestamp - time_begin;
465  return update_kvm_event(event, vcpu_record->vcpu_id, time_diff);
466 }
467 
468 static
469 struct vcpu_event_record *per_vcpu_record(struct thread *thread,
470  struct perf_evsel *evsel,
471  struct perf_sample *sample)
472 {
473  /* Only kvm_entry records vcpu id. */
474  if (!thread->priv && kvm_entry_event(evsel)) {
475  struct vcpu_event_record *vcpu_record;
476 
477  vcpu_record = zalloc(sizeof(*vcpu_record));
478  if (!vcpu_record) {
479  pr_err("%s: Not enough memory\n", __func__);
480  return NULL;
481  }
482 
483  vcpu_record->vcpu_id = perf_evsel__intval(evsel, sample, "vcpu_id");
484  thread->priv = vcpu_record;
485  }
486 
487  return thread->priv;
488 }
489 
490 static bool handle_kvm_event(struct perf_kvm_stat *kvm,
491  struct thread *thread,
492  struct perf_evsel *evsel,
493  struct perf_sample *sample)
494 {
495  struct vcpu_event_record *vcpu_record;
496  struct event_key key = {.key = INVALID_KEY};
497 
498  vcpu_record = per_vcpu_record(thread, evsel, sample);
499  if (!vcpu_record)
500  return true;
501 
502  if (kvm->events_ops->is_begin_event(evsel, sample, &key))
503  return handle_begin_event(kvm, vcpu_record, &key, sample->time);
504 
505  if (kvm->events_ops->is_end_event(evsel, sample, &key))
506  return handle_end_event(kvm, vcpu_record, &key, sample->time);
507 
508  return true;
509 }
510 
511 #define GET_EVENT_KEY(func, field) \
512 static u64 get_event_ ##func(struct kvm_event *event, int vcpu) \
513 { \
514  if (vcpu == -1) \
515  return event->total.field; \
516  \
517  if (vcpu >= event->max_vcpu) \
518  return 0; \
519  \
520  return event->vcpu[vcpu].field; \
521 }
522 
523 #define COMPARE_EVENT_KEY(func, field) \
524 GET_EVENT_KEY(func, field) \
525 static int compare_kvm_event_ ## func(struct kvm_event *one, \
526  struct kvm_event *two, int vcpu)\
527 { \
528  return get_event_ ##func(one, vcpu) > \
529  get_event_ ##func(two, vcpu); \
530 }
531 
532 GET_EVENT_KEY(time, time);
533 COMPARE_EVENT_KEY(count, stats.n);
534 COMPARE_EVENT_KEY(mean, stats.mean);
535 
536 #define DEF_SORT_NAME_KEY(name, compare_key) \
537  { #name, compare_kvm_event_ ## compare_key }
538 
539 static struct kvm_event_key keys[] = {
540  DEF_SORT_NAME_KEY(sample, count),
541  DEF_SORT_NAME_KEY(time, mean),
542  { NULL, NULL }
543 };
544 
545 static bool select_key(struct perf_kvm_stat *kvm)
546 {
547  int i;
548 
549  for (i = 0; keys[i].name; i++) {
550  if (!strcmp(keys[i].name, kvm->sort_key)) {
551  kvm->compare = keys[i].key;
552  return true;
553  }
554  }
555 
556  pr_err("Unknown compare key:%s\n", kvm->sort_key);
557  return false;
558 }
559 
560 static void insert_to_result(struct rb_root *result, struct kvm_event *event,
561  key_cmp_fun bigger, int vcpu)
562 {
563  struct rb_node **rb = &result->rb_node;
564  struct rb_node *parent = NULL;
565  struct kvm_event *p;
566 
567  while (*rb) {
568  p = container_of(*rb, struct kvm_event, rb);
569  parent = *rb;
570 
571  if (bigger(event, p, vcpu))
572  rb = &(*rb)->rb_left;
573  else
574  rb = &(*rb)->rb_right;
575  }
576 
577  rb_link_node(&event->rb, parent, rb);
578  rb_insert_color(&event->rb, result);
579 }
580 
581 static void
582 update_total_count(struct perf_kvm_stat *kvm, struct kvm_event *event)
583 {
584  int vcpu = kvm->trace_vcpu;
585 
586  kvm->total_count += get_event_count(event, vcpu);
587  kvm->total_time += get_event_time(event, vcpu);
588 }
589 
590 static bool event_is_valid(struct kvm_event *event, int vcpu)
591 {
592  return !!get_event_count(event, vcpu);
593 }
594 
595 static void sort_result(struct perf_kvm_stat *kvm)
596 {
597  unsigned int i;
598  int vcpu = kvm->trace_vcpu;
599  struct kvm_event *event;
600 
601  for (i = 0; i < EVENTS_CACHE_SIZE; i++)
602  list_for_each_entry(event, &kvm->kvm_events_cache[i], hash_entry)
603  if (event_is_valid(event, vcpu)) {
604  update_total_count(kvm, event);
605  insert_to_result(&kvm->result, event,
606  kvm->compare, vcpu);
607  }
608 }
609 
610 /* returns left most element of result, and erase it */
611 static struct kvm_event *pop_from_result(struct rb_root *result)
612 {
613  struct rb_node *node = rb_first(result);
614 
615  if (!node)
616  return NULL;
617 
618  rb_erase(node, result);
619  return container_of(node, struct kvm_event, rb);
620 }
621 
622 static void print_vcpu_info(int vcpu)
623 {
624  pr_info("Analyze events for ");
625 
626  if (vcpu == -1)
627  pr_info("all VCPUs:\n\n");
628  else
629  pr_info("VCPU %d:\n\n", vcpu);
630 }
631 
632 static void print_result(struct perf_kvm_stat *kvm)
633 {
634  char decode[20];
635  struct kvm_event *event;
636  int vcpu = kvm->trace_vcpu;
637 
638  pr_info("\n\n");
639  print_vcpu_info(vcpu);
640  pr_info("%20s ", kvm->events_ops->name);
641  pr_info("%10s ", "Samples");
642  pr_info("%9s ", "Samples%");
643 
644  pr_info("%9s ", "Time%");
645  pr_info("%16s ", "Avg time");
646  pr_info("\n\n");
647 
648  while ((event = pop_from_result(&kvm->result))) {
649  u64 ecount, etime;
650 
651  ecount = get_event_count(event, vcpu);
652  etime = get_event_time(event, vcpu);
653 
654  kvm->events_ops->decode_key(kvm, &event->key, decode);
655  pr_info("%20s ", decode);
656  pr_info("%10llu ", (unsigned long long)ecount);
657  pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100);
658  pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100);
659  pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3,
660  kvm_event_rel_stddev(vcpu, event));
661  pr_info("\n");
662  }
663 
664  pr_info("\nTotal Samples:%lld, Total events handled time:%.2fus.\n\n",
665  (unsigned long long)kvm->total_count, kvm->total_time / 1e3);
666 }
667 
668 static int process_sample_event(struct perf_tool *tool,
669  union perf_event *event,
670  struct perf_sample *sample,
671  struct perf_evsel *evsel,
672  struct machine *machine)
673 {
674  struct thread *thread = machine__findnew_thread(machine, sample->tid);
675  struct perf_kvm_stat *kvm = container_of(tool, struct perf_kvm_stat,
676  tool);
677 
678  if (thread == NULL) {
679  pr_debug("problem processing %d event, skipping it.\n",
680  event->header.type);
681  return -1;
682  }
683 
684  if (!handle_kvm_event(kvm, thread, evsel, sample))
685  return -1;
686 
687  return 0;
688 }
689 
690 static int get_cpu_isa(struct perf_session *session)
691 {
692  char *cpuid = session->header.env.cpuid;
693  int isa;
694 
695  if (strstr(cpuid, "Intel"))
696  isa = 1;
697  else if (strstr(cpuid, "AMD"))
698  isa = 0;
699  else {
700  pr_err("CPU %s is not supported.\n", cpuid);
701  isa = -ENOTSUP;
702  }
703 
704  return isa;
705 }
706 
707 static int read_events(struct perf_kvm_stat *kvm)
708 {
709  int ret;
710 
711  struct perf_tool eops = {
712  .sample = process_sample_event,
713  .comm = perf_event__process_comm,
714  .ordered_samples = true,
715  };
716 
717  kvm->tool = eops;
718  kvm->session = perf_session__new(kvm->file_name, O_RDONLY, 0, false,
719  &kvm->tool);
720  if (!kvm->session) {
721  pr_err("Initializing perf session failed\n");
722  return -EINVAL;
723  }
724 
725  if (!perf_session__has_traces(kvm->session, "kvm record"))
726  return -EINVAL;
727 
728  /*
729  * Do not use 'isa' recorded in kvm_exit tracepoint since it is not
730  * traced in the old kernel.
731  */
732  ret = get_cpu_isa(kvm->session);
733 
734  if (ret < 0)
735  return ret;
736 
737  if (ret == 1) {
738  kvm->exit_reasons = vmx_exit_reasons;
739  kvm->exit_reasons_size = ARRAY_SIZE(vmx_exit_reasons);
740  kvm->exit_reasons_isa = "VMX";
741  }
742 
743  return perf_session__process_events(kvm->session, &kvm->tool);
744 }
745 
746 static bool verify_vcpu(int vcpu)
747 {
748  if (vcpu != -1 && vcpu < 0) {
749  pr_err("Invalid vcpu:%d.\n", vcpu);
750  return false;
751  }
752 
753  return true;
754 }
755 
756 static int kvm_events_report_vcpu(struct perf_kvm_stat *kvm)
757 {
758  int ret = -EINVAL;
759  int vcpu = kvm->trace_vcpu;
760 
761  if (!verify_vcpu(vcpu))
762  goto exit;
763 
764  if (!select_key(kvm))
765  goto exit;
766 
767  if (!register_kvm_events_ops(kvm))
768  goto exit;
769 
770  init_kvm_event_record(kvm);
771  setup_pager();
772 
773  ret = read_events(kvm);
774  if (ret)
775  goto exit;
776 
777  sort_result(kvm);
778  print_result(kvm);
779 
780 exit:
781  return ret;
782 }
783 
784 static const char * const record_args[] = {
785  "record",
786  "-R",
787  "-f",
788  "-m", "1024",
789  "-c", "1",
790  "-e", "kvm:kvm_entry",
791  "-e", "kvm:kvm_exit",
792  "-e", "kvm:kvm_mmio",
793  "-e", "kvm:kvm_pio",
794 };
795 
796 #define STRDUP_FAIL_EXIT(s) \
797  ({ char *_p; \
798  _p = strdup(s); \
799  if (!_p) \
800  return -ENOMEM; \
801  _p; \
802  })
803 
804 static int
805 kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
806 {
807  unsigned int rec_argc, i, j;
808  const char **rec_argv;
809 
810  rec_argc = ARRAY_SIZE(record_args) + argc + 2;
811  rec_argv = calloc(rec_argc + 1, sizeof(char *));
812 
813  if (rec_argv == NULL)
814  return -ENOMEM;
815 
816  for (i = 0; i < ARRAY_SIZE(record_args); i++)
817  rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]);
818 
819  rec_argv[i++] = STRDUP_FAIL_EXIT("-o");
820  rec_argv[i++] = STRDUP_FAIL_EXIT(kvm->file_name);
821 
822  for (j = 1; j < (unsigned int)argc; j++, i++)
823  rec_argv[i] = argv[j];
824 
825  return cmd_record(i, rec_argv, NULL);
826 }
827 
828 static int
829 kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
830 {
831  const struct option kvm_events_report_options[] = {
832  OPT_STRING(0, "event", &kvm->report_event, "report event",
833  "event for reporting: vmexit, mmio, ioport"),
834  OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu,
835  "vcpu id to report"),
836  OPT_STRING('k', "key", &kvm->sort_key, "sort-key",
837  "key for sorting: sample(sort by samples number)"
838  " time (sort by avg time)"),
839  OPT_END()
840  };
841 
842  const char * const kvm_events_report_usage[] = {
843  "perf kvm stat report [<options>]",
844  NULL
845  };
846 
847  symbol__init();
848 
849  if (argc) {
850  argc = parse_options(argc, argv,
851  kvm_events_report_options,
852  kvm_events_report_usage, 0);
853  if (argc)
854  usage_with_options(kvm_events_report_usage,
855  kvm_events_report_options);
856  }
857 
858  return kvm_events_report_vcpu(kvm);
859 }
860 
861 static void print_kvm_stat_usage(void)
862 {
863  printf("Usage: perf kvm stat <command>\n\n");
864 
865  printf("# Available commands:\n");
866  printf("\trecord: record kvm events\n");
867  printf("\treport: report statistical data of kvm events\n");
868 
869  printf("\nOtherwise, it is the alias of 'perf stat':\n");
870 }
871 
872 static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)
873 {
874  struct perf_kvm_stat kvm = {
875  .file_name = file_name,
876 
877  .trace_vcpu = -1,
878  .report_event = "vmexit",
879  .sort_key = "sample",
880 
881  .exit_reasons = svm_exit_reasons,
882  .exit_reasons_size = ARRAY_SIZE(svm_exit_reasons),
883  .exit_reasons_isa = "SVM",
884  };
885 
886  if (argc == 1) {
887  print_kvm_stat_usage();
888  goto perf_stat;
889  }
890 
891  if (!strncmp(argv[1], "rec", 3))
892  return kvm_events_record(&kvm, argc - 1, argv + 1);
893 
894  if (!strncmp(argv[1], "rep", 3))
895  return kvm_events_report(&kvm, argc - 1 , argv + 1);
896 
897 perf_stat:
898  return cmd_stat(argc, argv, NULL);
899 }
900 #endif
901 
902 static int __cmd_record(const char *file_name, int argc, const char **argv)
903 {
904  int rec_argc, i = 0, j;
905  const char **rec_argv;
906 
907  rec_argc = argc + 2;
908  rec_argv = calloc(rec_argc + 1, sizeof(char *));
909  rec_argv[i++] = strdup("record");
910  rec_argv[i++] = strdup("-o");
911  rec_argv[i++] = strdup(file_name);
912  for (j = 1; j < argc; j++, i++)
913  rec_argv[i] = argv[j];
914 
915  BUG_ON(i != rec_argc);
916 
917  return cmd_record(i, rec_argv, NULL);
918 }
919 
920 static int __cmd_report(const char *file_name, int argc, const char **argv)
921 {
922  int rec_argc, i = 0, j;
923  const char **rec_argv;
924 
925  rec_argc = argc + 2;
926  rec_argv = calloc(rec_argc + 1, sizeof(char *));
927  rec_argv[i++] = strdup("report");
928  rec_argv[i++] = strdup("-i");
929  rec_argv[i++] = strdup(file_name);
930  for (j = 1; j < argc; j++, i++)
931  rec_argv[i] = argv[j];
932 
933  BUG_ON(i != rec_argc);
934 
935  return cmd_report(i, rec_argv, NULL);
936 }
937 
938 static int
939 __cmd_buildid_list(const char *file_name, int argc, const char **argv)
940 {
941  int rec_argc, i = 0, j;
942  const char **rec_argv;
943 
944  rec_argc = argc + 2;
945  rec_argv = calloc(rec_argc + 1, sizeof(char *));
946  rec_argv[i++] = strdup("buildid-list");
947  rec_argv[i++] = strdup("-i");
948  rec_argv[i++] = strdup(file_name);
949  for (j = 1; j < argc; j++, i++)
950  rec_argv[i] = argv[j];
951 
952  BUG_ON(i != rec_argc);
953 
954  return cmd_buildid_list(i, rec_argv, NULL);
955 }
956 
957 int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
958 {
959  const char *file_name;
960 
961  const struct option kvm_options[] = {
962  OPT_STRING('i', "input", &file_name, "file",
963  "Input file name"),
964  OPT_STRING('o', "output", &file_name, "file",
965  "Output file name"),
966  OPT_BOOLEAN(0, "guest", &perf_guest,
967  "Collect guest os data"),
968  OPT_BOOLEAN(0, "host", &perf_host,
969  "Collect host os data"),
970  OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory",
971  "guest mount directory under which every guest os"
972  " instance has a subdir"),
974  "file", "file saving guest os vmlinux"),
975  OPT_STRING(0, "guestkallsyms", &symbol_conf.default_guest_kallsyms,
976  "file", "file saving guest os /proc/kallsyms"),
977  OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules,
978  "file", "file saving guest os /proc/modules"),
979  OPT_END()
980  };
981 
982 
983  const char * const kvm_usage[] = {
984  "perf kvm [<options>] {top|record|report|diff|buildid-list|stat}",
985  NULL
986  };
987 
988  perf_host = 0;
989  perf_guest = 1;
990 
991  argc = parse_options(argc, argv, kvm_options, kvm_usage,
993  if (!argc)
994  usage_with_options(kvm_usage, kvm_options);
995 
996  if (!perf_host)
997  perf_guest = 1;
998 
999  if (!file_name) {
1000  if (perf_host && !perf_guest)
1001  file_name = strdup("perf.data.host");
1002  else if (!perf_host && perf_guest)
1003  file_name = strdup("perf.data.guest");
1004  else
1005  file_name = strdup("perf.data.kvm");
1006 
1007  if (!file_name) {
1008  pr_err("Failed to allocate memory for filename\n");
1009  return -ENOMEM;
1010  }
1011  }
1012 
1013  if (!strncmp(argv[0], "rec", 3))
1014  return __cmd_record(file_name, argc, argv);
1015  else if (!strncmp(argv[0], "rep", 3))
1016  return __cmd_report(file_name, argc, argv);
1017  else if (!strncmp(argv[0], "diff", 4))
1018  return cmd_diff(argc, argv, NULL);
1019  else if (!strncmp(argv[0], "top", 3))
1020  return cmd_top(argc, argv, NULL);
1021  else if (!strncmp(argv[0], "buildid-list", 12))
1022  return __cmd_buildid_list(file_name, argc, argv);
1023 #if defined(__i386__) || defined(__x86_64__)
1024  else if (!strncmp(argv[0], "stat", 4))
1025  return kvm_cmd_stat(file_name, argc, argv);
1026 #endif
1027  else
1028  usage_with_options(kvm_usage, kvm_options);
1029 
1030  return 0;
1031 }