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