diff options
Diffstat (limited to 'tools/perf/builtin-kvm.c')
| -rw-r--r-- | tools/perf/builtin-kvm.c | 156 | 
1 files changed, 93 insertions, 63 deletions
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 260abc535b5..ca3f80ebc10 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -22,9 +22,10 @@  #include <pthread.h>  #include <math.h> -#include "../../arch/x86/include/asm/svm.h" -#include "../../arch/x86/include/asm/vmx.h" -#include "../../arch/x86/include/asm/kvm.h" +#if defined(__i386__) || defined(__x86_64__) +#include <asm/svm.h> +#include <asm/vmx.h> +#include <asm/kvm.h>  struct event_key {  	#define INVALID_KEY     (~0ULL) @@ -58,7 +59,7 @@ struct kvm_event_key {  }; -struct perf_kvm; +struct perf_kvm_stat;  struct kvm_events_ops {  	bool (*is_begin_event)(struct perf_evsel *evsel, @@ -66,7 +67,7 @@ struct kvm_events_ops {  			       struct event_key *key);  	bool (*is_end_event)(struct perf_evsel *evsel,  			     struct perf_sample *sample, struct event_key *key); -	void (*decode_key)(struct perf_kvm *kvm, struct event_key *key, +	void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key,  			   char decode[20]);  	const char *name;  }; @@ -79,7 +80,7 @@ struct exit_reasons_table {  #define EVENTS_BITS		12  #define EVENTS_CACHE_SIZE	(1UL << EVENTS_BITS) -struct perf_kvm { +struct perf_kvm_stat {  	struct perf_tool    tool;  	struct perf_session *session; @@ -146,7 +147,7 @@ static struct exit_reasons_table svm_exit_reasons[] = {  	SVM_EXIT_REASONS  }; -static const char *get_exit_reason(struct perf_kvm *kvm, u64 exit_code) +static const char *get_exit_reason(struct perf_kvm_stat *kvm, u64 exit_code)  {  	int i = kvm->exit_reasons_size;  	struct exit_reasons_table *tbl = kvm->exit_reasons; @@ -162,7 +163,7 @@ static const char *get_exit_reason(struct perf_kvm *kvm, u64 exit_code)  	return "UNKNOWN";  } -static void exit_event_decode_key(struct perf_kvm *kvm, +static void exit_event_decode_key(struct perf_kvm_stat *kvm,  				  struct event_key *key,  				  char decode[20])  { @@ -228,7 +229,7 @@ static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample,  	return false;  } -static void mmio_event_decode_key(struct perf_kvm *kvm __maybe_unused, +static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,  				  struct event_key *key,  				  char decode[20])  { @@ -271,7 +272,7 @@ static bool ioport_event_end(struct perf_evsel *evsel,  	return kvm_entry_event(evsel);  } -static void ioport_event_decode_key(struct perf_kvm *kvm __maybe_unused, +static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,  				    struct event_key *key,  				    char decode[20])  { @@ -286,7 +287,7 @@ static struct kvm_events_ops ioport_events = {  	.name = "IO Port Access"  }; -static bool register_kvm_events_ops(struct perf_kvm *kvm) +static bool register_kvm_events_ops(struct perf_kvm_stat *kvm)  {  	bool ret = true; @@ -311,11 +312,11 @@ struct vcpu_event_record {  }; -static void init_kvm_event_record(struct perf_kvm *kvm) +static void init_kvm_event_record(struct perf_kvm_stat *kvm)  { -	int i; +	unsigned int i; -	for (i = 0; i < (int)EVENTS_CACHE_SIZE; i++) +	for (i = 0; i < EVENTS_CACHE_SIZE; i++)  		INIT_LIST_HEAD(&kvm->kvm_events_cache[i]);  } @@ -360,7 +361,7 @@ static struct kvm_event *kvm_alloc_init_event(struct event_key *key)  	return event;  } -static struct kvm_event *find_create_kvm_event(struct perf_kvm *kvm, +static struct kvm_event *find_create_kvm_event(struct perf_kvm_stat *kvm,  					       struct event_key *key)  {  	struct kvm_event *event; @@ -369,9 +370,10 @@ static struct kvm_event *find_create_kvm_event(struct perf_kvm *kvm,  	BUG_ON(key->key == INVALID_KEY);  	head = &kvm->kvm_events_cache[kvm_events_hash_fn(key->key)]; -	list_for_each_entry(event, head, hash_entry) +	list_for_each_entry(event, head, hash_entry) {  		if (event->key.key == key->key && event->key.info == key->info)  			return event; +	}  	event = kvm_alloc_init_event(key);  	if (!event) @@ -381,7 +383,7 @@ static struct kvm_event *find_create_kvm_event(struct perf_kvm *kvm,  	return event;  } -static bool handle_begin_event(struct perf_kvm *kvm, +static bool handle_begin_event(struct perf_kvm_stat *kvm,  			       struct vcpu_event_record *vcpu_record,  			       struct event_key *key, u64 timestamp)  { @@ -416,7 +418,10 @@ static double kvm_event_rel_stddev(int vcpu_id, struct kvm_event *event)  static bool update_kvm_event(struct kvm_event *event, int vcpu_id,  			     u64 time_diff)  { -	kvm_update_event_stats(&event->total, time_diff); +	if (vcpu_id == -1) { +		kvm_update_event_stats(&event->total, time_diff); +		return true; +	}  	if (!kvm_event_expand(event, vcpu_id))  		return false; @@ -425,13 +430,19 @@ static bool update_kvm_event(struct kvm_event *event, int vcpu_id,  	return true;  } -static bool handle_end_event(struct perf_kvm *kvm, +static bool handle_end_event(struct perf_kvm_stat *kvm,  			     struct vcpu_event_record *vcpu_record,  			     struct event_key *key,  			     u64 timestamp)  {  	struct kvm_event *event;  	u64 time_begin, time_diff; +	int vcpu; + +	if (kvm->trace_vcpu == -1) +		vcpu = -1; +	else +		vcpu = vcpu_record->vcpu_id;  	event = vcpu_record->last_event;  	time_begin = vcpu_record->start_time; @@ -461,7 +472,7 @@ static bool handle_end_event(struct perf_kvm *kvm,  	BUG_ON(timestamp < time_begin);  	time_diff = timestamp - time_begin; -	return update_kvm_event(event, vcpu_record->vcpu_id, time_diff); +	return update_kvm_event(event, vcpu, time_diff);  }  static @@ -486,7 +497,7 @@ struct vcpu_event_record *per_vcpu_record(struct thread *thread,  	return thread->priv;  } -static bool handle_kvm_event(struct perf_kvm *kvm, +static bool handle_kvm_event(struct perf_kvm_stat *kvm,  			     struct thread *thread,  			     struct perf_evsel *evsel,  			     struct perf_sample *sample) @@ -498,6 +509,11 @@ static bool handle_kvm_event(struct perf_kvm *kvm,  	if (!vcpu_record)  		return true; +	/* only process events for vcpus user cares about */ +	if ((kvm->trace_vcpu != -1) && +	    (kvm->trace_vcpu != vcpu_record->vcpu_id)) +		return true; +  	if (kvm->events_ops->is_begin_event(evsel, sample, &key))  		return handle_begin_event(kvm, vcpu_record, &key, sample->time); @@ -541,7 +557,7 @@ static struct kvm_event_key keys[] = {  	{ NULL, NULL }  }; -static bool select_key(struct perf_kvm *kvm) +static bool select_key(struct perf_kvm_stat *kvm)  {  	int i; @@ -577,7 +593,8 @@ static void insert_to_result(struct rb_root *result, struct kvm_event *event,  	rb_insert_color(&event->rb, result);  } -static void update_total_count(struct perf_kvm *kvm, struct kvm_event *event) +static void +update_total_count(struct perf_kvm_stat *kvm, struct kvm_event *event)  {  	int vcpu = kvm->trace_vcpu; @@ -590,19 +607,21 @@ static bool event_is_valid(struct kvm_event *event, int vcpu)  	return !!get_event_count(event, vcpu);  } -static void sort_result(struct perf_kvm *kvm) +static void sort_result(struct perf_kvm_stat *kvm)  {  	unsigned int i;  	int vcpu = kvm->trace_vcpu;  	struct kvm_event *event; -	for (i = 0; i < EVENTS_CACHE_SIZE; i++) -		list_for_each_entry(event, &kvm->kvm_events_cache[i], hash_entry) +	for (i = 0; i < EVENTS_CACHE_SIZE; i++) { +		list_for_each_entry(event, &kvm->kvm_events_cache[i], hash_entry) {  			if (event_is_valid(event, vcpu)) {  				update_total_count(kvm, event);  				insert_to_result(&kvm->result, event,  						 kvm->compare, vcpu);  			} +		} +	}  }  /* returns left most element of result, and erase it */ @@ -627,7 +646,7 @@ static void print_vcpu_info(int vcpu)  		pr_info("VCPU %d:\n\n", vcpu);  } -static void print_result(struct perf_kvm *kvm) +static void print_result(struct perf_kvm_stat *kvm)  {  	char decode[20];  	struct kvm_event *event; @@ -659,8 +678,8 @@ static void print_result(struct perf_kvm *kvm)  		pr_info("\n");  	} -	pr_info("\nTotal Samples:%lld, Total events handled time:%.2fus.\n\n", -		(unsigned long long)kvm->total_count, kvm->total_time / 1e3); +	pr_info("\nTotal Samples:%" PRIu64 ", Total events handled time:%.2fus.\n\n", +		kvm->total_count, kvm->total_time / 1e3);  }  static int process_sample_event(struct perf_tool *tool, @@ -670,7 +689,8 @@ static int process_sample_event(struct perf_tool *tool,  				struct machine *machine)  {  	struct thread *thread = machine__findnew_thread(machine, sample->tid); -	struct perf_kvm *kvm = container_of(tool, struct perf_kvm, tool); +	struct perf_kvm_stat *kvm = container_of(tool, struct perf_kvm_stat, +						 tool);  	if (thread == NULL) {  		pr_debug("problem processing %d event, skipping it.\n", @@ -701,7 +721,7 @@ static int get_cpu_isa(struct perf_session *session)  	return isa;  } -static int read_events(struct perf_kvm *kvm) +static int read_events(struct perf_kvm_stat *kvm)  {  	int ret; @@ -750,7 +770,7 @@ static bool verify_vcpu(int vcpu)  	return true;  } -static int kvm_events_report_vcpu(struct perf_kvm *kvm) +static int kvm_events_report_vcpu(struct perf_kvm_stat *kvm)  {  	int ret = -EINVAL;  	int vcpu = kvm->trace_vcpu; @@ -798,7 +818,8 @@ static const char * const record_args[] = {  		_p;			\  	}) -static int kvm_events_record(struct perf_kvm *kvm, int argc, const char **argv) +static int +kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)  {  	unsigned int rec_argc, i, j;  	const char **rec_argv; @@ -821,7 +842,8 @@ static int kvm_events_record(struct perf_kvm *kvm, int argc, const char **argv)  	return cmd_record(i, rec_argv, NULL);  } -static int kvm_events_report(struct perf_kvm *kvm, int argc, const char **argv) +static int +kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)  {  	const struct option kvm_events_report_options[] = {  		OPT_STRING(0, "event", &kvm->report_event, "report event", @@ -864,24 +886,37 @@ static void print_kvm_stat_usage(void)  	printf("\nOtherwise, it is the alias of 'perf stat':\n");  } -static int kvm_cmd_stat(struct perf_kvm *kvm, int argc, const char **argv) +static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)  { +	struct perf_kvm_stat kvm = { +		.file_name = file_name, + +		.trace_vcpu	= -1, +		.report_event	= "vmexit", +		.sort_key	= "sample", + +		.exit_reasons = svm_exit_reasons, +		.exit_reasons_size = ARRAY_SIZE(svm_exit_reasons), +		.exit_reasons_isa = "SVM", +	}; +  	if (argc == 1) {  		print_kvm_stat_usage();  		goto perf_stat;  	}  	if (!strncmp(argv[1], "rec", 3)) -		return kvm_events_record(kvm, argc - 1, argv + 1); +		return kvm_events_record(&kvm, argc - 1, argv + 1);  	if (!strncmp(argv[1], "rep", 3)) -		return kvm_events_report(kvm, argc - 1 , argv + 1); +		return kvm_events_report(&kvm, argc - 1 , argv + 1);  perf_stat:  	return cmd_stat(argc, argv, NULL);  } +#endif -static int __cmd_record(struct perf_kvm *kvm, int argc, const char **argv) +static int __cmd_record(const char *file_name, int argc, const char **argv)  {  	int rec_argc, i = 0, j;  	const char **rec_argv; @@ -890,7 +925,7 @@ static int __cmd_record(struct perf_kvm *kvm, int argc, const char **argv)  	rec_argv = calloc(rec_argc + 1, sizeof(char *));  	rec_argv[i++] = strdup("record");  	rec_argv[i++] = strdup("-o"); -	rec_argv[i++] = strdup(kvm->file_name); +	rec_argv[i++] = strdup(file_name);  	for (j = 1; j < argc; j++, i++)  		rec_argv[i] = argv[j]; @@ -899,7 +934,7 @@ static int __cmd_record(struct perf_kvm *kvm, int argc, const char **argv)  	return cmd_record(i, rec_argv, NULL);  } -static int __cmd_report(struct perf_kvm *kvm, int argc, const char **argv) +static int __cmd_report(const char *file_name, int argc, const char **argv)  {  	int rec_argc, i = 0, j;  	const char **rec_argv; @@ -908,7 +943,7 @@ static int __cmd_report(struct perf_kvm *kvm, int argc, const char **argv)  	rec_argv = calloc(rec_argc + 1, sizeof(char *));  	rec_argv[i++] = strdup("report");  	rec_argv[i++] = strdup("-i"); -	rec_argv[i++] = strdup(kvm->file_name); +	rec_argv[i++] = strdup(file_name);  	for (j = 1; j < argc; j++, i++)  		rec_argv[i] = argv[j]; @@ -917,7 +952,8 @@ static int __cmd_report(struct perf_kvm *kvm, int argc, const char **argv)  	return cmd_report(i, rec_argv, NULL);  } -static int __cmd_buildid_list(struct perf_kvm *kvm, int argc, const char **argv) +static int +__cmd_buildid_list(const char *file_name, int argc, const char **argv)  {  	int rec_argc, i = 0, j;  	const char **rec_argv; @@ -926,7 +962,7 @@ static int __cmd_buildid_list(struct perf_kvm *kvm, int argc, const char **argv)  	rec_argv = calloc(rec_argc + 1, sizeof(char *));  	rec_argv[i++] = strdup("buildid-list");  	rec_argv[i++] = strdup("-i"); -	rec_argv[i++] = strdup(kvm->file_name); +	rec_argv[i++] = strdup(file_name);  	for (j = 1; j < argc; j++, i++)  		rec_argv[i] = argv[j]; @@ -937,20 +973,12 @@ static int __cmd_buildid_list(struct perf_kvm *kvm, int argc, const char **argv)  int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)  { -	struct perf_kvm kvm = { -		.trace_vcpu	= -1, -		.report_event	= "vmexit", -		.sort_key	= "sample", - -		.exit_reasons = svm_exit_reasons, -		.exit_reasons_size = ARRAY_SIZE(svm_exit_reasons), -		.exit_reasons_isa = "SVM", -	}; +	const char *file_name;  	const struct option kvm_options[] = { -		OPT_STRING('i', "input", &kvm.file_name, "file", +		OPT_STRING('i', "input", &file_name, "file",  			   "Input file name"), -		OPT_STRING('o', "output", &kvm.file_name, "file", +		OPT_STRING('o', "output", &file_name, "file",  			   "Output file name"),  		OPT_BOOLEAN(0, "guest", &perf_guest,  			    "Collect guest os data"), @@ -985,32 +1013,34 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)  	if (!perf_host)  		perf_guest = 1; -	if (!kvm.file_name) { +	if (!file_name) {  		if (perf_host && !perf_guest) -			kvm.file_name = strdup("perf.data.host"); +			file_name = strdup("perf.data.host");  		else if (!perf_host && perf_guest) -			kvm.file_name = strdup("perf.data.guest"); +			file_name = strdup("perf.data.guest");  		else -			kvm.file_name = strdup("perf.data.kvm"); +			file_name = strdup("perf.data.kvm"); -		if (!kvm.file_name) { +		if (!file_name) {  			pr_err("Failed to allocate memory for filename\n");  			return -ENOMEM;  		}  	}  	if (!strncmp(argv[0], "rec", 3)) -		return __cmd_record(&kvm, argc, argv); +		return __cmd_record(file_name, argc, argv);  	else if (!strncmp(argv[0], "rep", 3)) -		return __cmd_report(&kvm, argc, argv); +		return __cmd_report(file_name, argc, argv);  	else if (!strncmp(argv[0], "diff", 4))  		return cmd_diff(argc, argv, NULL);  	else if (!strncmp(argv[0], "top", 3))  		return cmd_top(argc, argv, NULL);  	else if (!strncmp(argv[0], "buildid-list", 12)) -		return __cmd_buildid_list(&kvm, argc, argv); +		return __cmd_buildid_list(file_name, argc, argv); +#if defined(__i386__) || defined(__x86_64__)  	else if (!strncmp(argv[0], "stat", 4)) -		return kvm_cmd_stat(&kvm, argc, argv); +		return kvm_cmd_stat(file_name, argc, argv); +#endif  	else  		usage_with_options(kvm_usage, kvm_options);  |