All of lore.kernel.org
 help / color / mirror / Atom feed
From: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
To: David Ahern <dsahern@gmail.com>
Cc: linux-kernel@vger.kernel.org, mingo@kernel.org,
	peterz@infradead.org, fweisbec@gmail.com,
	Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com>,
	Dong Hao <haodong@linux.vnet.ibm.com>
Subject: Re: [PATCH 12/12] perf kvm: add live mode
Date: Mon, 8 Oct 2012 13:35:34 -0700	[thread overview]
Message-ID: <20121008203534.GF2631@ghostprotocols.net> (raw)
In-Reply-To: <1349716656-48165-13-git-send-email-dsahern@gmail.com>

Em Mon, Oct 08, 2012 at 11:17:36AM -0600, David Ahern escreveu:
> perf kvm stat currently requires back to back record and report
> commands to see stats. e.g,.
> 
>   perf kvm stat record -p $pid -- sleep 1
>   perf kvm stat report
> 
> This is rather inconvenvient for on box monitoring of a VM. This
> patch introduces a 'live' mode that in effect combines the record
> plus report into one command. e.g., to monitor a single VM:
> 
>   perf kvm stat live -p $pid
> 
> Same stats options for the record+report path work with the live mode.
> Display rate defaults to 1 and can be changed using the -d option.

Overall it looks good, I like the fact you're not doing it the way perf
script does, i.e. that "pipe mode" thing, more or less like I'm doing on
'perf trace', but I think this is the time to get rid of 'perf_session'
too for this specific "live mode" tools.

I'm almost getting there for 'trace' and 'top', just need to move the
ordered_samples code to evlist, then session, top, trace, kvm live and
script will not need to use 'perf_session' at all.

Also that 'perf_kvm__open_counters' really is just a third copy of code
in 'record' and 'top', right? You could move it to
'perf_ev{list,open}__open' and solve this dup :-)

I applied the cleanups/simple stuff, will try to do some of the prep
work on ordered_samples to use on top and trace and then I think you
could look there so that we get to something that is useful for all
these !perf.data tools.

- Arnaldo
 
> Signed-off-by: David Ahern <dsahern@gmail.com>
> Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
> Cc: Ingo Molnar <mingo@kernel.org>
> Cc: Frederic Weisbecker <fweisbec@gmail.com>
> Cc: Peter Zijlstra <peterz@infradead.org>
> Cc: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com>
> Cc: Dong Hao <haodong@linux.vnet.ibm.com>
> ---
>  tools/perf/builtin-kvm.c |  649 ++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 623 insertions(+), 26 deletions(-)
> 
> diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
> index dcbbcc7..9dd1921 100644
> --- a/tools/perf/builtin-kvm.c
> +++ b/tools/perf/builtin-kvm.c
> @@ -2,6 +2,7 @@
>  #include "perf.h"
>  
>  #include "util/evsel.h"
> +#include "util/evlist.h"
>  #include "util/util.h"
>  #include "util/cache.h"
>  #include "util/symbol.h"
> @@ -15,9 +16,12 @@
>  #include "util/debugfs.h"
>  #include "util/tool.h"
>  #include "util/stat.h"
> +#include "util/top.h"
>  
>  #include <sys/prctl.h>
> +#include <sys/timerfd.h>
>  
> +#include <termios.h>
>  #include <semaphore.h>
>  #include <pthread.h>
>  #include <math.h>
> @@ -81,6 +85,8 @@ struct exit_reasons_table {
>  
>  struct perf_kvm {
>  	struct perf_tool    tool;
> +	struct perf_record_opts opts;
> +	struct perf_evlist  *evlist;
>  	struct perf_session *session;
>  
>  	const char *file_name;
> @@ -95,10 +101,16 @@ struct perf_kvm {
>  	struct kvm_events_ops *events_ops;
>  	key_cmp_fun compare;
>  	struct list_head kvm_events_cache[EVENTS_CACHE_SIZE];
> +
>  	u64 total_time;
>  	u64 total_count;
> +	u64 lost_events;
>  
>  	struct rb_root result;
> +
> +	int timerfd;
> +	unsigned int display_time;
> +	bool live;
>  };
>  
>  
> @@ -319,6 +331,23 @@ static void init_kvm_event_record(struct perf_kvm *kvm)
>  		INIT_LIST_HEAD(&kvm->kvm_events_cache[i]);
>  }
>  
> +static void clear_events_cache_stats(struct list_head *kvm_events_cache)
> +{
> +	struct list_head *head;
> +	struct kvm_event *event;
> +	unsigned int i;
> +
> +	for (i = 0; i < EVENTS_CACHE_SIZE; i++) {
> +		head = &kvm_events_cache[i];
> +		list_for_each_entry(event, head, hash_entry) {
> +			/* reset stats for event */
> +			memset(&event->total, 0, sizeof(event->total));
> +			memset(event->vcpu, 0,
> +			       event->max_vcpu * sizeof(*event->vcpu));
> +		}
> +	}
> +}
> +
>  static int kvm_events_hash_fn(u64 key)
>  {
>  	return key & (EVENTS_CACHE_SIZE - 1);
> @@ -471,7 +500,11 @@ static bool handle_end_event(struct perf_kvm *kvm,
>  	vcpu_record->last_event = NULL;
>  	vcpu_record->start_time = 0;
>  
> -	BUG_ON(timestamp < time_begin);
> +	/* seems to happen once in a while during live mode */
> +	if (timestamp < time_begin) {
> +		pr_debug("End time before begin time; skipping event.\n");
> +		return true;
> +	}
>  
>  	time_diff = timestamp - time_begin;
>  	return update_kvm_event(event, vcpu, time_diff);
> @@ -637,24 +670,60 @@ static struct kvm_event *pop_from_result(struct rb_root *result)
>  	return container_of(node, struct kvm_event, rb);
>  }
>  
> -static void print_vcpu_info(int vcpu)
> +static void print_vcpu_info(struct perf_kvm *kvm)
>  {
> +	int vcpu = kvm->trace_vcpu;
> +
>  	pr_info("Analyze events for ");
>  
> +	if (kvm->live) {
> +		if (kvm->opts.target.system_wide)
> +			pr_info("all VMs, ");
> +		else if (kvm->opts.target.pid)
> +			pr_info("pid(s) %s, ", kvm->opts.target.pid);
> +		else if (kvm->opts.target.tid)
> +			pr_info("tid(s) %s, ", kvm->opts.target.tid);
> +		else if (kvm->opts.target.cpu_list)
> +			pr_info("host cpu(s) %s, ", kvm->opts.target.cpu_list);
> +		else
> +			pr_info("dazed and confused on what is monitored, ");
> +	}
> +
>  	if (vcpu == -1)
>  		pr_info("all VCPUs:\n\n");
>  	else
>  		pr_info("VCPU %d:\n\n", vcpu);
>  }
>  
> +static void show_timeofday(void)
> +{
> +	char date[64];
> +	struct timeval tv;
> +	struct tm ltime;
> +
> +	gettimeofday(&tv, NULL);
> +	if (localtime_r(&tv.tv_sec, &ltime)) {
> +		strftime(date, sizeof(date), "%H:%M:%S", &ltime);
> +		pr_info("%s.%06ld", date, tv.tv_usec);
> +	} else
> +		pr_info("00:00:00.000000");
> +
> +	return;
> +}
> +
>  static void print_result(struct perf_kvm *kvm)
>  {
>  	char decode[20];
>  	struct kvm_event *event;
>  	int vcpu = kvm->trace_vcpu;
>  
> +	if (kvm->live) {
> +		puts(CONSOLE_CLEAR);
> +		show_timeofday();
> +	}
> +
>  	pr_info("\n\n");
> -	print_vcpu_info(vcpu);
> +	print_vcpu_info(kvm);
>  	pr_info("%20s ", kvm->events_ops->name);
>  	pr_info("%10s ", "Samples");
>  	pr_info("%9s ", "Samples%");
> @@ -681,6 +750,20 @@ static void print_result(struct perf_kvm *kvm)
>  
>  	pr_info("\nTotal Samples:%" PRIu64 ", Total events handled time:%.2fus.\n\n",
>  		kvm->total_count, kvm->total_time / 1e3);
> +
> +	if (kvm->lost_events)
> +		pr_info("\nLost events: %" PRIu64 "\n\n", kvm->lost_events);
> +}
> +
> +static int process_lost_event(struct perf_tool *tool,
> +			      union perf_event *event __maybe_unused,
> +			      struct perf_sample *sample __maybe_unused,
> +			      struct machine *machine __maybe_unused)
> +{
> +	struct perf_kvm *kvm = container_of(tool, struct perf_kvm, tool);
> +
> +	kvm->lost_events++;
> +	return 0;
>  }
>  
>  static int process_sample_event(struct perf_tool *tool,
> @@ -704,10 +787,20 @@ static int process_sample_event(struct perf_tool *tool,
>  	return 0;
>  }
>  
> -static int get_cpu_isa(struct perf_session *session)
> +static int cpu_isa_config(struct perf_kvm *kvm)
>  {
> -	char *cpuid = session->header.env.cpuid;
> -	int isa;
> +	char buf[64], *cpuid;
> +	int err, isa;
> +
> +	if (kvm->live) {
> +		err = get_cpuid(buf, sizeof(buf));
> +		if (err != 0) {
> +			pr_err("Failed to look up CPU type (Intel or AMD)\n");
> +			return err;
> +		}
> +		cpuid = buf;
> +	} else
> +		cpuid = kvm->session->header.env.cpuid;
>  
>  	if (strstr(cpuid, "Intel"))
>  		isa = 1;
> @@ -715,10 +808,374 @@ static int get_cpu_isa(struct perf_session *session)
>  		isa = 0;
>  	else {
>  		pr_err("CPU %s is not supported.\n", cpuid);
> -		isa = -ENOTSUP;
> +		return -ENOTSUP;
> +	}
> +
> +	if (isa == 1) {
> +		kvm->exit_reasons = vmx_exit_reasons;
> +		kvm->exit_reasons_size = ARRAY_SIZE(vmx_exit_reasons);
> +		kvm->exit_reasons_isa = "VMX";
> +	}
> +
> +	return 0;
> +}
> +
> +static bool verify_vcpu(int vcpu)
> +{
> +	if (vcpu != -1 && vcpu < 0) {
> +		pr_err("Invalid vcpu:%d.\n", vcpu);
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
> +#define PERF_KVM__MAX_EVENTS_PER_MMAP  1000
> +
> +static s64 perf_kvm__mmap_read_idx(struct perf_kvm *kvm, int idx)
> +{
> +	union perf_event *event;
> +	s64 n = 0;
> +	int err;
> +
> +	while ((event = perf_evlist__mmap_read(kvm->evlist, idx)) != NULL) {
> +		err = perf_session__process_event(kvm->session, event,
> +						  &kvm->tool, 0);
> +		if (err) {
> +			pr_err("Failed to process event\n");
> +			return err;
> +		}
> +		n++;
> +
> +		/* limit events per mmap handled all at once */
> +		if (n == PERF_KVM__MAX_EVENTS_PER_MMAP)
> +			break;
> +	}
> +
> +	return n;
> +}
> +
> +static int perf_kvm__mmap_read(struct perf_kvm *kvm)
> +{
> +	int i, err, throttled = 0;
> +	s64 n, ntotal = 0;
> +
> +	for (i = 0; i < kvm->evlist->nr_mmaps; i++) {
> +		n = perf_kvm__mmap_read_idx(kvm, i);
> +		if (n < 0)
> +			return -1;
> +		ntotal += n;
> +		if (n == PERF_KVM__MAX_EVENTS_PER_MMAP)
> +			throttled = 1;
> +	}
> +
> +	/* flush queue after each round in which we processed events */
> +	if (ntotal) {
> +		err = kvm->tool.finished_round(&kvm->tool, NULL, kvm->session);
> +		if (err) {
> +			if (kvm->lost_events)
> +				pr_info("\nLost events: %" PRIu64 "\n\n",
> +					kvm->lost_events);
> +			return err;
> +		}
> +	}
> +
> +	return throttled;
> +}
> +
> +static volatile int done;
> +
> +static void sig_handler(int sig)
> +{
> +	if (sig == SIGINT)
> +		done = 1;
> +}
> +
> +static int perf_kvm__timerfd_create(struct perf_kvm *kvm)
> +{
> +	struct itimerspec new_value;
> +	struct timespec now;
> +	int rc = -1;
> +
> +	kvm->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
> +	if (kvm->timerfd < 0) {
> +		pr_err("timerfd_create failed\n");
> +		goto out;
> +	}
> +
> +	if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) {
> +		pr_err("clock_gettime failed: %d\n", errno);
> +		close(kvm->timerfd);
> +		goto out;
> +	}
> +
> +	new_value.it_value.tv_sec = now.tv_sec + kvm->display_time;
> +	new_value.it_value.tv_nsec = now.tv_nsec;
> +	new_value.it_interval.tv_sec = kvm->display_time;
> +	new_value.it_interval.tv_nsec = 0;
> +
> +	if (timerfd_settime(kvm->timerfd, TFD_TIMER_ABSTIME,
> +			    &new_value, NULL) != 0) {
> +		pr_err("timerfd_settime failed: %d\n", errno);
> +		close(kvm->timerfd);
> +		goto out;
> +	}
> +
> +	rc = 0;
> +out:
> +	return rc;
> +}
> +
> +static int perf_kvm__handle_timerfd(struct perf_kvm *kvm)
> +{
> +	uint64_t c;
> +	int rc;
> +
> +	rc = read(kvm->timerfd, &c, sizeof(uint64_t));
> +	if (rc < 0) {
> +		if (errno == EAGAIN)
> +			return 0;
> +
> +		pr_err("Failed to read timer fd: %d\n", errno);
> +		return -1;
> +	}
> +
> +	if (rc != sizeof(uint64_t)) {
> +		pr_err("Error reading timer fd - invalid size returned\n");
> +		return -1;
> +	}
> +
> +	if (c != 1)
> +		pr_debug("Missed timer beats: %" PRIu64 "\n", c-1);
> +
> +	/* update display */
> +	sort_result(kvm);
> +	print_result(kvm);
> +
> +	/* reset counts */
> +	clear_events_cache_stats(kvm->kvm_events_cache);
> +	kvm->total_count = 0;
> +	kvm->total_time = 0;
> +	kvm->lost_events = 0;
> +
> +	return 0;
> +}
> +
> +static int fd_set_nonblock(int fd)
> +{
> +	long arg = 0;
> +
> +	arg = fcntl(fd, F_GETFL);
> +	if (arg < 0) {
> +		pr_err("Failed to get current flags for fd %d\n", fd);
> +		return -1;
> +	}
> +
> +	if (fcntl(fd, F_SETFL, arg | O_NONBLOCK) < 0) {
> +		pr_err("Failed to set non-block option on fd %d\n", fd);
> +		return -1;
>  	}
>  
> -	return isa;
> +	return 0;
> +}
> +
> +static
> +int perf_kvm__handle_stdin(struct termios *tc_now, struct termios *tc_save)
> +{
> +	int c;
> +
> +	tcsetattr(0, TCSANOW, tc_now);
> +	c = getc(stdin);
> +	tcsetattr(0, TCSAFLUSH, tc_save);
> +
> +	if (c == 'q')
> +		return 1;
> +
> +	/* TO-DO: add hook for 'd' to change display rate
> +	 *        needs an update to timerfd too
> +	 */
> +
> +	return 0;
> +}
> +
> +static int kvm_events_live_report(struct perf_kvm *kvm)
> +{
> +	struct pollfd *pollfds = NULL;
> +	int nr_fds, ret, err = -EINVAL;
> +	struct termios tc, save;
> +
> +	/* live flag must be set first */
> +	kvm->live = true;
> +
> +	ret = cpu_isa_config(kvm);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (!verify_vcpu(kvm->trace_vcpu) ||
> +	    !select_key(kvm) ||
> +	    !register_kvm_events_ops(kvm)) {
> +		goto out;
> +	}
> +
> +	init_kvm_event_record(kvm);
> +
> +
> +	tcgetattr(0, &save);
> +	tc = save;
> +	tc.c_lflag &= ~(ICANON | ECHO);
> +	tc.c_cc[VMIN] = 0;
> +	tc.c_cc[VTIME] = 0;
> +
> +	signal(SIGINT, sig_handler);
> +
> +
> +	/* copy pollfds -- need to add timerfd and stdin */
> +	nr_fds = kvm->evlist->nr_fds;
> +	pollfds = zalloc(sizeof(struct pollfd) * (nr_fds + 2));
> +	if (!pollfds) {
> +		err = -ENOMEM;
> +		goto out;
> +	}
> +	memcpy(pollfds, kvm->evlist->pollfd,
> +		sizeof(struct pollfd) * kvm->evlist->nr_fds);
> +
> +	/* add timer fd */
> +	if (perf_kvm__timerfd_create(kvm) < 0) {
> +		err = -1;
> +		goto out;
> +	}
> +
> +	pollfds[nr_fds].fd = kvm->timerfd;
> +	pollfds[nr_fds].events = POLLIN;
> +	nr_fds++;
> +
> +	pollfds[nr_fds].fd = fileno(stdin);
> +	pollfds[nr_fds].events = POLLIN;
> +	nr_fds++;
> +	if (fd_set_nonblock(fileno(stdin)) != 0)
> +		goto out;
> +
> +	/* everything is good - enable the events and process */
> +	perf_evlist__enable(kvm->evlist);
> +
> +	while (!done) {
> +		int rc;
> +
> +		rc = perf_kvm__mmap_read(kvm);
> +		if (rc < 0)
> +			break;
> +
> +		err = perf_kvm__handle_timerfd(kvm);
> +		if (err)
> +			goto out;
> +
> +		done = perf_kvm__handle_stdin(&tc, &save);
> +
> +		if (!rc && !done)
> +			err = poll(pollfds, nr_fds, 100);
> +	}
> +
> +	perf_evlist__disable(kvm->evlist);
> +
> +	if (err == 0) {
> +		sort_result(kvm);
> +		print_result(kvm);
> +	}
> +
> +out:
> +	if (kvm->timerfd >= 0)
> +		close(kvm->timerfd);
> +
> +	if (pollfds)
> +		free(pollfds);
> +
> +	return err;
> +}
> +
> +
> +/* TO-DO: how to merge this with perf-stat */
> +static int perf_kvm__open_counters(struct perf_kvm *kvm)
> +{
> +	struct perf_evsel *pos;
> +	struct perf_evlist *evlist = kvm->evlist;
> +	int err = 0;
> +
> +	/*
> +	 * Note: exclude_{guest,host} do not apply here.
> +	 *       This command processes KVM tracepoints form host only
> +	 */
> +	list_for_each_entry(pos, &evlist->entries, node) {
> +		struct perf_event_attr *attr = &pos->attr;
> +
> +		attr->sample_type = 0;
> +		attr->read_format = 0;
> +
> +		attr->sample_type |= PERF_SAMPLE_TID;
> +		attr->sample_type |= PERF_SAMPLE_TIME;
> +		attr->sample_type |= PERF_SAMPLE_CPU;
> +		attr->sample_type |= PERF_SAMPLE_RAW;
> +
> +		if (evlist->nr_entries > 1) {
> +			attr->sample_type |= PERF_SAMPLE_ID;
> +			attr->read_format |= PERF_FORMAT_ID;
> +		}
> +
> +		attr->sample_id_all = kvm->opts.sample_id_all_missing ? 0 : 1;
> +		attr->sample_period = 1;
> +		attr->comm = !pos->idx;
> +
> +		attr->watermark = 0;
> +		attr->wakeup_events = 100;
> +
> +		/* will enable all once we are ready */
> +		attr->disabled = 1;
> +
> +retry_sample_id:
> +		attr->sample_id_all = kvm->opts.sample_id_all_missing ? 0 : 1;
> +		if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
> +			err = errno;
> +
> +			if (err == EPERM || err == EACCES) {
> +				ui__error_paranoid();
> +				goto out_err;
> +			} else if ((err == EINVAL) &&
> +				   !kvm->opts.sample_id_all_missing) {
> +				/*
> +				 * Old kernel, no attr->sample_id_type_all field
> +				 */
> +				kvm->opts.sample_id_all_missing = true;
> +				goto retry_sample_id;
> +			}
> +
> +			/*
> +			 * should never happen since the event is validated
> +			 * before adding to evlist.
> +			 */
> +			if (err == ENOENT) {
> +				ui__error("The %s event is not supported.\n",
> +					  perf_evsel__name(pos));
> +				goto out_err;
> +			} else if (err == EMFILE) {
> +				ui__error("Too many events need to be opened.\n");
> +				goto out_err;
> +			}
> +
> +			ui__error("The sys_perf_event_open() syscall "
> +				  "returned with %d (%s).  /bin/dmesg "
> +				  "may provide additional information.\n",
> +				  err, strerror(err));
> +			goto out_err;
> +		}
> +	}
> +
> +	if (perf_evlist__mmap(evlist, kvm->opts.mmap_pages, false) < 0) {
> +		ui__error("Failed to mmap with %d (%s)\n",
> +			  errno, strerror(errno));
> +		goto out_err;
> +	}
> +
> +out_err:
> +	return err;
>  }
>  
>  static int read_events(struct perf_kvm *kvm)
> @@ -746,30 +1203,13 @@ static int read_events(struct perf_kvm *kvm)
>  	 * Do not use 'isa' recorded in kvm_exit tracepoint since it is not
>  	 * traced in the old kernel.
>  	 */
> -	ret = get_cpu_isa(kvm->session);
> -
> +	ret = cpu_isa_config(kvm);
>  	if (ret < 0)
>  		return ret;
>  
> -	if (ret == 1) {
> -		kvm->exit_reasons = vmx_exit_reasons;
> -		kvm->exit_reasons_size = ARRAY_SIZE(vmx_exit_reasons);
> -		kvm->exit_reasons_isa = "VMX";
> -	}
> -
>  	return perf_session__process_events(kvm->session, &kvm->tool);
>  }
>  
> -static bool verify_vcpu(int vcpu)
> -{
> -	if (vcpu != -1 && vcpu < 0) {
> -		pr_err("Invalid vcpu:%d.\n", vcpu);
> -		return false;
> -	}
> -
> -	return true;
> -}
> -
>  static int kvm_events_report_vcpu(struct perf_kvm *kvm)
>  {
>  	int ret = -EINVAL;
> @@ -881,6 +1321,159 @@ static int kvm_events_report(struct perf_kvm *kvm, int argc, const char **argv)
>  	return kvm_events_report_vcpu(kvm);
>  }
>  
> +static int kvm_events_live(struct perf_kvm *kvm, int argc, const char **argv)
> +{
> +	struct perf_session *session = NULL;
> +	char errbuf[BUFSIZ];
> +	int err;
> +	const struct option live_options[] = {
> +		OPT_STRING('p', "pid", &kvm->opts.target.pid, "pid",
> +			"record events on existing process id"),
> +		OPT_STRING('t', "tid", &kvm->opts.target.tid, "tid",
> +			"record events on existing thread id"),
> +		OPT_STRING('C', "cpu", &kvm->opts.target.cpu_list, "cpu",
> +			"list of host cpus to monitor"),
> +		OPT_UINTEGER('m', "mmap-pages", &kvm->opts.mmap_pages,
> +			"number of mmap data pages"),
> +		OPT_INCR('v', "verbose", &verbose,
> +			"be more verbose (show counter open errors, etc)"),
> +		OPT_BOOLEAN('a', "all-cpus", &kvm->opts.target.system_wide,
> +			"system-wide collection from all CPUs"),
> +		OPT_UINTEGER('d', "display", &kvm->display_time,
> +			"time in seconds between display updates"),
> +		OPT_STRING(0, "event", &kvm->report_event, "report event",
> +			"event for reporting: vmexit, mmio, ioport"),
> +		OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu,
> +			"vcpu id to report"),
> +		OPT_STRING('k', "key", &kvm->sort_key, "sort-key",
> +			"key for sorting: sample(sort by samples number)"
> +			" time (sort by avg time)"),
> +		OPT_END()
> +	};
> +	const char * const live_usage[] = {
> +		"perf kvm stat live [<options>]",
> +		NULL
> +	};
> +
> +
> +	/* event handling */
> +	kvm->tool.sample = process_sample_event;
> +	kvm->tool.comm   = perf_event__process_comm;
> +	kvm->tool.exit   = perf_event__process_exit;
> +	kvm->tool.fork   = perf_event__process_fork,
> +	kvm->tool.lost   = process_lost_event;
> +	kvm->tool.ordered_samples = true;
> +	perf_tool__fill_defaults(&kvm->tool);
> +
> +	/* set defaults */
> +	kvm->display_time = 1;
> +	kvm->opts.user_interval = 1;
> +	kvm->opts.mmap_pages = 512;
> +	kvm->opts.target.uses_mmap = true;
> +
> +	kvm->evlist = perf_evlist__new(NULL, NULL);
> +	if (kvm->evlist == NULL)
> +		return -ENOMEM;
> +
> +	symbol__init();
> +	disable_buildid_cache();
> +
> +	if (argc) {
> +		argc = parse_options(argc, argv, live_options,
> +				     live_usage, 0);
> +		if (argc)
> +			usage_with_options(live_usage, live_options);
> +	}
> +
> +	use_browser = 0;
> +	setup_browser(false);
> +
> +	/*
> +	 * target related setups
> +	 */
> +	if (perf_target__none(&kvm->opts.target))
> +		kvm->opts.target.system_wide = true;
> +
> +	err = perf_target__validate(&kvm->opts.target);
> +	if (err) {
> +		perf_target__strerror(&kvm->opts.target, err, errbuf, BUFSIZ);
> +		ui__warning("%s", errbuf);
> +	}
> +
> +	err = perf_target__parse_uid(&kvm->opts.target);
> +	if (err) {
> +		int saved_errno = errno;
> +
> +		perf_target__strerror(&kvm->opts.target, err,
> +				      errbuf, BUFSIZ);
> +		ui__error("%s", errbuf);
> +
> +		err = -saved_errno;
> +		goto out;
> +	}
> +
> +	/*
> +	 * generate the event list
> +	 */
> +	err = perf_evlist__add_tracepoints(kvm->evlist,
> +					   kvm_events_tp,
> +					   ARRAY_SIZE(kvm_events_tp));
> +	if (err != 0)
> +		goto out;
> +
> +	symbol_conf.nr_events = kvm->evlist->nr_entries;
> +
> +	if (perf_evlist__create_maps(kvm->evlist, &kvm->opts.target) < 0)
> +		usage_with_options(live_usage, live_options);
> +
> +	/*
> +	 * perf session
> +	 */
> +	session = perf_session__new(NULL, O_WRONLY, false, false, &kvm->tool);
> +	if (session == NULL) {
> +		err = -ENOMEM;
> +		goto out;
> +	}
> +	session->evlist = kvm->evlist;
> +	kvm->session = session;
> +	perf_session__set_id_hdr_size(session);
> +
> +
> +	/*
> +	 * need to get pevent initialized
> +	 */
> +	err = perf_evlist__trace_init(kvm->evlist, session);
> +	if (err != 0)
> +		goto out;
> +
> +	if (perf_target__has_task(&kvm->opts.target))
> +		perf_event__synthesize_thread_map(&kvm->tool,
> +						  kvm->evlist->threads,
> +						  perf_event__process,
> +						  &session->host_machine);
> +	else
> +		perf_event__synthesize_threads(&kvm->tool, perf_event__process,
> +					       &session->host_machine);
> +
> +
> +	err = perf_kvm__open_counters(kvm);
> +	if (err != 0)
> +		goto out;
> +
> +	err = kvm_events_live_report(kvm);
> +
> +out:
> +	exit_browser(0);
> +
> +	if (session)
> +		perf_session__delete(session);
> +	kvm->session = NULL;
> +	perf_evlist__delete_maps(kvm->evlist);
> +	perf_evlist__delete(kvm->evlist);
> +
> +	return err;
> +}
> +
>  static void print_kvm_stat_usage(void)
>  {
>  	printf("Usage: perf kvm stat <command>\n\n");
> @@ -888,6 +1481,7 @@ static void print_kvm_stat_usage(void)
>  	printf("# Available commands:\n");
>  	printf("\trecord: record kvm events\n");
>  	printf("\treport: report statistical data of kvm events\n");
> +	printf("\tlive:   live reporting of statistical data of kvm events\n");
>  
>  	printf("\nOtherwise, it is the alias of 'perf stat':\n");
>  }
> @@ -905,6 +1499,9 @@ static int kvm_cmd_stat(struct perf_kvm *kvm, int argc, const char **argv)
>  	if (!strncmp(argv[1], "rep", 3))
>  		return kvm_events_report(kvm, argc - 1 , argv + 1);
>  
> +	if (!strncmp(argv[1], "live", 4))
> +		return kvm_events_live(kvm, argc - 1 , argv + 1);
> +
>  perf_stat:
>  	return cmd_stat(argc, argv, NULL);
>  }
> -- 
> 1.7.10.1

  reply	other threads:[~2012-10-08 20:35 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-10-08 17:17 [PATCH 00/12] perf kvm: Add live mode for analyzing events David Ahern
2012-10-08 17:17 ` [PATCH 01/12] perf evlist: restore some methods removed in an earlier cleanup David Ahern
2012-10-08 17:17 ` [PATCH 02/12] perf evlist: move tracepoint processing code to evlist.c David Ahern
2012-10-08 17:17 ` [PATCH 03/12] perf evlist: add initialzation function for tracepoints David Ahern
2012-10-08 17:17 ` [PATCH 04/12] perf session: export a few functions for event processing David Ahern
2012-10-08 17:17 ` [PATCH 05/12] perf top: move CONSOLE_CLEAR to header file David Ahern
2012-10-08 17:17 ` [PATCH 06/12] perf kvm: remove typecast in init_kvm_event_record David Ahern
2012-10-09 17:38   ` [tip:perf/core] perf kvm: Remove " tip-bot for David Ahern
2012-10-08 17:17 ` [PATCH 07/12] perf kvm: handle realloc failures David Ahern
2012-10-08 20:19   ` Arnaldo Carvalho de Melo
2012-10-08 20:34     ` David Ahern
2012-10-08 21:38       ` Arnaldo Carvalho de Melo
2012-10-08 17:17 ` [PATCH 08/12] perf kvm: add braces around multi-line statements David Ahern
2012-10-09 17:40   ` [tip:perf/core] perf kvm: Add " tip-bot for David Ahern
2012-10-08 17:17 ` [PATCH 09/12] perf kvm: split out tracepoints from record args David Ahern
2012-10-17  8:19   ` Xiao Guangrong
2012-10-17 13:38     ` David Ahern
2012-10-08 17:17 ` [PATCH 10/12] perf kvm: total count is a u64, print as so David Ahern
2012-10-09 17:39   ` [tip:perf/core] perf kvm: Total " tip-bot for David Ahern
2012-10-08 17:17 ` [PATCH 11/12] perf kvm: only process events for vcpus of interest David Ahern
2012-10-09 17:37   ` [tip:perf/core] perf kvm: Only " tip-bot for David Ahern
2012-10-08 17:17 ` [PATCH 12/12] perf kvm: add live mode David Ahern
2012-10-08 20:35   ` Arnaldo Carvalho de Melo [this message]
2012-10-08 20:54     ` David Ahern
2012-10-08 21:44       ` Arnaldo Carvalho de Melo
2012-10-08 21:57         ` David Ahern

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20121008203534.GF2631@ghostprotocols.net \
    --to=acme@ghostprotocols.net \
    --cc=dsahern@gmail.com \
    --cc=fweisbec@gmail.com \
    --cc=haodong@linux.vnet.ibm.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@kernel.org \
    --cc=peterz@infradead.org \
    --cc=xiaoguangrong@linux.vnet.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.