4 #include "util/evsel.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"
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"
19 #include <sys/prctl.h>
21 #include <semaphore.h>
25 #include "../../arch/x86/include/asm/svm.h"
26 #include "../../arch/x86/include/asm/vmx.h"
27 #include "../../arch/x86/include/asm/kvm.h"
30 #define INVALID_KEY (~0ULL)
35 struct kvm_event_stats
{
41 struct list_head hash_entry
;
46 struct kvm_event_stats total
;
48 #define DEFAULT_VCPU_NUM 8
50 struct kvm_event_stats
*vcpu
;
53 typedef int (*key_cmp_fun
)(struct kvm_event
*, struct kvm_event
*, int);
55 struct kvm_event_key
{
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
,
74 struct exit_reasons_table
{
75 unsigned long exit_code
;
79 #define EVENTS_BITS 12
80 #define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS)
83 struct perf_tool tool
;
84 struct perf_session
*session
;
86 const char *file_name
;
87 const char *report_event
;
91 struct exit_reasons_table
*exit_reasons
;
92 int exit_reasons_size
;
93 const char *exit_reasons_isa
;
95 struct kvm_events_ops
*events_ops
;
97 struct list_head kvm_events_cache
[EVENTS_CACHE_SIZE
];
101 struct rb_root result
;
105 static void exit_event_get_key(struct perf_evsel
*evsel
,
106 struct perf_sample
*sample
,
107 struct event_key
*key
)
110 key
->key
= perf_evsel__intval(evsel
, sample
, "exit_reason");
113 static bool kvm_exit_event(struct perf_evsel
*evsel
)
115 return !strcmp(evsel
->name
, "kvm:kvm_exit");
118 static bool exit_event_begin(struct perf_evsel
*evsel
,
119 struct perf_sample
*sample
, struct event_key
*key
)
121 if (kvm_exit_event(evsel
)) {
122 exit_event_get_key(evsel
, sample
, key
);
129 static bool kvm_entry_event(struct perf_evsel
*evsel
)
131 return !strcmp(evsel
->name
, "kvm:kvm_entry");
134 static bool exit_event_end(struct perf_evsel
*evsel
,
135 struct perf_sample
*sample __maybe_unused
,
136 struct event_key
*key __maybe_unused
)
138 return kvm_entry_event(evsel
);
141 static struct exit_reasons_table vmx_exit_reasons
[] = {
145 static struct exit_reasons_table svm_exit_reasons
[] = {
149 static const char *get_exit_reason(struct perf_kvm
*kvm
, u64 exit_code
)
151 int i
= kvm
->exit_reasons_size
;
152 struct exit_reasons_table
*tbl
= kvm
->exit_reasons
;
155 if (tbl
->exit_code
== exit_code
)
160 pr_err("unknown kvm exit code:%lld on %s\n",
161 (unsigned long long)exit_code
, kvm
->exit_reasons_isa
);
165 static void exit_event_decode_key(struct perf_kvm
*kvm
,
166 struct event_key
*key
,
169 const char *exit_reason
= get_exit_reason(kvm
, key
->key
);
171 scnprintf(decode
, 20, "%s", exit_reason
);
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
,
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...).
186 static void mmio_event_get_key(struct perf_evsel
*evsel
, struct perf_sample
*sample
,
187 struct event_key
*key
)
189 key
->key
= perf_evsel__intval(evsel
, sample
, "gpa");
190 key
->info
= perf_evsel__intval(evsel
, sample
, "type");
193 #define KVM_TRACE_MMIO_READ_UNSATISFIED 0
194 #define KVM_TRACE_MMIO_READ 1
195 #define KVM_TRACE_MMIO_WRITE 2
197 static bool mmio_event_begin(struct perf_evsel
*evsel
,
198 struct perf_sample
*sample
, struct event_key
*key
)
200 /* MMIO read begin event in kernel. */
201 if (kvm_exit_event(evsel
))
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
);
214 static bool mmio_event_end(struct perf_evsel
*evsel
, struct perf_sample
*sample
,
215 struct event_key
*key
)
217 /* MMIO write end event in kernel. */
218 if (kvm_entry_event(evsel
))
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
);
231 static void mmio_event_decode_key(struct perf_kvm
*kvm __maybe_unused
,
232 struct event_key
*key
,
235 scnprintf(decode
, 20, "%#lx:%s", (unsigned long)key
->key
,
236 key
->info
== KVM_TRACE_MMIO_WRITE
? "W" : "R");
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"
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
)
251 key
->key
= perf_evsel__intval(evsel
, sample
, "port");
252 key
->info
= perf_evsel__intval(evsel
, sample
, "rw");
255 static bool ioport_event_begin(struct perf_evsel
*evsel
,
256 struct perf_sample
*sample
,
257 struct event_key
*key
)
259 if (!strcmp(evsel
->name
, "kvm:kvm_pio")) {
260 ioport_event_get_key(evsel
, sample
, key
);
267 static bool ioport_event_end(struct perf_evsel
*evsel
,
268 struct perf_sample
*sample __maybe_unused
,
269 struct event_key
*key __maybe_unused
)
271 return kvm_entry_event(evsel
);
274 static void ioport_event_decode_key(struct perf_kvm
*kvm __maybe_unused
,
275 struct event_key
*key
,
278 scnprintf(decode
, 20, "%#llx:%s", (unsigned long long)key
->key
,
279 key
->info
? "POUT" : "PIN");
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"
289 static bool register_kvm_events_ops(struct perf_kvm
*kvm
)
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
;
300 pr_err("Unknown report event:%s\n", kvm
->report_event
);
307 struct vcpu_event_record
{
310 struct kvm_event
*last_event
;
314 static void init_kvm_event_record(struct perf_kvm
*kvm
)
318 for (i
= 0; i
< (int)EVENTS_CACHE_SIZE
; i
++)
319 INIT_LIST_HEAD(&kvm
->kvm_events_cache
[i
]);
322 static int kvm_events_hash_fn(u64 key
)
324 return key
& (EVENTS_CACHE_SIZE
- 1);
327 static bool kvm_event_expand(struct kvm_event
*event
, int vcpu_id
)
329 int old_max_vcpu
= event
->max_vcpu
;
331 if (vcpu_id
< event
->max_vcpu
)
334 while (event
->max_vcpu
<= vcpu_id
)
335 event
->max_vcpu
+= DEFAULT_VCPU_NUM
;
337 event
->vcpu
= realloc(event
->vcpu
,
338 event
->max_vcpu
* sizeof(*event
->vcpu
));
340 pr_err("Not enough memory\n");
344 memset(event
->vcpu
+ old_max_vcpu
, 0,
345 (event
->max_vcpu
- old_max_vcpu
) * sizeof(*event
->vcpu
));
349 static struct kvm_event
*kvm_alloc_init_event(struct event_key
*key
)
351 struct kvm_event
*event
;
353 event
= zalloc(sizeof(*event
));
355 pr_err("Not enough memory\n");
363 static struct kvm_event
*find_create_kvm_event(struct perf_kvm
*kvm
,
364 struct event_key
*key
)
366 struct kvm_event
*event
;
367 struct list_head
*head
;
369 BUG_ON(key
->key
== INVALID_KEY
);
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
)
376 event
= kvm_alloc_init_event(key
);
380 list_add(&event
->hash_entry
, head
);
384 static bool handle_begin_event(struct perf_kvm
*kvm
,
385 struct vcpu_event_record
*vcpu_record
,
386 struct event_key
*key
, u64 timestamp
)
388 struct kvm_event
*event
= NULL
;
390 if (key
->key
!= INVALID_KEY
)
391 event
= find_create_kvm_event(kvm
, key
);
393 vcpu_record
->last_event
= event
;
394 vcpu_record
->start_time
= timestamp
;
399 kvm_update_event_stats(struct kvm_event_stats
*kvm_stats
, u64 time_diff
)
401 kvm_stats
->time
+= time_diff
;
402 update_stats(&kvm_stats
->stats
, time_diff
);
405 static double kvm_event_rel_stddev(int vcpu_id
, struct kvm_event
*event
)
407 struct kvm_event_stats
*kvm_stats
= &event
->total
;
410 kvm_stats
= &event
->vcpu
[vcpu_id
];
412 return rel_stddev_stats(stddev_stats(&kvm_stats
->stats
),
413 avg_stats(&kvm_stats
->stats
));
416 static bool update_kvm_event(struct kvm_event
*event
, int vcpu_id
,
419 kvm_update_event_stats(&event
->total
, time_diff
);
421 if (!kvm_event_expand(event
, vcpu_id
))
424 kvm_update_event_stats(&event
->vcpu
[vcpu_id
], time_diff
);
428 static bool handle_end_event(struct perf_kvm
*kvm
,
429 struct vcpu_event_record
*vcpu_record
,
430 struct event_key
*key
,
433 struct kvm_event
*event
;
434 u64 time_begin
, time_diff
;
436 event
= vcpu_record
->last_event
;
437 time_begin
= vcpu_record
->start_time
;
439 /* The begin event is not caught. */
444 * In some case, the 'begin event' only records the start timestamp,
445 * the actual event is recognized in the 'end event' (e.g. mmio-event).
448 /* Both begin and end events did not get the key. */
449 if (!event
&& key
->key
== INVALID_KEY
)
453 event
= find_create_kvm_event(kvm
, key
);
458 vcpu_record
->last_event
= NULL
;
459 vcpu_record
->start_time
= 0;
461 BUG_ON(timestamp
< time_begin
);
463 time_diff
= timestamp
- time_begin
;
464 return update_kvm_event(event
, vcpu_record
->vcpu_id
, time_diff
);
468 struct vcpu_event_record
*per_vcpu_record(struct thread
*thread
,
469 struct perf_evsel
*evsel
,
470 struct perf_sample
*sample
)
472 /* Only kvm_entry records vcpu id. */
473 if (!thread
->priv
&& kvm_entry_event(evsel
)) {
474 struct vcpu_event_record
*vcpu_record
;
476 vcpu_record
= zalloc(sizeof(*vcpu_record
));
478 pr_err("%s: Not enough memory\n", __func__
);
482 vcpu_record
->vcpu_id
= perf_evsel__intval(evsel
, sample
, "vcpu_id");
483 thread
->priv
= vcpu_record
;
489 static bool handle_kvm_event(struct perf_kvm
*kvm
,
490 struct thread
*thread
,
491 struct perf_evsel
*evsel
,
492 struct perf_sample
*sample
)
494 struct vcpu_event_record
*vcpu_record
;
495 struct event_key key
= {.key
= INVALID_KEY
};
497 vcpu_record
= per_vcpu_record(thread
, evsel
, sample
);
501 if (kvm
->events_ops
->is_begin_event(evsel
, sample
, &key
))
502 return handle_begin_event(kvm
, vcpu_record
, &key
, sample
->time
);
504 if (kvm
->events_ops
->is_end_event(evsel
, sample
, &key
))
505 return handle_end_event(kvm
, vcpu_record
, &key
, sample
->time
);
510 #define GET_EVENT_KEY(func, field) \
511 static u64 get_event_ ##func(struct kvm_event *event, int vcpu) \
514 return event->total.field; \
516 if (vcpu >= event->max_vcpu) \
519 return event->vcpu[vcpu].field; \
522 #define COMPARE_EVENT_KEY(func, field) \
523 GET_EVENT_KEY(func, field) \
524 static int compare_kvm_event_ ## func(struct kvm_event *one, \
525 struct kvm_event *two, int vcpu)\
527 return get_event_ ##func(one, vcpu) > \
528 get_event_ ##func(two, vcpu); \
531 GET_EVENT_KEY(time
, time
);
532 COMPARE_EVENT_KEY(count
, stats
.n
);
533 COMPARE_EVENT_KEY(mean
, stats
.mean
);
535 #define DEF_SORT_NAME_KEY(name, compare_key) \
536 { #name, compare_kvm_event_ ## compare_key }
538 static struct kvm_event_key keys
[] = {
539 DEF_SORT_NAME_KEY(sample
, count
),
540 DEF_SORT_NAME_KEY(time
, mean
),
544 static bool select_key(struct perf_kvm
*kvm
)
548 for (i
= 0; keys
[i
].name
; i
++) {
549 if (!strcmp(keys
[i
].name
, kvm
->sort_key
)) {
550 kvm
->compare
= keys
[i
].key
;
555 pr_err("Unknown compare key:%s\n", kvm
->sort_key
);
559 static void insert_to_result(struct rb_root
*result
, struct kvm_event
*event
,
560 key_cmp_fun bigger
, int vcpu
)
562 struct rb_node
**rb
= &result
->rb_node
;
563 struct rb_node
*parent
= NULL
;
567 p
= container_of(*rb
, struct kvm_event
, rb
);
570 if (bigger(event
, p
, vcpu
))
571 rb
= &(*rb
)->rb_left
;
573 rb
= &(*rb
)->rb_right
;
576 rb_link_node(&event
->rb
, parent
, rb
);
577 rb_insert_color(&event
->rb
, result
);
580 static void update_total_count(struct perf_kvm
*kvm
, struct kvm_event
*event
)
582 int vcpu
= kvm
->trace_vcpu
;
584 kvm
->total_count
+= get_event_count(event
, vcpu
);
585 kvm
->total_time
+= get_event_time(event
, vcpu
);
588 static bool event_is_valid(struct kvm_event
*event
, int vcpu
)
590 return !!get_event_count(event
, vcpu
);
593 static void sort_result(struct perf_kvm
*kvm
)
596 int vcpu
= kvm
->trace_vcpu
;
597 struct kvm_event
*event
;
599 for (i
= 0; i
< EVENTS_CACHE_SIZE
; i
++)
600 list_for_each_entry(event
, &kvm
->kvm_events_cache
[i
], hash_entry
)
601 if (event_is_valid(event
, vcpu
)) {
602 update_total_count(kvm
, event
);
603 insert_to_result(&kvm
->result
, event
,
608 /* returns left most element of result, and erase it */
609 static struct kvm_event
*pop_from_result(struct rb_root
*result
)
611 struct rb_node
*node
= rb_first(result
);
616 rb_erase(node
, result
);
617 return container_of(node
, struct kvm_event
, rb
);
620 static void print_vcpu_info(int vcpu
)
622 pr_info("Analyze events for ");
625 pr_info("all VCPUs:\n\n");
627 pr_info("VCPU %d:\n\n", vcpu
);
630 static void print_result(struct perf_kvm
*kvm
)
633 struct kvm_event
*event
;
634 int vcpu
= kvm
->trace_vcpu
;
637 print_vcpu_info(vcpu
);
638 pr_info("%20s ", kvm
->events_ops
->name
);
639 pr_info("%10s ", "Samples");
640 pr_info("%9s ", "Samples%");
642 pr_info("%9s ", "Time%");
643 pr_info("%16s ", "Avg time");
646 while ((event
= pop_from_result(&kvm
->result
))) {
649 ecount
= get_event_count(event
, vcpu
);
650 etime
= get_event_time(event
, vcpu
);
652 kvm
->events_ops
->decode_key(kvm
, &event
->key
, decode
);
653 pr_info("%20s ", decode
);
654 pr_info("%10llu ", (unsigned long long)ecount
);
655 pr_info("%8.2f%% ", (double)ecount
/ kvm
->total_count
* 100);
656 pr_info("%8.2f%% ", (double)etime
/ kvm
->total_time
* 100);
657 pr_info("%9.2fus ( +-%7.2f%% )", (double)etime
/ ecount
/1e3
,
658 kvm_event_rel_stddev(vcpu
, event
));
662 pr_info("\nTotal Samples:%lld, Total events handled time:%.2fus.\n\n",
663 (unsigned long long)kvm
->total_count
, kvm
->total_time
/ 1e3
);
666 static int process_sample_event(struct perf_tool
*tool
,
667 union perf_event
*event
,
668 struct perf_sample
*sample
,
669 struct perf_evsel
*evsel
,
670 struct machine
*machine
)
672 struct thread
*thread
= machine__findnew_thread(machine
, sample
->tid
);
673 struct perf_kvm
*kvm
= container_of(tool
, struct perf_kvm
, tool
);
675 if (thread
== NULL
) {
676 pr_debug("problem processing %d event, skipping it.\n",
681 if (!handle_kvm_event(kvm
, thread
, evsel
, sample
))
687 static int get_cpu_isa(struct perf_session
*session
)
689 char *cpuid
= session
->header
.env
.cpuid
;
692 if (strstr(cpuid
, "Intel"))
694 else if (strstr(cpuid
, "AMD"))
697 pr_err("CPU %s is not supported.\n", cpuid
);
704 static int read_events(struct perf_kvm
*kvm
)
708 struct perf_tool eops
= {
709 .sample
= process_sample_event
,
710 .comm
= perf_event__process_comm
,
711 .ordered_samples
= true,
715 kvm
->session
= perf_session__new(kvm
->file_name
, O_RDONLY
, 0, false,
718 pr_err("Initializing perf session failed\n");
722 if (!perf_session__has_traces(kvm
->session
, "kvm record"))
726 * Do not use 'isa' recorded in kvm_exit tracepoint since it is not
727 * traced in the old kernel.
729 ret
= get_cpu_isa(kvm
->session
);
735 kvm
->exit_reasons
= vmx_exit_reasons
;
736 kvm
->exit_reasons_size
= ARRAY_SIZE(vmx_exit_reasons
);
737 kvm
->exit_reasons_isa
= "VMX";
740 return perf_session__process_events(kvm
->session
, &kvm
->tool
);
743 static bool verify_vcpu(int vcpu
)
745 if (vcpu
!= -1 && vcpu
< 0) {
746 pr_err("Invalid vcpu:%d.\n", vcpu
);
753 static int kvm_events_report_vcpu(struct perf_kvm
*kvm
)
756 int vcpu
= kvm
->trace_vcpu
;
758 if (!verify_vcpu(vcpu
))
761 if (!select_key(kvm
))
764 if (!register_kvm_events_ops(kvm
))
767 init_kvm_event_record(kvm
);
770 ret
= read_events(kvm
);
781 static const char * const record_args
[] = {
787 "-e", "kvm:kvm_entry",
788 "-e", "kvm:kvm_exit",
789 "-e", "kvm:kvm_mmio",
793 #define STRDUP_FAIL_EXIT(s) \
801 static int kvm_events_record(struct perf_kvm
*kvm
, int argc
, const char **argv
)
803 unsigned int rec_argc
, i
, j
;
804 const char **rec_argv
;
806 rec_argc
= ARRAY_SIZE(record_args
) + argc
+ 2;
807 rec_argv
= calloc(rec_argc
+ 1, sizeof(char *));
809 if (rec_argv
== NULL
)
812 for (i
= 0; i
< ARRAY_SIZE(record_args
); i
++)
813 rec_argv
[i
] = STRDUP_FAIL_EXIT(record_args
[i
]);
815 rec_argv
[i
++] = STRDUP_FAIL_EXIT("-o");
816 rec_argv
[i
++] = STRDUP_FAIL_EXIT(kvm
->file_name
);
818 for (j
= 1; j
< (unsigned int)argc
; j
++, i
++)
819 rec_argv
[i
] = argv
[j
];
821 return cmd_record(i
, rec_argv
, NULL
);
824 static int kvm_events_report(struct perf_kvm
*kvm
, int argc
, const char **argv
)
826 const struct option kvm_events_report_options
[] = {
827 OPT_STRING(0, "event", &kvm
->report_event
, "report event",
828 "event for reporting: vmexit, mmio, ioport"),
829 OPT_INTEGER(0, "vcpu", &kvm
->trace_vcpu
,
830 "vcpu id to report"),
831 OPT_STRING('k', "key", &kvm
->sort_key
, "sort-key",
832 "key for sorting: sample(sort by samples number)"
833 " time (sort by avg time)"),
837 const char * const kvm_events_report_usage
[] = {
838 "perf kvm stat report [<options>]",
845 argc
= parse_options(argc
, argv
,
846 kvm_events_report_options
,
847 kvm_events_report_usage
, 0);
849 usage_with_options(kvm_events_report_usage
,
850 kvm_events_report_options
);
853 return kvm_events_report_vcpu(kvm
);
856 static void print_kvm_stat_usage(void)
858 printf("Usage: perf kvm stat <command>\n\n");
860 printf("# Available commands:\n");
861 printf("\trecord: record kvm events\n");
862 printf("\treport: report statistical data of kvm events\n");
864 printf("\nOtherwise, it is the alias of 'perf stat':\n");
867 static int kvm_cmd_stat(struct perf_kvm
*kvm
, int argc
, const char **argv
)
870 print_kvm_stat_usage();
874 if (!strncmp(argv
[1], "rec", 3))
875 return kvm_events_record(kvm
, argc
- 1, argv
+ 1);
877 if (!strncmp(argv
[1], "rep", 3))
878 return kvm_events_report(kvm
, argc
- 1 , argv
+ 1);
881 return cmd_stat(argc
, argv
, NULL
);
884 static int __cmd_record(struct perf_kvm
*kvm
, int argc
, const char **argv
)
886 int rec_argc
, i
= 0, j
;
887 const char **rec_argv
;
890 rec_argv
= calloc(rec_argc
+ 1, sizeof(char *));
891 rec_argv
[i
++] = strdup("record");
892 rec_argv
[i
++] = strdup("-o");
893 rec_argv
[i
++] = strdup(kvm
->file_name
);
894 for (j
= 1; j
< argc
; j
++, i
++)
895 rec_argv
[i
] = argv
[j
];
897 BUG_ON(i
!= rec_argc
);
899 return cmd_record(i
, rec_argv
, NULL
);
902 static int __cmd_report(struct perf_kvm
*kvm
, int argc
, const char **argv
)
904 int rec_argc
, i
= 0, j
;
905 const char **rec_argv
;
908 rec_argv
= calloc(rec_argc
+ 1, sizeof(char *));
909 rec_argv
[i
++] = strdup("report");
910 rec_argv
[i
++] = strdup("-i");
911 rec_argv
[i
++] = strdup(kvm
->file_name
);
912 for (j
= 1; j
< argc
; j
++, i
++)
913 rec_argv
[i
] = argv
[j
];
915 BUG_ON(i
!= rec_argc
);
917 return cmd_report(i
, rec_argv
, NULL
);
920 static int __cmd_buildid_list(struct perf_kvm
*kvm
, int argc
, const char **argv
)
922 int rec_argc
, i
= 0, j
;
923 const char **rec_argv
;
926 rec_argv
= calloc(rec_argc
+ 1, sizeof(char *));
927 rec_argv
[i
++] = strdup("buildid-list");
928 rec_argv
[i
++] = strdup("-i");
929 rec_argv
[i
++] = strdup(kvm
->file_name
);
930 for (j
= 1; j
< argc
; j
++, i
++)
931 rec_argv
[i
] = argv
[j
];
933 BUG_ON(i
!= rec_argc
);
935 return cmd_buildid_list(i
, rec_argv
, NULL
);
938 int cmd_kvm(int argc
, const char **argv
, const char *prefix __maybe_unused
)
940 struct perf_kvm kvm
= {
942 .report_event
= "vmexit",
943 .sort_key
= "sample",
945 .exit_reasons
= svm_exit_reasons
,
946 .exit_reasons_size
= ARRAY_SIZE(svm_exit_reasons
),
947 .exit_reasons_isa
= "SVM",
950 const struct option kvm_options
[] = {
951 OPT_STRING('i', "input", &kvm
.file_name
, "file",
953 OPT_STRING('o', "output", &kvm
.file_name
, "file",
955 OPT_BOOLEAN(0, "guest", &perf_guest
,
956 "Collect guest os data"),
957 OPT_BOOLEAN(0, "host", &perf_host
,
958 "Collect host os data"),
959 OPT_STRING(0, "guestmount", &symbol_conf
.guestmount
, "directory",
960 "guest mount directory under which every guest os"
961 " instance has a subdir"),
962 OPT_STRING(0, "guestvmlinux", &symbol_conf
.default_guest_vmlinux_name
,
963 "file", "file saving guest os vmlinux"),
964 OPT_STRING(0, "guestkallsyms", &symbol_conf
.default_guest_kallsyms
,
965 "file", "file saving guest os /proc/kallsyms"),
966 OPT_STRING(0, "guestmodules", &symbol_conf
.default_guest_modules
,
967 "file", "file saving guest os /proc/modules"),
972 const char * const kvm_usage
[] = {
973 "perf kvm [<options>] {top|record|report|diff|buildid-list|stat}",
980 argc
= parse_options(argc
, argv
, kvm_options
, kvm_usage
,
981 PARSE_OPT_STOP_AT_NON_OPTION
);
983 usage_with_options(kvm_usage
, kvm_options
);
988 if (!kvm
.file_name
) {
989 if (perf_host
&& !perf_guest
)
990 kvm
.file_name
= strdup("perf.data.host");
991 else if (!perf_host
&& perf_guest
)
992 kvm
.file_name
= strdup("perf.data.guest");
994 kvm
.file_name
= strdup("perf.data.kvm");
996 if (!kvm
.file_name
) {
997 pr_err("Failed to allocate memory for filename\n");
1002 if (!strncmp(argv
[0], "rec", 3))
1003 return __cmd_record(&kvm
, argc
, argv
);
1004 else if (!strncmp(argv
[0], "rep", 3))
1005 return __cmd_report(&kvm
, argc
, argv
);
1006 else if (!strncmp(argv
[0], "diff", 4))
1007 return cmd_diff(argc
, argv
, NULL
);
1008 else if (!strncmp(argv
[0], "top", 3))
1009 return cmd_top(argc
, argv
, NULL
);
1010 else if (!strncmp(argv
[0], "buildid-list", 12))
1011 return __cmd_buildid_list(&kvm
, argc
, argv
);
1012 else if (!strncmp(argv
[0], "stat", 4))
1013 return kvm_cmd_stat(&kvm
, argc
, argv
);
1015 usage_with_options(kvm_usage
, kvm_options
);