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_events_ops
{
36 bool (*is_begin_event
)(struct perf_evsel
*evsel
,
37 struct perf_sample
*sample
,
38 struct event_key
*key
);
39 bool (*is_end_event
)(struct perf_evsel
*evsel
,
40 struct perf_sample
*sample
, struct event_key
*key
);
41 void (*decode_key
)(struct event_key
*key
, char decode
[20]);
45 static void exit_event_get_key(struct perf_evsel
*evsel
,
46 struct perf_sample
*sample
,
47 struct event_key
*key
)
50 key
->key
= perf_evsel__intval(evsel
, sample
, "exit_reason");
53 static bool kvm_exit_event(struct perf_evsel
*evsel
)
55 return !strcmp(evsel
->name
, "kvm:kvm_exit");
58 static bool exit_event_begin(struct perf_evsel
*evsel
,
59 struct perf_sample
*sample
, struct event_key
*key
)
61 if (kvm_exit_event(evsel
)) {
62 exit_event_get_key(evsel
, sample
, key
);
69 static bool kvm_entry_event(struct perf_evsel
*evsel
)
71 return !strcmp(evsel
->name
, "kvm:kvm_entry");
74 static bool exit_event_end(struct perf_evsel
*evsel
,
75 struct perf_sample
*sample __maybe_unused
,
76 struct event_key
*key __maybe_unused
)
78 return kvm_entry_event(evsel
);
81 struct exit_reasons_table
{
82 unsigned long exit_code
;
86 struct exit_reasons_table vmx_exit_reasons
[] = {
90 struct exit_reasons_table svm_exit_reasons
[] = {
96 static const char *get_exit_reason(u64 exit_code
)
98 int table_size
= ARRAY_SIZE(svm_exit_reasons
);
99 struct exit_reasons_table
*table
= svm_exit_reasons
;
102 table
= vmx_exit_reasons
;
103 table_size
= ARRAY_SIZE(vmx_exit_reasons
);
106 while (table_size
--) {
107 if (table
->exit_code
== exit_code
)
108 return table
->reason
;
112 pr_err("unknown kvm exit code:%lld on %s\n",
113 (unsigned long long)exit_code
, cpu_isa
? "VMX" : "SVM");
117 static void exit_event_decode_key(struct event_key
*key
, char decode
[20])
119 const char *exit_reason
= get_exit_reason(key
->key
);
121 scnprintf(decode
, 20, "%s", exit_reason
);
124 static struct kvm_events_ops exit_events
= {
125 .is_begin_event
= exit_event_begin
,
126 .is_end_event
= exit_event_end
,
127 .decode_key
= exit_event_decode_key
,
132 * For the mmio events, we treat:
133 * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry
134 * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...).
136 static void mmio_event_get_key(struct perf_evsel
*evsel
, struct perf_sample
*sample
,
137 struct event_key
*key
)
139 key
->key
= perf_evsel__intval(evsel
, sample
, "gpa");
140 key
->info
= perf_evsel__intval(evsel
, sample
, "type");
143 #define KVM_TRACE_MMIO_READ_UNSATISFIED 0
144 #define KVM_TRACE_MMIO_READ 1
145 #define KVM_TRACE_MMIO_WRITE 2
147 static bool mmio_event_begin(struct perf_evsel
*evsel
,
148 struct perf_sample
*sample
, struct event_key
*key
)
150 /* MMIO read begin event in kernel. */
151 if (kvm_exit_event(evsel
))
154 /* MMIO write begin event in kernel. */
155 if (!strcmp(evsel
->name
, "kvm:kvm_mmio") &&
156 perf_evsel__intval(evsel
, sample
, "type") == KVM_TRACE_MMIO_WRITE
) {
157 mmio_event_get_key(evsel
, sample
, key
);
164 static bool mmio_event_end(struct perf_evsel
*evsel
, struct perf_sample
*sample
,
165 struct event_key
*key
)
167 /* MMIO write end event in kernel. */
168 if (kvm_entry_event(evsel
))
171 /* MMIO read end event in kernel.*/
172 if (!strcmp(evsel
->name
, "kvm:kvm_mmio") &&
173 perf_evsel__intval(evsel
, sample
, "type") == KVM_TRACE_MMIO_READ
) {
174 mmio_event_get_key(evsel
, sample
, key
);
181 static void mmio_event_decode_key(struct event_key
*key
, char decode
[20])
183 scnprintf(decode
, 20, "%#lx:%s", (unsigned long)key
->key
,
184 key
->info
== KVM_TRACE_MMIO_WRITE
? "W" : "R");
187 static struct kvm_events_ops mmio_events
= {
188 .is_begin_event
= mmio_event_begin
,
189 .is_end_event
= mmio_event_end
,
190 .decode_key
= mmio_event_decode_key
,
191 .name
= "MMIO Access"
194 /* The time of emulation pio access is from kvm_pio to kvm_entry. */
195 static void ioport_event_get_key(struct perf_evsel
*evsel
,
196 struct perf_sample
*sample
,
197 struct event_key
*key
)
199 key
->key
= perf_evsel__intval(evsel
, sample
, "port");
200 key
->info
= perf_evsel__intval(evsel
, sample
, "rw");
203 static bool ioport_event_begin(struct perf_evsel
*evsel
,
204 struct perf_sample
*sample
,
205 struct event_key
*key
)
207 if (!strcmp(evsel
->name
, "kvm:kvm_pio")) {
208 ioport_event_get_key(evsel
, sample
, key
);
215 static bool ioport_event_end(struct perf_evsel
*evsel
,
216 struct perf_sample
*sample __maybe_unused
,
217 struct event_key
*key __maybe_unused
)
219 return kvm_entry_event(evsel
);
222 static void ioport_event_decode_key(struct event_key
*key
, char decode
[20])
224 scnprintf(decode
, 20, "%#llx:%s", (unsigned long long)key
->key
,
225 key
->info
? "POUT" : "PIN");
228 static struct kvm_events_ops ioport_events
= {
229 .is_begin_event
= ioport_event_begin
,
230 .is_end_event
= ioport_event_end
,
231 .decode_key
= ioport_event_decode_key
,
232 .name
= "IO Port Access"
235 static const char *report_event
= "vmexit";
236 struct kvm_events_ops
*events_ops
;
238 static bool register_kvm_events_ops(void)
242 if (!strcmp(report_event
, "vmexit"))
243 events_ops
= &exit_events
;
244 else if (!strcmp(report_event
, "mmio"))
245 events_ops
= &mmio_events
;
246 else if (!strcmp(report_event
, "ioport"))
247 events_ops
= &ioport_events
;
249 pr_err("Unknown report event:%s\n", report_event
);
256 struct kvm_event_stats
{
262 struct list_head hash_entry
;
265 struct event_key key
;
267 struct kvm_event_stats total
;
269 #define DEFAULT_VCPU_NUM 8
271 struct kvm_event_stats
*vcpu
;
274 struct vcpu_event_record
{
277 struct kvm_event
*last_event
;
280 #define EVENTS_BITS 12
281 #define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS)
283 static u64 total_time
;
284 static u64 total_count
;
285 static struct list_head kvm_events_cache
[EVENTS_CACHE_SIZE
];
287 static void init_kvm_event_record(void)
291 for (i
= 0; i
< (int)EVENTS_CACHE_SIZE
; i
++)
292 INIT_LIST_HEAD(&kvm_events_cache
[i
]);
295 static int kvm_events_hash_fn(u64 key
)
297 return key
& (EVENTS_CACHE_SIZE
- 1);
300 static bool kvm_event_expand(struct kvm_event
*event
, int vcpu_id
)
302 int old_max_vcpu
= event
->max_vcpu
;
304 if (vcpu_id
< event
->max_vcpu
)
307 while (event
->max_vcpu
<= vcpu_id
)
308 event
->max_vcpu
+= DEFAULT_VCPU_NUM
;
310 event
->vcpu
= realloc(event
->vcpu
,
311 event
->max_vcpu
* sizeof(*event
->vcpu
));
313 pr_err("Not enough memory\n");
317 memset(event
->vcpu
+ old_max_vcpu
, 0,
318 (event
->max_vcpu
- old_max_vcpu
) * sizeof(*event
->vcpu
));
322 static struct kvm_event
*kvm_alloc_init_event(struct event_key
*key
)
324 struct kvm_event
*event
;
326 event
= zalloc(sizeof(*event
));
328 pr_err("Not enough memory\n");
336 static struct kvm_event
*find_create_kvm_event(struct event_key
*key
)
338 struct kvm_event
*event
;
339 struct list_head
*head
;
341 BUG_ON(key
->key
== INVALID_KEY
);
343 head
= &kvm_events_cache
[kvm_events_hash_fn(key
->key
)];
344 list_for_each_entry(event
, head
, hash_entry
)
345 if (event
->key
.key
== key
->key
&& event
->key
.info
== key
->info
)
348 event
= kvm_alloc_init_event(key
);
352 list_add(&event
->hash_entry
, head
);
356 static bool handle_begin_event(struct vcpu_event_record
*vcpu_record
,
357 struct event_key
*key
, u64 timestamp
)
359 struct kvm_event
*event
= NULL
;
361 if (key
->key
!= INVALID_KEY
)
362 event
= find_create_kvm_event(key
);
364 vcpu_record
->last_event
= event
;
365 vcpu_record
->start_time
= timestamp
;
370 kvm_update_event_stats(struct kvm_event_stats
*kvm_stats
, u64 time_diff
)
372 kvm_stats
->time
+= time_diff
;
373 update_stats(&kvm_stats
->stats
, time_diff
);
376 static double kvm_event_rel_stddev(int vcpu_id
, struct kvm_event
*event
)
378 struct kvm_event_stats
*kvm_stats
= &event
->total
;
381 kvm_stats
= &event
->vcpu
[vcpu_id
];
383 return rel_stddev_stats(stddev_stats(&kvm_stats
->stats
),
384 avg_stats(&kvm_stats
->stats
));
387 static bool update_kvm_event(struct kvm_event
*event
, int vcpu_id
,
390 kvm_update_event_stats(&event
->total
, time_diff
);
392 if (!kvm_event_expand(event
, vcpu_id
))
395 kvm_update_event_stats(&event
->vcpu
[vcpu_id
], time_diff
);
399 static bool handle_end_event(struct vcpu_event_record
*vcpu_record
,
400 struct event_key
*key
, u64 timestamp
)
402 struct kvm_event
*event
;
403 u64 time_begin
, time_diff
;
405 event
= vcpu_record
->last_event
;
406 time_begin
= vcpu_record
->start_time
;
408 /* The begin event is not caught. */
413 * In some case, the 'begin event' only records the start timestamp,
414 * the actual event is recognized in the 'end event' (e.g. mmio-event).
417 /* Both begin and end events did not get the key. */
418 if (!event
&& key
->key
== INVALID_KEY
)
422 event
= find_create_kvm_event(key
);
427 vcpu_record
->last_event
= NULL
;
428 vcpu_record
->start_time
= 0;
430 BUG_ON(timestamp
< time_begin
);
432 time_diff
= timestamp
- time_begin
;
433 return update_kvm_event(event
, vcpu_record
->vcpu_id
, time_diff
);
437 struct vcpu_event_record
*per_vcpu_record(struct thread
*thread
,
438 struct perf_evsel
*evsel
,
439 struct perf_sample
*sample
)
441 /* Only kvm_entry records vcpu id. */
442 if (!thread
->priv
&& kvm_entry_event(evsel
)) {
443 struct vcpu_event_record
*vcpu_record
;
445 vcpu_record
= zalloc(sizeof(*vcpu_record
));
447 pr_err("%s: Not enough memory\n", __func__
);
451 vcpu_record
->vcpu_id
= perf_evsel__intval(evsel
, sample
, "vcpu_id");
452 thread
->priv
= vcpu_record
;
458 static bool handle_kvm_event(struct thread
*thread
, struct perf_evsel
*evsel
,
459 struct perf_sample
*sample
)
461 struct vcpu_event_record
*vcpu_record
;
462 struct event_key key
= {.key
= INVALID_KEY
};
464 vcpu_record
= per_vcpu_record(thread
, evsel
, sample
);
468 if (events_ops
->is_begin_event(evsel
, sample
, &key
))
469 return handle_begin_event(vcpu_record
, &key
, sample
->time
);
471 if (events_ops
->is_end_event(evsel
, sample
, &key
))
472 return handle_end_event(vcpu_record
, &key
, sample
->time
);
477 typedef int (*key_cmp_fun
)(struct kvm_event
*, struct kvm_event
*, int);
478 struct kvm_event_key
{
483 static int trace_vcpu
= -1;
484 #define GET_EVENT_KEY(func, field) \
485 static u64 get_event_ ##func(struct kvm_event *event, int vcpu) \
488 return event->total.field; \
490 if (vcpu >= event->max_vcpu) \
493 return event->vcpu[vcpu].field; \
496 #define COMPARE_EVENT_KEY(func, field) \
497 GET_EVENT_KEY(func, field) \
498 static int compare_kvm_event_ ## func(struct kvm_event *one, \
499 struct kvm_event *two, int vcpu)\
501 return get_event_ ##func(one, vcpu) > \
502 get_event_ ##func(two, vcpu); \
505 GET_EVENT_KEY(time
, time
);
506 COMPARE_EVENT_KEY(count
, stats
.n
);
507 COMPARE_EVENT_KEY(mean
, stats
.mean
);
509 #define DEF_SORT_NAME_KEY(name, compare_key) \
510 { #name, compare_kvm_event_ ## compare_key }
512 static struct kvm_event_key keys
[] = {
513 DEF_SORT_NAME_KEY(sample
, count
),
514 DEF_SORT_NAME_KEY(time
, mean
),
518 static const char *sort_key
= "sample";
519 static key_cmp_fun compare
;
521 static bool select_key(void)
525 for (i
= 0; keys
[i
].name
; i
++) {
526 if (!strcmp(keys
[i
].name
, sort_key
)) {
527 compare
= keys
[i
].key
;
532 pr_err("Unknown compare key:%s\n", sort_key
);
536 static struct rb_root result
;
537 static void insert_to_result(struct kvm_event
*event
, key_cmp_fun bigger
,
540 struct rb_node
**rb
= &result
.rb_node
;
541 struct rb_node
*parent
= NULL
;
545 p
= container_of(*rb
, struct kvm_event
, rb
);
548 if (bigger(event
, p
, vcpu
))
549 rb
= &(*rb
)->rb_left
;
551 rb
= &(*rb
)->rb_right
;
554 rb_link_node(&event
->rb
, parent
, rb
);
555 rb_insert_color(&event
->rb
, &result
);
558 static void update_total_count(struct kvm_event
*event
, int vcpu
)
560 total_count
+= get_event_count(event
, vcpu
);
561 total_time
+= get_event_time(event
, vcpu
);
564 static bool event_is_valid(struct kvm_event
*event
, int vcpu
)
566 return !!get_event_count(event
, vcpu
);
569 static void sort_result(int vcpu
)
572 struct kvm_event
*event
;
574 for (i
= 0; i
< EVENTS_CACHE_SIZE
; i
++)
575 list_for_each_entry(event
, &kvm_events_cache
[i
], hash_entry
)
576 if (event_is_valid(event
, vcpu
)) {
577 update_total_count(event
, vcpu
);
578 insert_to_result(event
, compare
, vcpu
);
582 /* returns left most element of result, and erase it */
583 static struct kvm_event
*pop_from_result(void)
585 struct rb_node
*node
= rb_first(&result
);
590 rb_erase(node
, &result
);
591 return container_of(node
, struct kvm_event
, rb
);
594 static void print_vcpu_info(int vcpu
)
596 pr_info("Analyze events for ");
599 pr_info("all VCPUs:\n\n");
601 pr_info("VCPU %d:\n\n", vcpu
);
604 static void print_result(int vcpu
)
607 struct kvm_event
*event
;
610 print_vcpu_info(vcpu
);
611 pr_info("%20s ", events_ops
->name
);
612 pr_info("%10s ", "Samples");
613 pr_info("%9s ", "Samples%");
615 pr_info("%9s ", "Time%");
616 pr_info("%16s ", "Avg time");
619 while ((event
= pop_from_result())) {
622 ecount
= get_event_count(event
, vcpu
);
623 etime
= get_event_time(event
, vcpu
);
625 events_ops
->decode_key(&event
->key
, decode
);
626 pr_info("%20s ", decode
);
627 pr_info("%10llu ", (unsigned long long)ecount
);
628 pr_info("%8.2f%% ", (double)ecount
/ total_count
* 100);
629 pr_info("%8.2f%% ", (double)etime
/ total_time
* 100);
630 pr_info("%9.2fus ( +-%7.2f%% )", (double)etime
/ ecount
/1e3
,
631 kvm_event_rel_stddev(vcpu
, event
));
635 pr_info("\nTotal Samples:%lld, Total events handled time:%.2fus.\n\n",
636 (unsigned long long)total_count
, total_time
/ 1e3
);
639 static int process_sample_event(struct perf_tool
*tool __maybe_unused
,
640 union perf_event
*event
,
641 struct perf_sample
*sample
,
642 struct perf_evsel
*evsel
,
643 struct machine
*machine
)
645 struct thread
*thread
= machine__findnew_thread(machine
, sample
->tid
);
647 if (thread
== NULL
) {
648 pr_debug("problem processing %d event, skipping it.\n",
653 if (!handle_kvm_event(thread
, evsel
, sample
))
659 static struct perf_tool eops
= {
660 .sample
= process_sample_event
,
661 .comm
= perf_event__process_comm
,
662 .ordered_samples
= true,
665 static int get_cpu_isa(struct perf_session
*session
)
667 char *cpuid
= session
->header
.env
.cpuid
;
670 if (strstr(cpuid
, "Intel"))
672 else if (strstr(cpuid
, "AMD"))
675 pr_err("CPU %s is not supported.\n", cpuid
);
682 static const char *file_name
;
684 static int read_events(void)
686 struct perf_session
*kvm_session
;
689 kvm_session
= perf_session__new(file_name
, O_RDONLY
, 0, false, &eops
);
691 pr_err("Initializing perf session failed\n");
695 if (!perf_session__has_traces(kvm_session
, "kvm record"))
699 * Do not use 'isa' recorded in kvm_exit tracepoint since it is not
700 * traced in the old kernel.
702 ret
= get_cpu_isa(kvm_session
);
709 return perf_session__process_events(kvm_session
, &eops
);
712 static bool verify_vcpu(int vcpu
)
714 if (vcpu
!= -1 && vcpu
< 0) {
715 pr_err("Invalid vcpu:%d.\n", vcpu
);
722 static int kvm_events_report_vcpu(int vcpu
)
726 if (!verify_vcpu(vcpu
))
732 if (!register_kvm_events_ops())
735 init_kvm_event_record();
748 static const char * const record_args
[] = {
754 "-e", "kvm:kvm_entry",
755 "-e", "kvm:kvm_exit",
756 "-e", "kvm:kvm_mmio",
760 #define STRDUP_FAIL_EXIT(s) \
768 static int kvm_events_record(int argc
, const char **argv
)
770 unsigned int rec_argc
, i
, j
;
771 const char **rec_argv
;
773 rec_argc
= ARRAY_SIZE(record_args
) + argc
+ 2;
774 rec_argv
= calloc(rec_argc
+ 1, sizeof(char *));
776 if (rec_argv
== NULL
)
779 for (i
= 0; i
< ARRAY_SIZE(record_args
); i
++)
780 rec_argv
[i
] = STRDUP_FAIL_EXIT(record_args
[i
]);
782 rec_argv
[i
++] = STRDUP_FAIL_EXIT("-o");
783 rec_argv
[i
++] = STRDUP_FAIL_EXIT(file_name
);
785 for (j
= 1; j
< (unsigned int)argc
; j
++, i
++)
786 rec_argv
[i
] = argv
[j
];
788 return cmd_record(i
, rec_argv
, NULL
);
791 static const char * const kvm_events_report_usage
[] = {
792 "perf kvm stat report [<options>]",
796 static const struct option kvm_events_report_options
[] = {
797 OPT_STRING(0, "event", &report_event
, "report event",
798 "event for reporting: vmexit, mmio, ioport"),
799 OPT_INTEGER(0, "vcpu", &trace_vcpu
,
800 "vcpu id to report"),
801 OPT_STRING('k', "key", &sort_key
, "sort-key",
802 "key for sorting: sample(sort by samples number)"
803 " time (sort by avg time)"),
807 static int kvm_events_report(int argc
, const char **argv
)
812 argc
= parse_options(argc
, argv
,
813 kvm_events_report_options
,
814 kvm_events_report_usage
, 0);
816 usage_with_options(kvm_events_report_usage
,
817 kvm_events_report_options
);
820 return kvm_events_report_vcpu(trace_vcpu
);
823 static void print_kvm_stat_usage(void)
825 printf("Usage: perf kvm stat <command>\n\n");
827 printf("# Available commands:\n");
828 printf("\trecord: record kvm events\n");
829 printf("\treport: report statistical data of kvm events\n");
831 printf("\nOtherwise, it is the alias of 'perf stat':\n");
834 static int kvm_cmd_stat(int argc
, const char **argv
)
837 print_kvm_stat_usage();
841 if (!strncmp(argv
[1], "rec", 3))
842 return kvm_events_record(argc
- 1, argv
+ 1);
844 if (!strncmp(argv
[1], "rep", 3))
845 return kvm_events_report(argc
- 1 , argv
+ 1);
848 return cmd_stat(argc
, argv
, NULL
);
851 static char name_buffer
[256];
853 static const char * const kvm_usage
[] = {
854 "perf kvm [<options>] {top|record|report|diff|buildid-list|stat}",
858 static const struct option kvm_options
[] = {
859 OPT_STRING('i', "input", &file_name
, "file",
861 OPT_STRING('o', "output", &file_name
, "file",
863 OPT_BOOLEAN(0, "guest", &perf_guest
,
864 "Collect guest os data"),
865 OPT_BOOLEAN(0, "host", &perf_host
,
866 "Collect host os data"),
867 OPT_STRING(0, "guestmount", &symbol_conf
.guestmount
, "directory",
868 "guest mount directory under which every guest os"
869 " instance has a subdir"),
870 OPT_STRING(0, "guestvmlinux", &symbol_conf
.default_guest_vmlinux_name
,
871 "file", "file saving guest os vmlinux"),
872 OPT_STRING(0, "guestkallsyms", &symbol_conf
.default_guest_kallsyms
,
873 "file", "file saving guest os /proc/kallsyms"),
874 OPT_STRING(0, "guestmodules", &symbol_conf
.default_guest_modules
,
875 "file", "file saving guest os /proc/modules"),
879 static int __cmd_record(int argc
, const char **argv
)
881 int rec_argc
, i
= 0, j
;
882 const char **rec_argv
;
885 rec_argv
= calloc(rec_argc
+ 1, sizeof(char *));
886 rec_argv
[i
++] = strdup("record");
887 rec_argv
[i
++] = strdup("-o");
888 rec_argv
[i
++] = strdup(file_name
);
889 for (j
= 1; j
< argc
; j
++, i
++)
890 rec_argv
[i
] = argv
[j
];
892 BUG_ON(i
!= rec_argc
);
894 return cmd_record(i
, rec_argv
, NULL
);
897 static int __cmd_report(int argc
, const char **argv
)
899 int rec_argc
, i
= 0, j
;
900 const char **rec_argv
;
903 rec_argv
= calloc(rec_argc
+ 1, sizeof(char *));
904 rec_argv
[i
++] = strdup("report");
905 rec_argv
[i
++] = strdup("-i");
906 rec_argv
[i
++] = strdup(file_name
);
907 for (j
= 1; j
< argc
; j
++, i
++)
908 rec_argv
[i
] = argv
[j
];
910 BUG_ON(i
!= rec_argc
);
912 return cmd_report(i
, rec_argv
, NULL
);
915 static int __cmd_buildid_list(int argc
, const char **argv
)
917 int rec_argc
, i
= 0, j
;
918 const char **rec_argv
;
921 rec_argv
= calloc(rec_argc
+ 1, sizeof(char *));
922 rec_argv
[i
++] = strdup("buildid-list");
923 rec_argv
[i
++] = strdup("-i");
924 rec_argv
[i
++] = strdup(file_name
);
925 for (j
= 1; j
< argc
; j
++, i
++)
926 rec_argv
[i
] = argv
[j
];
928 BUG_ON(i
!= rec_argc
);
930 return cmd_buildid_list(i
, rec_argv
, NULL
);
933 int cmd_kvm(int argc
, const char **argv
, const char *prefix __maybe_unused
)
938 argc
= parse_options(argc
, argv
, kvm_options
, kvm_usage
,
939 PARSE_OPT_STOP_AT_NON_OPTION
);
941 usage_with_options(kvm_usage
, kvm_options
);
947 if (perf_host
&& !perf_guest
)
948 sprintf(name_buffer
, "perf.data.host");
949 else if (!perf_host
&& perf_guest
)
950 sprintf(name_buffer
, "perf.data.guest");
952 sprintf(name_buffer
, "perf.data.kvm");
953 file_name
= name_buffer
;
956 if (!strncmp(argv
[0], "rec", 3))
957 return __cmd_record(argc
, argv
);
958 else if (!strncmp(argv
[0], "rep", 3))
959 return __cmd_report(argc
, argv
);
960 else if (!strncmp(argv
[0], "diff", 4))
961 return cmd_diff(argc
, argv
, NULL
);
962 else if (!strncmp(argv
[0], "top", 3))
963 return cmd_top(argc
, argv
, NULL
);
964 else if (!strncmp(argv
[0], "buildid-list", 12))
965 return __cmd_buildid_list(argc
, argv
);
966 else if (!strncmp(argv
[0], "stat", 4))
967 return kvm_cmd_stat(argc
, argv
);
969 usage_with_options(kvm_usage
, kvm_options
);