18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include "builtin.h"
38c2ecf20Sopenharmony_ci#include "perf.h"
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include "util/build-id.h"
68c2ecf20Sopenharmony_ci#include "util/evsel.h"
78c2ecf20Sopenharmony_ci#include "util/evlist.h"
88c2ecf20Sopenharmony_ci#include "util/mmap.h"
98c2ecf20Sopenharmony_ci#include "util/term.h"
108c2ecf20Sopenharmony_ci#include "util/symbol.h"
118c2ecf20Sopenharmony_ci#include "util/thread.h"
128c2ecf20Sopenharmony_ci#include "util/header.h"
138c2ecf20Sopenharmony_ci#include "util/session.h"
148c2ecf20Sopenharmony_ci#include "util/intlist.h"
158c2ecf20Sopenharmony_ci#include <subcmd/pager.h>
168c2ecf20Sopenharmony_ci#include <subcmd/parse-options.h>
178c2ecf20Sopenharmony_ci#include "util/trace-event.h"
188c2ecf20Sopenharmony_ci#include "util/debug.h"
198c2ecf20Sopenharmony_ci#include "util/tool.h"
208c2ecf20Sopenharmony_ci#include "util/stat.h"
218c2ecf20Sopenharmony_ci#include "util/synthetic-events.h"
228c2ecf20Sopenharmony_ci#include "util/top.h"
238c2ecf20Sopenharmony_ci#include "util/data.h"
248c2ecf20Sopenharmony_ci#include "util/ordered-events.h"
258c2ecf20Sopenharmony_ci#include "util/kvm-stat.h"
268c2ecf20Sopenharmony_ci#include "ui/ui.h"
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include <sys/prctl.h>
298c2ecf20Sopenharmony_ci#ifdef HAVE_TIMERFD_SUPPORT
308c2ecf20Sopenharmony_ci#include <sys/timerfd.h>
318c2ecf20Sopenharmony_ci#endif
328c2ecf20Sopenharmony_ci#include <sys/time.h>
338c2ecf20Sopenharmony_ci#include <sys/types.h>
348c2ecf20Sopenharmony_ci#include <sys/stat.h>
358c2ecf20Sopenharmony_ci#include <fcntl.h>
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#include <linux/err.h>
388c2ecf20Sopenharmony_ci#include <linux/kernel.h>
398c2ecf20Sopenharmony_ci#include <linux/string.h>
408c2ecf20Sopenharmony_ci#include <linux/time64.h>
418c2ecf20Sopenharmony_ci#include <linux/zalloc.h>
428c2ecf20Sopenharmony_ci#include <errno.h>
438c2ecf20Sopenharmony_ci#include <inttypes.h>
448c2ecf20Sopenharmony_ci#include <poll.h>
458c2ecf20Sopenharmony_ci#include <termios.h>
468c2ecf20Sopenharmony_ci#include <semaphore.h>
478c2ecf20Sopenharmony_ci#include <signal.h>
488c2ecf20Sopenharmony_ci#include <math.h>
498c2ecf20Sopenharmony_ci#include <perf/mmap.h>
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic const char *get_filename_for_perf_kvm(void)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	const char *filename;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	if (perf_host && !perf_guest)
568c2ecf20Sopenharmony_ci		filename = strdup("perf.data.host");
578c2ecf20Sopenharmony_ci	else if (!perf_host && perf_guest)
588c2ecf20Sopenharmony_ci		filename = strdup("perf.data.guest");
598c2ecf20Sopenharmony_ci	else
608c2ecf20Sopenharmony_ci		filename = strdup("perf.data.kvm");
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	return filename;
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci#ifdef HAVE_KVM_STAT_SUPPORT
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_civoid exit_event_get_key(struct evsel *evsel,
688c2ecf20Sopenharmony_ci			struct perf_sample *sample,
698c2ecf20Sopenharmony_ci			struct event_key *key)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	key->info = 0;
728c2ecf20Sopenharmony_ci	key->key  = evsel__intval(evsel, sample, kvm_exit_reason);
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cibool kvm_exit_event(struct evsel *evsel)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	return !strcmp(evsel->name, kvm_exit_trace);
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cibool exit_event_begin(struct evsel *evsel,
818c2ecf20Sopenharmony_ci		      struct perf_sample *sample, struct event_key *key)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	if (kvm_exit_event(evsel)) {
848c2ecf20Sopenharmony_ci		exit_event_get_key(evsel, sample, key);
858c2ecf20Sopenharmony_ci		return true;
868c2ecf20Sopenharmony_ci	}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	return false;
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cibool kvm_entry_event(struct evsel *evsel)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	return !strcmp(evsel->name, kvm_entry_trace);
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cibool exit_event_end(struct evsel *evsel,
978c2ecf20Sopenharmony_ci		    struct perf_sample *sample __maybe_unused,
988c2ecf20Sopenharmony_ci		    struct event_key *key __maybe_unused)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	return kvm_entry_event(evsel);
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic const char *get_exit_reason(struct perf_kvm_stat *kvm,
1048c2ecf20Sopenharmony_ci				   struct exit_reasons_table *tbl,
1058c2ecf20Sopenharmony_ci				   u64 exit_code)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	while (tbl->reason != NULL) {
1088c2ecf20Sopenharmony_ci		if (tbl->exit_code == exit_code)
1098c2ecf20Sopenharmony_ci			return tbl->reason;
1108c2ecf20Sopenharmony_ci		tbl++;
1118c2ecf20Sopenharmony_ci	}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	pr_err("unknown kvm exit code:%lld on %s\n",
1148c2ecf20Sopenharmony_ci		(unsigned long long)exit_code, kvm->exit_reasons_isa);
1158c2ecf20Sopenharmony_ci	return "UNKNOWN";
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_civoid exit_event_decode_key(struct perf_kvm_stat *kvm,
1198c2ecf20Sopenharmony_ci			   struct event_key *key,
1208c2ecf20Sopenharmony_ci			   char *decode)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	const char *exit_reason = get_exit_reason(kvm, key->exit_reasons,
1238c2ecf20Sopenharmony_ci						  key->key);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	scnprintf(decode, decode_str_len, "%s", exit_reason);
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic bool register_kvm_events_ops(struct perf_kvm_stat *kvm)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	struct kvm_reg_events_ops *events_ops = kvm_reg_events_ops;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	for (events_ops = kvm_reg_events_ops; events_ops->name; events_ops++) {
1338c2ecf20Sopenharmony_ci		if (!strcmp(events_ops->name, kvm->report_event)) {
1348c2ecf20Sopenharmony_ci			kvm->events_ops = events_ops->ops;
1358c2ecf20Sopenharmony_ci			return true;
1368c2ecf20Sopenharmony_ci		}
1378c2ecf20Sopenharmony_ci	}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	return false;
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistruct vcpu_event_record {
1438c2ecf20Sopenharmony_ci	int vcpu_id;
1448c2ecf20Sopenharmony_ci	u64 start_time;
1458c2ecf20Sopenharmony_ci	struct kvm_event *last_event;
1468c2ecf20Sopenharmony_ci};
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic void init_kvm_event_record(struct perf_kvm_stat *kvm)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	unsigned int i;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	for (i = 0; i < EVENTS_CACHE_SIZE; i++)
1548c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&kvm->kvm_events_cache[i]);
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci#ifdef HAVE_TIMERFD_SUPPORT
1588c2ecf20Sopenharmony_cistatic void clear_events_cache_stats(struct list_head *kvm_events_cache)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	struct list_head *head;
1618c2ecf20Sopenharmony_ci	struct kvm_event *event;
1628c2ecf20Sopenharmony_ci	unsigned int i;
1638c2ecf20Sopenharmony_ci	int j;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	for (i = 0; i < EVENTS_CACHE_SIZE; i++) {
1668c2ecf20Sopenharmony_ci		head = &kvm_events_cache[i];
1678c2ecf20Sopenharmony_ci		list_for_each_entry(event, head, hash_entry) {
1688c2ecf20Sopenharmony_ci			/* reset stats for event */
1698c2ecf20Sopenharmony_ci			event->total.time = 0;
1708c2ecf20Sopenharmony_ci			init_stats(&event->total.stats);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci			for (j = 0; j < event->max_vcpu; ++j) {
1738c2ecf20Sopenharmony_ci				event->vcpu[j].time = 0;
1748c2ecf20Sopenharmony_ci				init_stats(&event->vcpu[j].stats);
1758c2ecf20Sopenharmony_ci			}
1768c2ecf20Sopenharmony_ci		}
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci#endif
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic int kvm_events_hash_fn(u64 key)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	return key & (EVENTS_CACHE_SIZE - 1);
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cistatic bool kvm_event_expand(struct kvm_event *event, int vcpu_id)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	int old_max_vcpu = event->max_vcpu;
1898c2ecf20Sopenharmony_ci	void *prev;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	if (vcpu_id < event->max_vcpu)
1928c2ecf20Sopenharmony_ci		return true;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	while (event->max_vcpu <= vcpu_id)
1958c2ecf20Sopenharmony_ci		event->max_vcpu += DEFAULT_VCPU_NUM;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	prev = event->vcpu;
1988c2ecf20Sopenharmony_ci	event->vcpu = realloc(event->vcpu,
1998c2ecf20Sopenharmony_ci			      event->max_vcpu * sizeof(*event->vcpu));
2008c2ecf20Sopenharmony_ci	if (!event->vcpu) {
2018c2ecf20Sopenharmony_ci		free(prev);
2028c2ecf20Sopenharmony_ci		pr_err("Not enough memory\n");
2038c2ecf20Sopenharmony_ci		return false;
2048c2ecf20Sopenharmony_ci	}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	memset(event->vcpu + old_max_vcpu, 0,
2078c2ecf20Sopenharmony_ci	       (event->max_vcpu - old_max_vcpu) * sizeof(*event->vcpu));
2088c2ecf20Sopenharmony_ci	return true;
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cistatic struct kvm_event *kvm_alloc_init_event(struct event_key *key)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	struct kvm_event *event;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	event = zalloc(sizeof(*event));
2168c2ecf20Sopenharmony_ci	if (!event) {
2178c2ecf20Sopenharmony_ci		pr_err("Not enough memory\n");
2188c2ecf20Sopenharmony_ci		return NULL;
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	event->key = *key;
2228c2ecf20Sopenharmony_ci	init_stats(&event->total.stats);
2238c2ecf20Sopenharmony_ci	return event;
2248c2ecf20Sopenharmony_ci}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_cistatic struct kvm_event *find_create_kvm_event(struct perf_kvm_stat *kvm,
2278c2ecf20Sopenharmony_ci					       struct event_key *key)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	struct kvm_event *event;
2308c2ecf20Sopenharmony_ci	struct list_head *head;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	BUG_ON(key->key == INVALID_KEY);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	head = &kvm->kvm_events_cache[kvm_events_hash_fn(key->key)];
2358c2ecf20Sopenharmony_ci	list_for_each_entry(event, head, hash_entry) {
2368c2ecf20Sopenharmony_ci		if (event->key.key == key->key && event->key.info == key->info)
2378c2ecf20Sopenharmony_ci			return event;
2388c2ecf20Sopenharmony_ci	}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	event = kvm_alloc_init_event(key);
2418c2ecf20Sopenharmony_ci	if (!event)
2428c2ecf20Sopenharmony_ci		return NULL;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	list_add(&event->hash_entry, head);
2458c2ecf20Sopenharmony_ci	return event;
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cistatic bool handle_begin_event(struct perf_kvm_stat *kvm,
2498c2ecf20Sopenharmony_ci			       struct vcpu_event_record *vcpu_record,
2508c2ecf20Sopenharmony_ci			       struct event_key *key, u64 timestamp)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	struct kvm_event *event = NULL;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	if (key->key != INVALID_KEY)
2558c2ecf20Sopenharmony_ci		event = find_create_kvm_event(kvm, key);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	vcpu_record->last_event = event;
2588c2ecf20Sopenharmony_ci	vcpu_record->start_time = timestamp;
2598c2ecf20Sopenharmony_ci	return true;
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_cistatic void
2638c2ecf20Sopenharmony_cikvm_update_event_stats(struct kvm_event_stats *kvm_stats, u64 time_diff)
2648c2ecf20Sopenharmony_ci{
2658c2ecf20Sopenharmony_ci	kvm_stats->time += time_diff;
2668c2ecf20Sopenharmony_ci	update_stats(&kvm_stats->stats, time_diff);
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_cistatic double kvm_event_rel_stddev(int vcpu_id, struct kvm_event *event)
2708c2ecf20Sopenharmony_ci{
2718c2ecf20Sopenharmony_ci	struct kvm_event_stats *kvm_stats = &event->total;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	if (vcpu_id != -1)
2748c2ecf20Sopenharmony_ci		kvm_stats = &event->vcpu[vcpu_id];
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	return rel_stddev_stats(stddev_stats(&kvm_stats->stats),
2778c2ecf20Sopenharmony_ci				avg_stats(&kvm_stats->stats));
2788c2ecf20Sopenharmony_ci}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_cistatic bool update_kvm_event(struct kvm_event *event, int vcpu_id,
2818c2ecf20Sopenharmony_ci			     u64 time_diff)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	if (vcpu_id == -1) {
2848c2ecf20Sopenharmony_ci		kvm_update_event_stats(&event->total, time_diff);
2858c2ecf20Sopenharmony_ci		return true;
2868c2ecf20Sopenharmony_ci	}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	if (!kvm_event_expand(event, vcpu_id))
2898c2ecf20Sopenharmony_ci		return false;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	kvm_update_event_stats(&event->vcpu[vcpu_id], time_diff);
2928c2ecf20Sopenharmony_ci	return true;
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_cistatic bool is_child_event(struct perf_kvm_stat *kvm,
2968c2ecf20Sopenharmony_ci			   struct evsel *evsel,
2978c2ecf20Sopenharmony_ci			   struct perf_sample *sample,
2988c2ecf20Sopenharmony_ci			   struct event_key *key)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci	struct child_event_ops *child_ops;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	child_ops = kvm->events_ops->child_ops;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	if (!child_ops)
3058c2ecf20Sopenharmony_ci		return false;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	for (; child_ops->name; child_ops++) {
3088c2ecf20Sopenharmony_ci		if (!strcmp(evsel->name, child_ops->name)) {
3098c2ecf20Sopenharmony_ci			child_ops->get_key(evsel, sample, key);
3108c2ecf20Sopenharmony_ci			return true;
3118c2ecf20Sopenharmony_ci		}
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	return false;
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_cistatic bool handle_child_event(struct perf_kvm_stat *kvm,
3188c2ecf20Sopenharmony_ci			       struct vcpu_event_record *vcpu_record,
3198c2ecf20Sopenharmony_ci			       struct event_key *key,
3208c2ecf20Sopenharmony_ci			       struct perf_sample *sample __maybe_unused)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	struct kvm_event *event = NULL;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	if (key->key != INVALID_KEY)
3258c2ecf20Sopenharmony_ci		event = find_create_kvm_event(kvm, key);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	vcpu_record->last_event = event;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	return true;
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_cistatic bool skip_event(const char *event)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	const char * const *skip_events;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	for (skip_events = kvm_skip_events; *skip_events; skip_events++)
3378c2ecf20Sopenharmony_ci		if (!strcmp(event, *skip_events))
3388c2ecf20Sopenharmony_ci			return true;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	return false;
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic bool handle_end_event(struct perf_kvm_stat *kvm,
3448c2ecf20Sopenharmony_ci			     struct vcpu_event_record *vcpu_record,
3458c2ecf20Sopenharmony_ci			     struct event_key *key,
3468c2ecf20Sopenharmony_ci			     struct perf_sample *sample)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	struct kvm_event *event;
3498c2ecf20Sopenharmony_ci	u64 time_begin, time_diff;
3508c2ecf20Sopenharmony_ci	int vcpu;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	if (kvm->trace_vcpu == -1)
3538c2ecf20Sopenharmony_ci		vcpu = -1;
3548c2ecf20Sopenharmony_ci	else
3558c2ecf20Sopenharmony_ci		vcpu = vcpu_record->vcpu_id;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	event = vcpu_record->last_event;
3588c2ecf20Sopenharmony_ci	time_begin = vcpu_record->start_time;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	/* The begin event is not caught. */
3618c2ecf20Sopenharmony_ci	if (!time_begin)
3628c2ecf20Sopenharmony_ci		return true;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	/*
3658c2ecf20Sopenharmony_ci	 * In some case, the 'begin event' only records the start timestamp,
3668c2ecf20Sopenharmony_ci	 * the actual event is recognized in the 'end event' (e.g. mmio-event).
3678c2ecf20Sopenharmony_ci	 */
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	/* Both begin and end events did not get the key. */
3708c2ecf20Sopenharmony_ci	if (!event && key->key == INVALID_KEY)
3718c2ecf20Sopenharmony_ci		return true;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	if (!event)
3748c2ecf20Sopenharmony_ci		event = find_create_kvm_event(kvm, key);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	if (!event)
3778c2ecf20Sopenharmony_ci		return false;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	vcpu_record->last_event = NULL;
3808c2ecf20Sopenharmony_ci	vcpu_record->start_time = 0;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	/* seems to happen once in a while during live mode */
3838c2ecf20Sopenharmony_ci	if (sample->time < time_begin) {
3848c2ecf20Sopenharmony_ci		pr_debug("End time before begin time; skipping event.\n");
3858c2ecf20Sopenharmony_ci		return true;
3868c2ecf20Sopenharmony_ci	}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	time_diff = sample->time - time_begin;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	if (kvm->duration && time_diff > kvm->duration) {
3918c2ecf20Sopenharmony_ci		char decode[decode_str_len];
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci		kvm->events_ops->decode_key(kvm, &event->key, decode);
3948c2ecf20Sopenharmony_ci		if (!skip_event(decode)) {
3958c2ecf20Sopenharmony_ci			pr_info("%" PRIu64 " VM %d, vcpu %d: %s event took %" PRIu64 "usec\n",
3968c2ecf20Sopenharmony_ci				 sample->time, sample->pid, vcpu_record->vcpu_id,
3978c2ecf20Sopenharmony_ci				 decode, time_diff / NSEC_PER_USEC);
3988c2ecf20Sopenharmony_ci		}
3998c2ecf20Sopenharmony_ci	}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	return update_kvm_event(event, vcpu, time_diff);
4028c2ecf20Sopenharmony_ci}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_cistatic
4058c2ecf20Sopenharmony_cistruct vcpu_event_record *per_vcpu_record(struct thread *thread,
4068c2ecf20Sopenharmony_ci					  struct evsel *evsel,
4078c2ecf20Sopenharmony_ci					  struct perf_sample *sample)
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci	/* Only kvm_entry records vcpu id. */
4108c2ecf20Sopenharmony_ci	if (!thread__priv(thread) && kvm_entry_event(evsel)) {
4118c2ecf20Sopenharmony_ci		struct vcpu_event_record *vcpu_record;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci		vcpu_record = zalloc(sizeof(*vcpu_record));
4148c2ecf20Sopenharmony_ci		if (!vcpu_record) {
4158c2ecf20Sopenharmony_ci			pr_err("%s: Not enough memory\n", __func__);
4168c2ecf20Sopenharmony_ci			return NULL;
4178c2ecf20Sopenharmony_ci		}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci		vcpu_record->vcpu_id = evsel__intval(evsel, sample, vcpu_id_str);
4208c2ecf20Sopenharmony_ci		thread__set_priv(thread, vcpu_record);
4218c2ecf20Sopenharmony_ci	}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	return thread__priv(thread);
4248c2ecf20Sopenharmony_ci}
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_cistatic bool handle_kvm_event(struct perf_kvm_stat *kvm,
4278c2ecf20Sopenharmony_ci			     struct thread *thread,
4288c2ecf20Sopenharmony_ci			     struct evsel *evsel,
4298c2ecf20Sopenharmony_ci			     struct perf_sample *sample)
4308c2ecf20Sopenharmony_ci{
4318c2ecf20Sopenharmony_ci	struct vcpu_event_record *vcpu_record;
4328c2ecf20Sopenharmony_ci	struct event_key key = { .key = INVALID_KEY,
4338c2ecf20Sopenharmony_ci				 .exit_reasons = kvm->exit_reasons };
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	vcpu_record = per_vcpu_record(thread, evsel, sample);
4368c2ecf20Sopenharmony_ci	if (!vcpu_record)
4378c2ecf20Sopenharmony_ci		return true;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	/* only process events for vcpus user cares about */
4408c2ecf20Sopenharmony_ci	if ((kvm->trace_vcpu != -1) &&
4418c2ecf20Sopenharmony_ci	    (kvm->trace_vcpu != vcpu_record->vcpu_id))
4428c2ecf20Sopenharmony_ci		return true;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	if (kvm->events_ops->is_begin_event(evsel, sample, &key))
4458c2ecf20Sopenharmony_ci		return handle_begin_event(kvm, vcpu_record, &key, sample->time);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	if (is_child_event(kvm, evsel, sample, &key))
4488c2ecf20Sopenharmony_ci		return handle_child_event(kvm, vcpu_record, &key, sample);
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	if (kvm->events_ops->is_end_event(evsel, sample, &key))
4518c2ecf20Sopenharmony_ci		return handle_end_event(kvm, vcpu_record, &key, sample);
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	return true;
4548c2ecf20Sopenharmony_ci}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci#define GET_EVENT_KEY(func, field)					\
4578c2ecf20Sopenharmony_cistatic u64 get_event_ ##func(struct kvm_event *event, int vcpu)		\
4588c2ecf20Sopenharmony_ci{									\
4598c2ecf20Sopenharmony_ci	if (vcpu == -1)							\
4608c2ecf20Sopenharmony_ci		return event->total.field;				\
4618c2ecf20Sopenharmony_ci									\
4628c2ecf20Sopenharmony_ci	if (vcpu >= event->max_vcpu)					\
4638c2ecf20Sopenharmony_ci		return 0;						\
4648c2ecf20Sopenharmony_ci									\
4658c2ecf20Sopenharmony_ci	return event->vcpu[vcpu].field;					\
4668c2ecf20Sopenharmony_ci}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci#define COMPARE_EVENT_KEY(func, field)					\
4698c2ecf20Sopenharmony_ciGET_EVENT_KEY(func, field)						\
4708c2ecf20Sopenharmony_cistatic int compare_kvm_event_ ## func(struct kvm_event *one,		\
4718c2ecf20Sopenharmony_ci					struct kvm_event *two, int vcpu)\
4728c2ecf20Sopenharmony_ci{									\
4738c2ecf20Sopenharmony_ci	return get_event_ ##func(one, vcpu) >				\
4748c2ecf20Sopenharmony_ci				get_event_ ##func(two, vcpu);		\
4758c2ecf20Sopenharmony_ci}
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ciGET_EVENT_KEY(time, time);
4788c2ecf20Sopenharmony_ciCOMPARE_EVENT_KEY(count, stats.n);
4798c2ecf20Sopenharmony_ciCOMPARE_EVENT_KEY(mean, stats.mean);
4808c2ecf20Sopenharmony_ciGET_EVENT_KEY(max, stats.max);
4818c2ecf20Sopenharmony_ciGET_EVENT_KEY(min, stats.min);
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci#define DEF_SORT_NAME_KEY(name, compare_key)				\
4848c2ecf20Sopenharmony_ci	{ #name, compare_kvm_event_ ## compare_key }
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_cistatic struct kvm_event_key keys[] = {
4878c2ecf20Sopenharmony_ci	DEF_SORT_NAME_KEY(sample, count),
4888c2ecf20Sopenharmony_ci	DEF_SORT_NAME_KEY(time, mean),
4898c2ecf20Sopenharmony_ci	{ NULL, NULL }
4908c2ecf20Sopenharmony_ci};
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_cistatic bool select_key(struct perf_kvm_stat *kvm)
4938c2ecf20Sopenharmony_ci{
4948c2ecf20Sopenharmony_ci	int i;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	for (i = 0; keys[i].name; i++) {
4978c2ecf20Sopenharmony_ci		if (!strcmp(keys[i].name, kvm->sort_key)) {
4988c2ecf20Sopenharmony_ci			kvm->compare = keys[i].key;
4998c2ecf20Sopenharmony_ci			return true;
5008c2ecf20Sopenharmony_ci		}
5018c2ecf20Sopenharmony_ci	}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	pr_err("Unknown compare key:%s\n", kvm->sort_key);
5048c2ecf20Sopenharmony_ci	return false;
5058c2ecf20Sopenharmony_ci}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_cistatic void insert_to_result(struct rb_root *result, struct kvm_event *event,
5088c2ecf20Sopenharmony_ci			     key_cmp_fun bigger, int vcpu)
5098c2ecf20Sopenharmony_ci{
5108c2ecf20Sopenharmony_ci	struct rb_node **rb = &result->rb_node;
5118c2ecf20Sopenharmony_ci	struct rb_node *parent = NULL;
5128c2ecf20Sopenharmony_ci	struct kvm_event *p;
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	while (*rb) {
5158c2ecf20Sopenharmony_ci		p = container_of(*rb, struct kvm_event, rb);
5168c2ecf20Sopenharmony_ci		parent = *rb;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci		if (bigger(event, p, vcpu))
5198c2ecf20Sopenharmony_ci			rb = &(*rb)->rb_left;
5208c2ecf20Sopenharmony_ci		else
5218c2ecf20Sopenharmony_ci			rb = &(*rb)->rb_right;
5228c2ecf20Sopenharmony_ci	}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	rb_link_node(&event->rb, parent, rb);
5258c2ecf20Sopenharmony_ci	rb_insert_color(&event->rb, result);
5268c2ecf20Sopenharmony_ci}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_cistatic void
5298c2ecf20Sopenharmony_ciupdate_total_count(struct perf_kvm_stat *kvm, struct kvm_event *event)
5308c2ecf20Sopenharmony_ci{
5318c2ecf20Sopenharmony_ci	int vcpu = kvm->trace_vcpu;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	kvm->total_count += get_event_count(event, vcpu);
5348c2ecf20Sopenharmony_ci	kvm->total_time += get_event_time(event, vcpu);
5358c2ecf20Sopenharmony_ci}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_cistatic bool event_is_valid(struct kvm_event *event, int vcpu)
5388c2ecf20Sopenharmony_ci{
5398c2ecf20Sopenharmony_ci	return !!get_event_count(event, vcpu);
5408c2ecf20Sopenharmony_ci}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_cistatic void sort_result(struct perf_kvm_stat *kvm)
5438c2ecf20Sopenharmony_ci{
5448c2ecf20Sopenharmony_ci	unsigned int i;
5458c2ecf20Sopenharmony_ci	int vcpu = kvm->trace_vcpu;
5468c2ecf20Sopenharmony_ci	struct kvm_event *event;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	for (i = 0; i < EVENTS_CACHE_SIZE; i++) {
5498c2ecf20Sopenharmony_ci		list_for_each_entry(event, &kvm->kvm_events_cache[i], hash_entry) {
5508c2ecf20Sopenharmony_ci			if (event_is_valid(event, vcpu)) {
5518c2ecf20Sopenharmony_ci				update_total_count(kvm, event);
5528c2ecf20Sopenharmony_ci				insert_to_result(&kvm->result, event,
5538c2ecf20Sopenharmony_ci						 kvm->compare, vcpu);
5548c2ecf20Sopenharmony_ci			}
5558c2ecf20Sopenharmony_ci		}
5568c2ecf20Sopenharmony_ci	}
5578c2ecf20Sopenharmony_ci}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci/* returns left most element of result, and erase it */
5608c2ecf20Sopenharmony_cistatic struct kvm_event *pop_from_result(struct rb_root *result)
5618c2ecf20Sopenharmony_ci{
5628c2ecf20Sopenharmony_ci	struct rb_node *node = rb_first(result);
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	if (!node)
5658c2ecf20Sopenharmony_ci		return NULL;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	rb_erase(node, result);
5688c2ecf20Sopenharmony_ci	return container_of(node, struct kvm_event, rb);
5698c2ecf20Sopenharmony_ci}
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_cistatic void print_vcpu_info(struct perf_kvm_stat *kvm)
5728c2ecf20Sopenharmony_ci{
5738c2ecf20Sopenharmony_ci	int vcpu = kvm->trace_vcpu;
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	pr_info("Analyze events for ");
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	if (kvm->opts.target.system_wide)
5788c2ecf20Sopenharmony_ci		pr_info("all VMs, ");
5798c2ecf20Sopenharmony_ci	else if (kvm->opts.target.pid)
5808c2ecf20Sopenharmony_ci		pr_info("pid(s) %s, ", kvm->opts.target.pid);
5818c2ecf20Sopenharmony_ci	else
5828c2ecf20Sopenharmony_ci		pr_info("dazed and confused on what is monitored, ");
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	if (vcpu == -1)
5858c2ecf20Sopenharmony_ci		pr_info("all VCPUs:\n\n");
5868c2ecf20Sopenharmony_ci	else
5878c2ecf20Sopenharmony_ci		pr_info("VCPU %d:\n\n", vcpu);
5888c2ecf20Sopenharmony_ci}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_cistatic void show_timeofday(void)
5918c2ecf20Sopenharmony_ci{
5928c2ecf20Sopenharmony_ci	char date[64];
5938c2ecf20Sopenharmony_ci	struct timeval tv;
5948c2ecf20Sopenharmony_ci	struct tm ltime;
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	gettimeofday(&tv, NULL);
5978c2ecf20Sopenharmony_ci	if (localtime_r(&tv.tv_sec, &ltime)) {
5988c2ecf20Sopenharmony_ci		strftime(date, sizeof(date), "%H:%M:%S", &ltime);
5998c2ecf20Sopenharmony_ci		pr_info("%s.%06ld", date, tv.tv_usec);
6008c2ecf20Sopenharmony_ci	} else
6018c2ecf20Sopenharmony_ci		pr_info("00:00:00.000000");
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	return;
6048c2ecf20Sopenharmony_ci}
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_cistatic void print_result(struct perf_kvm_stat *kvm)
6078c2ecf20Sopenharmony_ci{
6088c2ecf20Sopenharmony_ci	char decode[decode_str_len];
6098c2ecf20Sopenharmony_ci	struct kvm_event *event;
6108c2ecf20Sopenharmony_ci	int vcpu = kvm->trace_vcpu;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	if (kvm->live) {
6138c2ecf20Sopenharmony_ci		puts(CONSOLE_CLEAR);
6148c2ecf20Sopenharmony_ci		show_timeofday();
6158c2ecf20Sopenharmony_ci	}
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	pr_info("\n\n");
6188c2ecf20Sopenharmony_ci	print_vcpu_info(kvm);
6198c2ecf20Sopenharmony_ci	pr_info("%*s ", decode_str_len, kvm->events_ops->name);
6208c2ecf20Sopenharmony_ci	pr_info("%10s ", "Samples");
6218c2ecf20Sopenharmony_ci	pr_info("%9s ", "Samples%");
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	pr_info("%9s ", "Time%");
6248c2ecf20Sopenharmony_ci	pr_info("%11s ", "Min Time");
6258c2ecf20Sopenharmony_ci	pr_info("%11s ", "Max Time");
6268c2ecf20Sopenharmony_ci	pr_info("%16s ", "Avg time");
6278c2ecf20Sopenharmony_ci	pr_info("\n\n");
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	while ((event = pop_from_result(&kvm->result))) {
6308c2ecf20Sopenharmony_ci		u64 ecount, etime, max, min;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci		ecount = get_event_count(event, vcpu);
6338c2ecf20Sopenharmony_ci		etime = get_event_time(event, vcpu);
6348c2ecf20Sopenharmony_ci		max = get_event_max(event, vcpu);
6358c2ecf20Sopenharmony_ci		min = get_event_min(event, vcpu);
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci		kvm->events_ops->decode_key(kvm, &event->key, decode);
6388c2ecf20Sopenharmony_ci		pr_info("%*s ", decode_str_len, decode);
6398c2ecf20Sopenharmony_ci		pr_info("%10llu ", (unsigned long long)ecount);
6408c2ecf20Sopenharmony_ci		pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100);
6418c2ecf20Sopenharmony_ci		pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100);
6428c2ecf20Sopenharmony_ci		pr_info("%9.2fus ", (double)min / NSEC_PER_USEC);
6438c2ecf20Sopenharmony_ci		pr_info("%9.2fus ", (double)max / NSEC_PER_USEC);
6448c2ecf20Sopenharmony_ci		pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount / NSEC_PER_USEC,
6458c2ecf20Sopenharmony_ci			kvm_event_rel_stddev(vcpu, event));
6468c2ecf20Sopenharmony_ci		pr_info("\n");
6478c2ecf20Sopenharmony_ci	}
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	pr_info("\nTotal Samples:%" PRIu64 ", Total events handled time:%.2fus.\n\n",
6508c2ecf20Sopenharmony_ci		kvm->total_count, kvm->total_time / (double)NSEC_PER_USEC);
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	if (kvm->lost_events)
6538c2ecf20Sopenharmony_ci		pr_info("\nLost events: %" PRIu64 "\n\n", kvm->lost_events);
6548c2ecf20Sopenharmony_ci}
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci#ifdef HAVE_TIMERFD_SUPPORT
6578c2ecf20Sopenharmony_cistatic int process_lost_event(struct perf_tool *tool,
6588c2ecf20Sopenharmony_ci			      union perf_event *event __maybe_unused,
6598c2ecf20Sopenharmony_ci			      struct perf_sample *sample __maybe_unused,
6608c2ecf20Sopenharmony_ci			      struct machine *machine __maybe_unused)
6618c2ecf20Sopenharmony_ci{
6628c2ecf20Sopenharmony_ci	struct perf_kvm_stat *kvm = container_of(tool, struct perf_kvm_stat, tool);
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	kvm->lost_events++;
6658c2ecf20Sopenharmony_ci	return 0;
6668c2ecf20Sopenharmony_ci}
6678c2ecf20Sopenharmony_ci#endif
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_cistatic bool skip_sample(struct perf_kvm_stat *kvm,
6708c2ecf20Sopenharmony_ci			struct perf_sample *sample)
6718c2ecf20Sopenharmony_ci{
6728c2ecf20Sopenharmony_ci	if (kvm->pid_list && intlist__find(kvm->pid_list, sample->pid) == NULL)
6738c2ecf20Sopenharmony_ci		return true;
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	return false;
6768c2ecf20Sopenharmony_ci}
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_cistatic int process_sample_event(struct perf_tool *tool,
6798c2ecf20Sopenharmony_ci				union perf_event *event,
6808c2ecf20Sopenharmony_ci				struct perf_sample *sample,
6818c2ecf20Sopenharmony_ci				struct evsel *evsel,
6828c2ecf20Sopenharmony_ci				struct machine *machine)
6838c2ecf20Sopenharmony_ci{
6848c2ecf20Sopenharmony_ci	int err = 0;
6858c2ecf20Sopenharmony_ci	struct thread *thread;
6868c2ecf20Sopenharmony_ci	struct perf_kvm_stat *kvm = container_of(tool, struct perf_kvm_stat,
6878c2ecf20Sopenharmony_ci						 tool);
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	if (skip_sample(kvm, sample))
6908c2ecf20Sopenharmony_ci		return 0;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	thread = machine__findnew_thread(machine, sample->pid, sample->tid);
6938c2ecf20Sopenharmony_ci	if (thread == NULL) {
6948c2ecf20Sopenharmony_ci		pr_debug("problem processing %d event, skipping it.\n",
6958c2ecf20Sopenharmony_ci			event->header.type);
6968c2ecf20Sopenharmony_ci		return -1;
6978c2ecf20Sopenharmony_ci	}
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	if (!handle_kvm_event(kvm, thread, evsel, sample))
7008c2ecf20Sopenharmony_ci		err = -1;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	thread__put(thread);
7038c2ecf20Sopenharmony_ci	return err;
7048c2ecf20Sopenharmony_ci}
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_cistatic int cpu_isa_config(struct perf_kvm_stat *kvm)
7078c2ecf20Sopenharmony_ci{
7088c2ecf20Sopenharmony_ci	char buf[128], *cpuid;
7098c2ecf20Sopenharmony_ci	int err;
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	if (kvm->live) {
7128c2ecf20Sopenharmony_ci		err = get_cpuid(buf, sizeof(buf));
7138c2ecf20Sopenharmony_ci		if (err != 0) {
7148c2ecf20Sopenharmony_ci			pr_err("Failed to look up CPU type: %s\n",
7158c2ecf20Sopenharmony_ci			       str_error_r(err, buf, sizeof(buf)));
7168c2ecf20Sopenharmony_ci			return -err;
7178c2ecf20Sopenharmony_ci		}
7188c2ecf20Sopenharmony_ci		cpuid = buf;
7198c2ecf20Sopenharmony_ci	} else
7208c2ecf20Sopenharmony_ci		cpuid = kvm->session->header.env.cpuid;
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	if (!cpuid) {
7238c2ecf20Sopenharmony_ci		pr_err("Failed to look up CPU type\n");
7248c2ecf20Sopenharmony_ci		return -EINVAL;
7258c2ecf20Sopenharmony_ci	}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	err = cpu_isa_init(kvm, cpuid);
7288c2ecf20Sopenharmony_ci	if (err == -ENOTSUP)
7298c2ecf20Sopenharmony_ci		pr_err("CPU %s is not supported.\n", cpuid);
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	return err;
7328c2ecf20Sopenharmony_ci}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_cistatic bool verify_vcpu(int vcpu)
7358c2ecf20Sopenharmony_ci{
7368c2ecf20Sopenharmony_ci	if (vcpu != -1 && vcpu < 0) {
7378c2ecf20Sopenharmony_ci		pr_err("Invalid vcpu:%d.\n", vcpu);
7388c2ecf20Sopenharmony_ci		return false;
7398c2ecf20Sopenharmony_ci	}
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	return true;
7428c2ecf20Sopenharmony_ci}
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci#ifdef HAVE_TIMERFD_SUPPORT
7458c2ecf20Sopenharmony_ci/* keeping the max events to a modest level to keep
7468c2ecf20Sopenharmony_ci * the processing of samples per mmap smooth.
7478c2ecf20Sopenharmony_ci */
7488c2ecf20Sopenharmony_ci#define PERF_KVM__MAX_EVENTS_PER_MMAP  25
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_cistatic s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx,
7518c2ecf20Sopenharmony_ci				   u64 *mmap_time)
7528c2ecf20Sopenharmony_ci{
7538c2ecf20Sopenharmony_ci	struct evlist *evlist = kvm->evlist;
7548c2ecf20Sopenharmony_ci	union perf_event *event;
7558c2ecf20Sopenharmony_ci	struct mmap *md;
7568c2ecf20Sopenharmony_ci	u64 timestamp;
7578c2ecf20Sopenharmony_ci	s64 n = 0;
7588c2ecf20Sopenharmony_ci	int err;
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	*mmap_time = ULLONG_MAX;
7618c2ecf20Sopenharmony_ci	md = &evlist->mmap[idx];
7628c2ecf20Sopenharmony_ci	err = perf_mmap__read_init(&md->core);
7638c2ecf20Sopenharmony_ci	if (err < 0)
7648c2ecf20Sopenharmony_ci		return (err == -EAGAIN) ? 0 : -1;
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	while ((event = perf_mmap__read_event(&md->core)) != NULL) {
7678c2ecf20Sopenharmony_ci		err = perf_evlist__parse_sample_timestamp(evlist, event, &timestamp);
7688c2ecf20Sopenharmony_ci		if (err) {
7698c2ecf20Sopenharmony_ci			perf_mmap__consume(&md->core);
7708c2ecf20Sopenharmony_ci			pr_err("Failed to parse sample\n");
7718c2ecf20Sopenharmony_ci			return -1;
7728c2ecf20Sopenharmony_ci		}
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci		err = perf_session__queue_event(kvm->session, event, timestamp, 0);
7758c2ecf20Sopenharmony_ci		/*
7768c2ecf20Sopenharmony_ci		 * FIXME: Here we can't consume the event, as perf_session__queue_event will
7778c2ecf20Sopenharmony_ci		 *        point to it, and it'll get possibly overwritten by the kernel.
7788c2ecf20Sopenharmony_ci		 */
7798c2ecf20Sopenharmony_ci		perf_mmap__consume(&md->core);
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci		if (err) {
7828c2ecf20Sopenharmony_ci			pr_err("Failed to enqueue sample: %d\n", err);
7838c2ecf20Sopenharmony_ci			return -1;
7848c2ecf20Sopenharmony_ci		}
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci		/* save time stamp of our first sample for this mmap */
7878c2ecf20Sopenharmony_ci		if (n == 0)
7888c2ecf20Sopenharmony_ci			*mmap_time = timestamp;
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci		/* limit events per mmap handled all at once */
7918c2ecf20Sopenharmony_ci		n++;
7928c2ecf20Sopenharmony_ci		if (n == PERF_KVM__MAX_EVENTS_PER_MMAP)
7938c2ecf20Sopenharmony_ci			break;
7948c2ecf20Sopenharmony_ci	}
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	perf_mmap__read_done(&md->core);
7978c2ecf20Sopenharmony_ci	return n;
7988c2ecf20Sopenharmony_ci}
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_cistatic int perf_kvm__mmap_read(struct perf_kvm_stat *kvm)
8018c2ecf20Sopenharmony_ci{
8028c2ecf20Sopenharmony_ci	int i, err, throttled = 0;
8038c2ecf20Sopenharmony_ci	s64 n, ntotal = 0;
8048c2ecf20Sopenharmony_ci	u64 flush_time = ULLONG_MAX, mmap_time;
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	for (i = 0; i < kvm->evlist->core.nr_mmaps; i++) {
8078c2ecf20Sopenharmony_ci		n = perf_kvm__mmap_read_idx(kvm, i, &mmap_time);
8088c2ecf20Sopenharmony_ci		if (n < 0)
8098c2ecf20Sopenharmony_ci			return -1;
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci		/* flush time is going to be the minimum of all the individual
8128c2ecf20Sopenharmony_ci		 * mmap times. Essentially, we flush all the samples queued up
8138c2ecf20Sopenharmony_ci		 * from the last pass under our minimal start time -- that leaves
8148c2ecf20Sopenharmony_ci		 * a very small race for samples to come in with a lower timestamp.
8158c2ecf20Sopenharmony_ci		 * The ioctl to return the perf_clock timestamp should close the
8168c2ecf20Sopenharmony_ci		 * race entirely.
8178c2ecf20Sopenharmony_ci		 */
8188c2ecf20Sopenharmony_ci		if (mmap_time < flush_time)
8198c2ecf20Sopenharmony_ci			flush_time = mmap_time;
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci		ntotal += n;
8228c2ecf20Sopenharmony_ci		if (n == PERF_KVM__MAX_EVENTS_PER_MMAP)
8238c2ecf20Sopenharmony_ci			throttled = 1;
8248c2ecf20Sopenharmony_ci	}
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	/* flush queue after each round in which we processed events */
8278c2ecf20Sopenharmony_ci	if (ntotal) {
8288c2ecf20Sopenharmony_ci		struct ordered_events *oe = &kvm->session->ordered_events;
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci		oe->next_flush = flush_time;
8318c2ecf20Sopenharmony_ci		err = ordered_events__flush(oe, OE_FLUSH__ROUND);
8328c2ecf20Sopenharmony_ci		if (err) {
8338c2ecf20Sopenharmony_ci			if (kvm->lost_events)
8348c2ecf20Sopenharmony_ci				pr_info("\nLost events: %" PRIu64 "\n\n",
8358c2ecf20Sopenharmony_ci					kvm->lost_events);
8368c2ecf20Sopenharmony_ci			return err;
8378c2ecf20Sopenharmony_ci		}
8388c2ecf20Sopenharmony_ci	}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	return throttled;
8418c2ecf20Sopenharmony_ci}
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_cistatic volatile int done;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_cistatic void sig_handler(int sig __maybe_unused)
8468c2ecf20Sopenharmony_ci{
8478c2ecf20Sopenharmony_ci	done = 1;
8488c2ecf20Sopenharmony_ci}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_cistatic int perf_kvm__timerfd_create(struct perf_kvm_stat *kvm)
8518c2ecf20Sopenharmony_ci{
8528c2ecf20Sopenharmony_ci	struct itimerspec new_value;
8538c2ecf20Sopenharmony_ci	int rc = -1;
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	kvm->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
8568c2ecf20Sopenharmony_ci	if (kvm->timerfd < 0) {
8578c2ecf20Sopenharmony_ci		pr_err("timerfd_create failed\n");
8588c2ecf20Sopenharmony_ci		goto out;
8598c2ecf20Sopenharmony_ci	}
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	new_value.it_value.tv_sec = kvm->display_time;
8628c2ecf20Sopenharmony_ci	new_value.it_value.tv_nsec = 0;
8638c2ecf20Sopenharmony_ci	new_value.it_interval.tv_sec = kvm->display_time;
8648c2ecf20Sopenharmony_ci	new_value.it_interval.tv_nsec = 0;
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	if (timerfd_settime(kvm->timerfd, 0, &new_value, NULL) != 0) {
8678c2ecf20Sopenharmony_ci		pr_err("timerfd_settime failed: %d\n", errno);
8688c2ecf20Sopenharmony_ci		close(kvm->timerfd);
8698c2ecf20Sopenharmony_ci		goto out;
8708c2ecf20Sopenharmony_ci	}
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	rc = 0;
8738c2ecf20Sopenharmony_ciout:
8748c2ecf20Sopenharmony_ci	return rc;
8758c2ecf20Sopenharmony_ci}
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_cistatic int perf_kvm__handle_timerfd(struct perf_kvm_stat *kvm)
8788c2ecf20Sopenharmony_ci{
8798c2ecf20Sopenharmony_ci	uint64_t c;
8808c2ecf20Sopenharmony_ci	int rc;
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	rc = read(kvm->timerfd, &c, sizeof(uint64_t));
8838c2ecf20Sopenharmony_ci	if (rc < 0) {
8848c2ecf20Sopenharmony_ci		if (errno == EAGAIN)
8858c2ecf20Sopenharmony_ci			return 0;
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci		pr_err("Failed to read timer fd: %d\n", errno);
8888c2ecf20Sopenharmony_ci		return -1;
8898c2ecf20Sopenharmony_ci	}
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	if (rc != sizeof(uint64_t)) {
8928c2ecf20Sopenharmony_ci		pr_err("Error reading timer fd - invalid size returned\n");
8938c2ecf20Sopenharmony_ci		return -1;
8948c2ecf20Sopenharmony_ci	}
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	if (c != 1)
8978c2ecf20Sopenharmony_ci		pr_debug("Missed timer beats: %" PRIu64 "\n", c-1);
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	/* update display */
9008c2ecf20Sopenharmony_ci	sort_result(kvm);
9018c2ecf20Sopenharmony_ci	print_result(kvm);
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	/* reset counts */
9048c2ecf20Sopenharmony_ci	clear_events_cache_stats(kvm->kvm_events_cache);
9058c2ecf20Sopenharmony_ci	kvm->total_count = 0;
9068c2ecf20Sopenharmony_ci	kvm->total_time = 0;
9078c2ecf20Sopenharmony_ci	kvm->lost_events = 0;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	return 0;
9108c2ecf20Sopenharmony_ci}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_cistatic int fd_set_nonblock(int fd)
9138c2ecf20Sopenharmony_ci{
9148c2ecf20Sopenharmony_ci	long arg = 0;
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	arg = fcntl(fd, F_GETFL);
9178c2ecf20Sopenharmony_ci	if (arg < 0) {
9188c2ecf20Sopenharmony_ci		pr_err("Failed to get current flags for fd %d\n", fd);
9198c2ecf20Sopenharmony_ci		return -1;
9208c2ecf20Sopenharmony_ci	}
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	if (fcntl(fd, F_SETFL, arg | O_NONBLOCK) < 0) {
9238c2ecf20Sopenharmony_ci		pr_err("Failed to set non-block option on fd %d\n", fd);
9248c2ecf20Sopenharmony_ci		return -1;
9258c2ecf20Sopenharmony_ci	}
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	return 0;
9288c2ecf20Sopenharmony_ci}
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_cistatic int perf_kvm__handle_stdin(void)
9318c2ecf20Sopenharmony_ci{
9328c2ecf20Sopenharmony_ci	int c;
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	c = getc(stdin);
9358c2ecf20Sopenharmony_ci	if (c == 'q')
9368c2ecf20Sopenharmony_ci		return 1;
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	return 0;
9398c2ecf20Sopenharmony_ci}
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_cistatic int kvm_events_live_report(struct perf_kvm_stat *kvm)
9428c2ecf20Sopenharmony_ci{
9438c2ecf20Sopenharmony_ci	int nr_stdin, ret, err = -EINVAL;
9448c2ecf20Sopenharmony_ci	struct termios save;
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	/* live flag must be set first */
9478c2ecf20Sopenharmony_ci	kvm->live = true;
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	ret = cpu_isa_config(kvm);
9508c2ecf20Sopenharmony_ci	if (ret < 0)
9518c2ecf20Sopenharmony_ci		return ret;
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	if (!verify_vcpu(kvm->trace_vcpu) ||
9548c2ecf20Sopenharmony_ci	    !select_key(kvm) ||
9558c2ecf20Sopenharmony_ci	    !register_kvm_events_ops(kvm)) {
9568c2ecf20Sopenharmony_ci		goto out;
9578c2ecf20Sopenharmony_ci	}
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	set_term_quiet_input(&save);
9608c2ecf20Sopenharmony_ci	init_kvm_event_record(kvm);
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci	signal(SIGINT, sig_handler);
9638c2ecf20Sopenharmony_ci	signal(SIGTERM, sig_handler);
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	/* add timer fd */
9668c2ecf20Sopenharmony_ci	if (perf_kvm__timerfd_create(kvm) < 0) {
9678c2ecf20Sopenharmony_ci		err = -1;
9688c2ecf20Sopenharmony_ci		goto out;
9698c2ecf20Sopenharmony_ci	}
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	if (evlist__add_pollfd(kvm->evlist, kvm->timerfd) < 0)
9728c2ecf20Sopenharmony_ci		goto out;
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	nr_stdin = evlist__add_pollfd(kvm->evlist, fileno(stdin));
9758c2ecf20Sopenharmony_ci	if (nr_stdin < 0)
9768c2ecf20Sopenharmony_ci		goto out;
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	if (fd_set_nonblock(fileno(stdin)) != 0)
9798c2ecf20Sopenharmony_ci		goto out;
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	/* everything is good - enable the events and process */
9828c2ecf20Sopenharmony_ci	evlist__enable(kvm->evlist);
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	while (!done) {
9858c2ecf20Sopenharmony_ci		struct fdarray *fda = &kvm->evlist->core.pollfd;
9868c2ecf20Sopenharmony_ci		int rc;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci		rc = perf_kvm__mmap_read(kvm);
9898c2ecf20Sopenharmony_ci		if (rc < 0)
9908c2ecf20Sopenharmony_ci			break;
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci		err = perf_kvm__handle_timerfd(kvm);
9938c2ecf20Sopenharmony_ci		if (err)
9948c2ecf20Sopenharmony_ci			goto out;
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci		if (fda->entries[nr_stdin].revents & POLLIN)
9978c2ecf20Sopenharmony_ci			done = perf_kvm__handle_stdin();
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci		if (!rc && !done)
10008c2ecf20Sopenharmony_ci			err = evlist__poll(kvm->evlist, 100);
10018c2ecf20Sopenharmony_ci	}
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	evlist__disable(kvm->evlist);
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	if (err == 0) {
10068c2ecf20Sopenharmony_ci		sort_result(kvm);
10078c2ecf20Sopenharmony_ci		print_result(kvm);
10088c2ecf20Sopenharmony_ci	}
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ciout:
10118c2ecf20Sopenharmony_ci	if (kvm->timerfd >= 0)
10128c2ecf20Sopenharmony_ci		close(kvm->timerfd);
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	tcsetattr(0, TCSAFLUSH, &save);
10158c2ecf20Sopenharmony_ci	return err;
10168c2ecf20Sopenharmony_ci}
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_cistatic int kvm_live_open_events(struct perf_kvm_stat *kvm)
10198c2ecf20Sopenharmony_ci{
10208c2ecf20Sopenharmony_ci	int err, rc = -1;
10218c2ecf20Sopenharmony_ci	struct evsel *pos;
10228c2ecf20Sopenharmony_ci	struct evlist *evlist = kvm->evlist;
10238c2ecf20Sopenharmony_ci	char sbuf[STRERR_BUFSIZE];
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	perf_evlist__config(evlist, &kvm->opts, NULL);
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	/*
10288c2ecf20Sopenharmony_ci	 * Note: exclude_{guest,host} do not apply here.
10298c2ecf20Sopenharmony_ci	 *       This command processes KVM tracepoints from host only
10308c2ecf20Sopenharmony_ci	 */
10318c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, pos) {
10328c2ecf20Sopenharmony_ci		struct perf_event_attr *attr = &pos->core.attr;
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci		/* make sure these *are* set */
10358c2ecf20Sopenharmony_ci		evsel__set_sample_bit(pos, TID);
10368c2ecf20Sopenharmony_ci		evsel__set_sample_bit(pos, TIME);
10378c2ecf20Sopenharmony_ci		evsel__set_sample_bit(pos, CPU);
10388c2ecf20Sopenharmony_ci		evsel__set_sample_bit(pos, RAW);
10398c2ecf20Sopenharmony_ci		/* make sure these are *not*; want as small a sample as possible */
10408c2ecf20Sopenharmony_ci		evsel__reset_sample_bit(pos, PERIOD);
10418c2ecf20Sopenharmony_ci		evsel__reset_sample_bit(pos, IP);
10428c2ecf20Sopenharmony_ci		evsel__reset_sample_bit(pos, CALLCHAIN);
10438c2ecf20Sopenharmony_ci		evsel__reset_sample_bit(pos, ADDR);
10448c2ecf20Sopenharmony_ci		evsel__reset_sample_bit(pos, READ);
10458c2ecf20Sopenharmony_ci		attr->mmap = 0;
10468c2ecf20Sopenharmony_ci		attr->comm = 0;
10478c2ecf20Sopenharmony_ci		attr->task = 0;
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci		attr->sample_period = 1;
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci		attr->watermark = 0;
10528c2ecf20Sopenharmony_ci		attr->wakeup_events = 1000;
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci		/* will enable all once we are ready */
10558c2ecf20Sopenharmony_ci		attr->disabled = 1;
10568c2ecf20Sopenharmony_ci	}
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	err = evlist__open(evlist);
10598c2ecf20Sopenharmony_ci	if (err < 0) {
10608c2ecf20Sopenharmony_ci		printf("Couldn't create the events: %s\n",
10618c2ecf20Sopenharmony_ci		       str_error_r(errno, sbuf, sizeof(sbuf)));
10628c2ecf20Sopenharmony_ci		goto out;
10638c2ecf20Sopenharmony_ci	}
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci	if (evlist__mmap(evlist, kvm->opts.mmap_pages) < 0) {
10668c2ecf20Sopenharmony_ci		ui__error("Failed to mmap the events: %s\n",
10678c2ecf20Sopenharmony_ci			  str_error_r(errno, sbuf, sizeof(sbuf)));
10688c2ecf20Sopenharmony_ci		evlist__close(evlist);
10698c2ecf20Sopenharmony_ci		goto out;
10708c2ecf20Sopenharmony_ci	}
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	rc = 0;
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ciout:
10758c2ecf20Sopenharmony_ci	return rc;
10768c2ecf20Sopenharmony_ci}
10778c2ecf20Sopenharmony_ci#endif
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_cistatic int read_events(struct perf_kvm_stat *kvm)
10808c2ecf20Sopenharmony_ci{
10818c2ecf20Sopenharmony_ci	int ret;
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	struct perf_tool eops = {
10848c2ecf20Sopenharmony_ci		.sample			= process_sample_event,
10858c2ecf20Sopenharmony_ci		.comm			= perf_event__process_comm,
10868c2ecf20Sopenharmony_ci		.namespaces		= perf_event__process_namespaces,
10878c2ecf20Sopenharmony_ci		.ordered_events		= true,
10888c2ecf20Sopenharmony_ci	};
10898c2ecf20Sopenharmony_ci	struct perf_data file = {
10908c2ecf20Sopenharmony_ci		.path  = kvm->file_name,
10918c2ecf20Sopenharmony_ci		.mode  = PERF_DATA_MODE_READ,
10928c2ecf20Sopenharmony_ci		.force = kvm->force,
10938c2ecf20Sopenharmony_ci	};
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci	kvm->tool = eops;
10968c2ecf20Sopenharmony_ci	kvm->session = perf_session__new(&file, false, &kvm->tool);
10978c2ecf20Sopenharmony_ci	if (IS_ERR(kvm->session)) {
10988c2ecf20Sopenharmony_ci		pr_err("Initializing perf session failed\n");
10998c2ecf20Sopenharmony_ci		return PTR_ERR(kvm->session);
11008c2ecf20Sopenharmony_ci	}
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	symbol__init(&kvm->session->header.env);
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	if (!perf_session__has_traces(kvm->session, "kvm record")) {
11058c2ecf20Sopenharmony_ci		ret = -EINVAL;
11068c2ecf20Sopenharmony_ci		goto out_delete;
11078c2ecf20Sopenharmony_ci	}
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci	/*
11108c2ecf20Sopenharmony_ci	 * Do not use 'isa' recorded in kvm_exit tracepoint since it is not
11118c2ecf20Sopenharmony_ci	 * traced in the old kernel.
11128c2ecf20Sopenharmony_ci	 */
11138c2ecf20Sopenharmony_ci	ret = cpu_isa_config(kvm);
11148c2ecf20Sopenharmony_ci	if (ret < 0)
11158c2ecf20Sopenharmony_ci		goto out_delete;
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	ret = perf_session__process_events(kvm->session);
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ciout_delete:
11208c2ecf20Sopenharmony_ci	perf_session__delete(kvm->session);
11218c2ecf20Sopenharmony_ci	return ret;
11228c2ecf20Sopenharmony_ci}
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_cistatic int parse_target_str(struct perf_kvm_stat *kvm)
11258c2ecf20Sopenharmony_ci{
11268c2ecf20Sopenharmony_ci	if (kvm->opts.target.pid) {
11278c2ecf20Sopenharmony_ci		kvm->pid_list = intlist__new(kvm->opts.target.pid);
11288c2ecf20Sopenharmony_ci		if (kvm->pid_list == NULL) {
11298c2ecf20Sopenharmony_ci			pr_err("Error parsing process id string\n");
11308c2ecf20Sopenharmony_ci			return -EINVAL;
11318c2ecf20Sopenharmony_ci		}
11328c2ecf20Sopenharmony_ci	}
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	return 0;
11358c2ecf20Sopenharmony_ci}
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_cistatic int kvm_events_report_vcpu(struct perf_kvm_stat *kvm)
11388c2ecf20Sopenharmony_ci{
11398c2ecf20Sopenharmony_ci	int ret = -EINVAL;
11408c2ecf20Sopenharmony_ci	int vcpu = kvm->trace_vcpu;
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci	if (parse_target_str(kvm) != 0)
11438c2ecf20Sopenharmony_ci		goto exit;
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci	if (!verify_vcpu(vcpu))
11468c2ecf20Sopenharmony_ci		goto exit;
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	if (!select_key(kvm))
11498c2ecf20Sopenharmony_ci		goto exit;
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	if (!register_kvm_events_ops(kvm))
11528c2ecf20Sopenharmony_ci		goto exit;
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	init_kvm_event_record(kvm);
11558c2ecf20Sopenharmony_ci	setup_pager();
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci	ret = read_events(kvm);
11588c2ecf20Sopenharmony_ci	if (ret)
11598c2ecf20Sopenharmony_ci		goto exit;
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	sort_result(kvm);
11628c2ecf20Sopenharmony_ci	print_result(kvm);
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ciexit:
11658c2ecf20Sopenharmony_ci	return ret;
11668c2ecf20Sopenharmony_ci}
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci#define STRDUP_FAIL_EXIT(s)		\
11698c2ecf20Sopenharmony_ci	({	char *_p;		\
11708c2ecf20Sopenharmony_ci	_p = strdup(s);		\
11718c2ecf20Sopenharmony_ci		if (!_p)		\
11728c2ecf20Sopenharmony_ci			return -ENOMEM;	\
11738c2ecf20Sopenharmony_ci		_p;			\
11748c2ecf20Sopenharmony_ci	})
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ciint __weak setup_kvm_events_tp(struct perf_kvm_stat *kvm __maybe_unused)
11778c2ecf20Sopenharmony_ci{
11788c2ecf20Sopenharmony_ci	return 0;
11798c2ecf20Sopenharmony_ci}
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_cistatic int
11828c2ecf20Sopenharmony_cikvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
11838c2ecf20Sopenharmony_ci{
11848c2ecf20Sopenharmony_ci	unsigned int rec_argc, i, j, events_tp_size;
11858c2ecf20Sopenharmony_ci	const char **rec_argv;
11868c2ecf20Sopenharmony_ci	const char * const record_args[] = {
11878c2ecf20Sopenharmony_ci		"record",
11888c2ecf20Sopenharmony_ci		"-R",
11898c2ecf20Sopenharmony_ci		"-m", "1024",
11908c2ecf20Sopenharmony_ci		"-c", "1",
11918c2ecf20Sopenharmony_ci	};
11928c2ecf20Sopenharmony_ci	const char * const kvm_stat_record_usage[] = {
11938c2ecf20Sopenharmony_ci		"perf kvm stat record [<options>]",
11948c2ecf20Sopenharmony_ci		NULL
11958c2ecf20Sopenharmony_ci	};
11968c2ecf20Sopenharmony_ci	const char * const *events_tp;
11978c2ecf20Sopenharmony_ci	int ret;
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci	events_tp_size = 0;
12008c2ecf20Sopenharmony_ci	ret = setup_kvm_events_tp(kvm);
12018c2ecf20Sopenharmony_ci	if (ret < 0) {
12028c2ecf20Sopenharmony_ci		pr_err("Unable to setup the kvm tracepoints\n");
12038c2ecf20Sopenharmony_ci		return ret;
12048c2ecf20Sopenharmony_ci	}
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	for (events_tp = kvm_events_tp; *events_tp; events_tp++)
12078c2ecf20Sopenharmony_ci		events_tp_size++;
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci	rec_argc = ARRAY_SIZE(record_args) + argc + 2 +
12108c2ecf20Sopenharmony_ci		   2 * events_tp_size;
12118c2ecf20Sopenharmony_ci	rec_argv = calloc(rec_argc + 1, sizeof(char *));
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	if (rec_argv == NULL)
12148c2ecf20Sopenharmony_ci		return -ENOMEM;
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(record_args); i++)
12178c2ecf20Sopenharmony_ci		rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]);
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	for (j = 0; j < events_tp_size; j++) {
12208c2ecf20Sopenharmony_ci		rec_argv[i++] = "-e";
12218c2ecf20Sopenharmony_ci		rec_argv[i++] = STRDUP_FAIL_EXIT(kvm_events_tp[j]);
12228c2ecf20Sopenharmony_ci	}
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci	rec_argv[i++] = STRDUP_FAIL_EXIT("-o");
12258c2ecf20Sopenharmony_ci	rec_argv[i++] = STRDUP_FAIL_EXIT(kvm->file_name);
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	for (j = 1; j < (unsigned int)argc; j++, i++)
12288c2ecf20Sopenharmony_ci		rec_argv[i] = argv[j];
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	set_option_flag(record_options, 'e', "event", PARSE_OPT_HIDDEN);
12318c2ecf20Sopenharmony_ci	set_option_flag(record_options, 0, "filter", PARSE_OPT_HIDDEN);
12328c2ecf20Sopenharmony_ci	set_option_flag(record_options, 'R', "raw-samples", PARSE_OPT_HIDDEN);
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	set_option_flag(record_options, 'F', "freq", PARSE_OPT_DISABLED);
12358c2ecf20Sopenharmony_ci	set_option_flag(record_options, 0, "group", PARSE_OPT_DISABLED);
12368c2ecf20Sopenharmony_ci	set_option_flag(record_options, 'g', NULL, PARSE_OPT_DISABLED);
12378c2ecf20Sopenharmony_ci	set_option_flag(record_options, 0, "call-graph", PARSE_OPT_DISABLED);
12388c2ecf20Sopenharmony_ci	set_option_flag(record_options, 'd', "data", PARSE_OPT_DISABLED);
12398c2ecf20Sopenharmony_ci	set_option_flag(record_options, 'T', "timestamp", PARSE_OPT_DISABLED);
12408c2ecf20Sopenharmony_ci	set_option_flag(record_options, 'P', "period", PARSE_OPT_DISABLED);
12418c2ecf20Sopenharmony_ci	set_option_flag(record_options, 'n', "no-samples", PARSE_OPT_DISABLED);
12428c2ecf20Sopenharmony_ci	set_option_flag(record_options, 'N', "no-buildid-cache", PARSE_OPT_DISABLED);
12438c2ecf20Sopenharmony_ci	set_option_flag(record_options, 'B', "no-buildid", PARSE_OPT_DISABLED);
12448c2ecf20Sopenharmony_ci	set_option_flag(record_options, 'G', "cgroup", PARSE_OPT_DISABLED);
12458c2ecf20Sopenharmony_ci	set_option_flag(record_options, 'b', "branch-any", PARSE_OPT_DISABLED);
12468c2ecf20Sopenharmony_ci	set_option_flag(record_options, 'j', "branch-filter", PARSE_OPT_DISABLED);
12478c2ecf20Sopenharmony_ci	set_option_flag(record_options, 'W', "weight", PARSE_OPT_DISABLED);
12488c2ecf20Sopenharmony_ci	set_option_flag(record_options, 0, "transaction", PARSE_OPT_DISABLED);
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci	record_usage = kvm_stat_record_usage;
12518c2ecf20Sopenharmony_ci	return cmd_record(i, rec_argv);
12528c2ecf20Sopenharmony_ci}
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_cistatic int
12558c2ecf20Sopenharmony_cikvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
12568c2ecf20Sopenharmony_ci{
12578c2ecf20Sopenharmony_ci	const struct option kvm_events_report_options[] = {
12588c2ecf20Sopenharmony_ci		OPT_STRING(0, "event", &kvm->report_event, "report event",
12598c2ecf20Sopenharmony_ci			   "event for reporting: vmexit, "
12608c2ecf20Sopenharmony_ci			   "mmio (x86 only), ioport (x86 only)"),
12618c2ecf20Sopenharmony_ci		OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu,
12628c2ecf20Sopenharmony_ci			    "vcpu id to report"),
12638c2ecf20Sopenharmony_ci		OPT_STRING('k', "key", &kvm->sort_key, "sort-key",
12648c2ecf20Sopenharmony_ci			    "key for sorting: sample(sort by samples number)"
12658c2ecf20Sopenharmony_ci			    " time (sort by avg time)"),
12668c2ecf20Sopenharmony_ci		OPT_STRING('p', "pid", &kvm->opts.target.pid, "pid",
12678c2ecf20Sopenharmony_ci			   "analyze events only for given process id(s)"),
12688c2ecf20Sopenharmony_ci		OPT_BOOLEAN('f', "force", &kvm->force, "don't complain, do it"),
12698c2ecf20Sopenharmony_ci		OPT_END()
12708c2ecf20Sopenharmony_ci	};
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci	const char * const kvm_events_report_usage[] = {
12738c2ecf20Sopenharmony_ci		"perf kvm stat report [<options>]",
12748c2ecf20Sopenharmony_ci		NULL
12758c2ecf20Sopenharmony_ci	};
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	if (argc) {
12788c2ecf20Sopenharmony_ci		argc = parse_options(argc, argv,
12798c2ecf20Sopenharmony_ci				     kvm_events_report_options,
12808c2ecf20Sopenharmony_ci				     kvm_events_report_usage, 0);
12818c2ecf20Sopenharmony_ci		if (argc)
12828c2ecf20Sopenharmony_ci			usage_with_options(kvm_events_report_usage,
12838c2ecf20Sopenharmony_ci					   kvm_events_report_options);
12848c2ecf20Sopenharmony_ci	}
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci	if (!kvm->opts.target.pid)
12878c2ecf20Sopenharmony_ci		kvm->opts.target.system_wide = true;
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci	return kvm_events_report_vcpu(kvm);
12908c2ecf20Sopenharmony_ci}
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_ci#ifdef HAVE_TIMERFD_SUPPORT
12938c2ecf20Sopenharmony_cistatic struct evlist *kvm_live_event_list(void)
12948c2ecf20Sopenharmony_ci{
12958c2ecf20Sopenharmony_ci	struct evlist *evlist;
12968c2ecf20Sopenharmony_ci	char *tp, *name, *sys;
12978c2ecf20Sopenharmony_ci	int err = -1;
12988c2ecf20Sopenharmony_ci	const char * const *events_tp;
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	evlist = evlist__new();
13018c2ecf20Sopenharmony_ci	if (evlist == NULL)
13028c2ecf20Sopenharmony_ci		return NULL;
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	for (events_tp = kvm_events_tp; *events_tp; events_tp++) {
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci		tp = strdup(*events_tp);
13078c2ecf20Sopenharmony_ci		if (tp == NULL)
13088c2ecf20Sopenharmony_ci			goto out;
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci		/* split tracepoint into subsystem and name */
13118c2ecf20Sopenharmony_ci		sys = tp;
13128c2ecf20Sopenharmony_ci		name = strchr(tp, ':');
13138c2ecf20Sopenharmony_ci		if (name == NULL) {
13148c2ecf20Sopenharmony_ci			pr_err("Error parsing %s tracepoint: subsystem delimiter not found\n",
13158c2ecf20Sopenharmony_ci			       *events_tp);
13168c2ecf20Sopenharmony_ci			free(tp);
13178c2ecf20Sopenharmony_ci			goto out;
13188c2ecf20Sopenharmony_ci		}
13198c2ecf20Sopenharmony_ci		*name = '\0';
13208c2ecf20Sopenharmony_ci		name++;
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci		if (evlist__add_newtp(evlist, sys, name, NULL)) {
13238c2ecf20Sopenharmony_ci			pr_err("Failed to add %s tracepoint to the list\n", *events_tp);
13248c2ecf20Sopenharmony_ci			free(tp);
13258c2ecf20Sopenharmony_ci			goto out;
13268c2ecf20Sopenharmony_ci		}
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_ci		free(tp);
13298c2ecf20Sopenharmony_ci	}
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_ci	err = 0;
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ciout:
13348c2ecf20Sopenharmony_ci	if (err) {
13358c2ecf20Sopenharmony_ci		evlist__delete(evlist);
13368c2ecf20Sopenharmony_ci		evlist = NULL;
13378c2ecf20Sopenharmony_ci	}
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	return evlist;
13408c2ecf20Sopenharmony_ci}
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_cistatic int kvm_events_live(struct perf_kvm_stat *kvm,
13438c2ecf20Sopenharmony_ci			   int argc, const char **argv)
13448c2ecf20Sopenharmony_ci{
13458c2ecf20Sopenharmony_ci	char errbuf[BUFSIZ];
13468c2ecf20Sopenharmony_ci	int err;
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	const struct option live_options[] = {
13498c2ecf20Sopenharmony_ci		OPT_STRING('p', "pid", &kvm->opts.target.pid, "pid",
13508c2ecf20Sopenharmony_ci			"record events on existing process id"),
13518c2ecf20Sopenharmony_ci		OPT_CALLBACK('m', "mmap-pages", &kvm->opts.mmap_pages, "pages",
13528c2ecf20Sopenharmony_ci			"number of mmap data pages",
13538c2ecf20Sopenharmony_ci			perf_evlist__parse_mmap_pages),
13548c2ecf20Sopenharmony_ci		OPT_INCR('v', "verbose", &verbose,
13558c2ecf20Sopenharmony_ci			"be more verbose (show counter open errors, etc)"),
13568c2ecf20Sopenharmony_ci		OPT_BOOLEAN('a', "all-cpus", &kvm->opts.target.system_wide,
13578c2ecf20Sopenharmony_ci			"system-wide collection from all CPUs"),
13588c2ecf20Sopenharmony_ci		OPT_UINTEGER('d', "display", &kvm->display_time,
13598c2ecf20Sopenharmony_ci			"time in seconds between display updates"),
13608c2ecf20Sopenharmony_ci		OPT_STRING(0, "event", &kvm->report_event, "report event",
13618c2ecf20Sopenharmony_ci			"event for reporting: "
13628c2ecf20Sopenharmony_ci			"vmexit, mmio (x86 only), ioport (x86 only)"),
13638c2ecf20Sopenharmony_ci		OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu,
13648c2ecf20Sopenharmony_ci			"vcpu id to report"),
13658c2ecf20Sopenharmony_ci		OPT_STRING('k', "key", &kvm->sort_key, "sort-key",
13668c2ecf20Sopenharmony_ci			"key for sorting: sample(sort by samples number)"
13678c2ecf20Sopenharmony_ci			" time (sort by avg time)"),
13688c2ecf20Sopenharmony_ci		OPT_U64(0, "duration", &kvm->duration,
13698c2ecf20Sopenharmony_ci			"show events other than"
13708c2ecf20Sopenharmony_ci			" HLT (x86 only) or Wait state (s390 only)"
13718c2ecf20Sopenharmony_ci			" that take longer than duration usecs"),
13728c2ecf20Sopenharmony_ci		OPT_UINTEGER(0, "proc-map-timeout", &proc_map_timeout,
13738c2ecf20Sopenharmony_ci				"per thread proc mmap processing timeout in ms"),
13748c2ecf20Sopenharmony_ci		OPT_END()
13758c2ecf20Sopenharmony_ci	};
13768c2ecf20Sopenharmony_ci	const char * const live_usage[] = {
13778c2ecf20Sopenharmony_ci		"perf kvm stat live [<options>]",
13788c2ecf20Sopenharmony_ci		NULL
13798c2ecf20Sopenharmony_ci	};
13808c2ecf20Sopenharmony_ci	struct perf_data data = {
13818c2ecf20Sopenharmony_ci		.mode = PERF_DATA_MODE_WRITE,
13828c2ecf20Sopenharmony_ci	};
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci	/* event handling */
13868c2ecf20Sopenharmony_ci	kvm->tool.sample = process_sample_event;
13878c2ecf20Sopenharmony_ci	kvm->tool.comm   = perf_event__process_comm;
13888c2ecf20Sopenharmony_ci	kvm->tool.exit   = perf_event__process_exit;
13898c2ecf20Sopenharmony_ci	kvm->tool.fork   = perf_event__process_fork;
13908c2ecf20Sopenharmony_ci	kvm->tool.lost   = process_lost_event;
13918c2ecf20Sopenharmony_ci	kvm->tool.namespaces  = perf_event__process_namespaces;
13928c2ecf20Sopenharmony_ci	kvm->tool.ordered_events = true;
13938c2ecf20Sopenharmony_ci	perf_tool__fill_defaults(&kvm->tool);
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci	/* set defaults */
13968c2ecf20Sopenharmony_ci	kvm->display_time = 1;
13978c2ecf20Sopenharmony_ci	kvm->opts.user_interval = 1;
13988c2ecf20Sopenharmony_ci	kvm->opts.mmap_pages = 512;
13998c2ecf20Sopenharmony_ci	kvm->opts.target.uses_mmap = false;
14008c2ecf20Sopenharmony_ci	kvm->opts.target.uid_str = NULL;
14018c2ecf20Sopenharmony_ci	kvm->opts.target.uid = UINT_MAX;
14028c2ecf20Sopenharmony_ci
14038c2ecf20Sopenharmony_ci	symbol__init(NULL);
14048c2ecf20Sopenharmony_ci	disable_buildid_cache();
14058c2ecf20Sopenharmony_ci
14068c2ecf20Sopenharmony_ci	use_browser = 0;
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	if (argc) {
14098c2ecf20Sopenharmony_ci		argc = parse_options(argc, argv, live_options,
14108c2ecf20Sopenharmony_ci				     live_usage, 0);
14118c2ecf20Sopenharmony_ci		if (argc)
14128c2ecf20Sopenharmony_ci			usage_with_options(live_usage, live_options);
14138c2ecf20Sopenharmony_ci	}
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	kvm->duration *= NSEC_PER_USEC;   /* convert usec to nsec */
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_ci	/*
14188c2ecf20Sopenharmony_ci	 * target related setups
14198c2ecf20Sopenharmony_ci	 */
14208c2ecf20Sopenharmony_ci	err = target__validate(&kvm->opts.target);
14218c2ecf20Sopenharmony_ci	if (err) {
14228c2ecf20Sopenharmony_ci		target__strerror(&kvm->opts.target, err, errbuf, BUFSIZ);
14238c2ecf20Sopenharmony_ci		ui__warning("%s", errbuf);
14248c2ecf20Sopenharmony_ci	}
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci	if (target__none(&kvm->opts.target))
14278c2ecf20Sopenharmony_ci		kvm->opts.target.system_wide = true;
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	/*
14318c2ecf20Sopenharmony_ci	 * generate the event list
14328c2ecf20Sopenharmony_ci	 */
14338c2ecf20Sopenharmony_ci	err = setup_kvm_events_tp(kvm);
14348c2ecf20Sopenharmony_ci	if (err < 0) {
14358c2ecf20Sopenharmony_ci		pr_err("Unable to setup the kvm tracepoints\n");
14368c2ecf20Sopenharmony_ci		return err;
14378c2ecf20Sopenharmony_ci	}
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci	kvm->evlist = kvm_live_event_list();
14408c2ecf20Sopenharmony_ci	if (kvm->evlist == NULL) {
14418c2ecf20Sopenharmony_ci		err = -1;
14428c2ecf20Sopenharmony_ci		goto out;
14438c2ecf20Sopenharmony_ci	}
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_ci	if (perf_evlist__create_maps(kvm->evlist, &kvm->opts.target) < 0)
14468c2ecf20Sopenharmony_ci		usage_with_options(live_usage, live_options);
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci	/*
14498c2ecf20Sopenharmony_ci	 * perf session
14508c2ecf20Sopenharmony_ci	 */
14518c2ecf20Sopenharmony_ci	kvm->session = perf_session__new(&data, false, &kvm->tool);
14528c2ecf20Sopenharmony_ci	if (IS_ERR(kvm->session)) {
14538c2ecf20Sopenharmony_ci		err = PTR_ERR(kvm->session);
14548c2ecf20Sopenharmony_ci		goto out;
14558c2ecf20Sopenharmony_ci	}
14568c2ecf20Sopenharmony_ci	kvm->session->evlist = kvm->evlist;
14578c2ecf20Sopenharmony_ci	perf_session__set_id_hdr_size(kvm->session);
14588c2ecf20Sopenharmony_ci	ordered_events__set_copy_on_queue(&kvm->session->ordered_events, true);
14598c2ecf20Sopenharmony_ci	machine__synthesize_threads(&kvm->session->machines.host, &kvm->opts.target,
14608c2ecf20Sopenharmony_ci				    kvm->evlist->core.threads, false, 1);
14618c2ecf20Sopenharmony_ci	err = kvm_live_open_events(kvm);
14628c2ecf20Sopenharmony_ci	if (err)
14638c2ecf20Sopenharmony_ci		goto out;
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci	err = kvm_events_live_report(kvm);
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ciout:
14688c2ecf20Sopenharmony_ci	perf_session__delete(kvm->session);
14698c2ecf20Sopenharmony_ci	kvm->session = NULL;
14708c2ecf20Sopenharmony_ci	evlist__delete(kvm->evlist);
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci	return err;
14738c2ecf20Sopenharmony_ci}
14748c2ecf20Sopenharmony_ci#endif
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_cistatic void print_kvm_stat_usage(void)
14778c2ecf20Sopenharmony_ci{
14788c2ecf20Sopenharmony_ci	printf("Usage: perf kvm stat <command>\n\n");
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci	printf("# Available commands:\n");
14818c2ecf20Sopenharmony_ci	printf("\trecord: record kvm events\n");
14828c2ecf20Sopenharmony_ci	printf("\treport: report statistical data of kvm events\n");
14838c2ecf20Sopenharmony_ci	printf("\tlive:   live reporting of statistical data of kvm events\n");
14848c2ecf20Sopenharmony_ci
14858c2ecf20Sopenharmony_ci	printf("\nOtherwise, it is the alias of 'perf stat':\n");
14868c2ecf20Sopenharmony_ci}
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_cistatic int kvm_cmd_stat(const char *file_name, int argc, const char **argv)
14898c2ecf20Sopenharmony_ci{
14908c2ecf20Sopenharmony_ci	struct perf_kvm_stat kvm = {
14918c2ecf20Sopenharmony_ci		.file_name = file_name,
14928c2ecf20Sopenharmony_ci
14938c2ecf20Sopenharmony_ci		.trace_vcpu	= -1,
14948c2ecf20Sopenharmony_ci		.report_event	= "vmexit",
14958c2ecf20Sopenharmony_ci		.sort_key	= "sample",
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci	};
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_ci	if (argc == 1) {
15008c2ecf20Sopenharmony_ci		print_kvm_stat_usage();
15018c2ecf20Sopenharmony_ci		goto perf_stat;
15028c2ecf20Sopenharmony_ci	}
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	if (!strncmp(argv[1], "rec", 3))
15058c2ecf20Sopenharmony_ci		return kvm_events_record(&kvm, argc - 1, argv + 1);
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_ci	if (!strncmp(argv[1], "rep", 3))
15088c2ecf20Sopenharmony_ci		return kvm_events_report(&kvm, argc - 1 , argv + 1);
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci#ifdef HAVE_TIMERFD_SUPPORT
15118c2ecf20Sopenharmony_ci	if (!strncmp(argv[1], "live", 4))
15128c2ecf20Sopenharmony_ci		return kvm_events_live(&kvm, argc - 1 , argv + 1);
15138c2ecf20Sopenharmony_ci#endif
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ciperf_stat:
15168c2ecf20Sopenharmony_ci	return cmd_stat(argc, argv);
15178c2ecf20Sopenharmony_ci}
15188c2ecf20Sopenharmony_ci#endif /* HAVE_KVM_STAT_SUPPORT */
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ciint __weak kvm_add_default_arch_event(int *argc __maybe_unused,
15218c2ecf20Sopenharmony_ci					const char **argv __maybe_unused)
15228c2ecf20Sopenharmony_ci{
15238c2ecf20Sopenharmony_ci	return 0;
15248c2ecf20Sopenharmony_ci}
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_cistatic int __cmd_record(const char *file_name, int argc, const char **argv)
15278c2ecf20Sopenharmony_ci{
15288c2ecf20Sopenharmony_ci	int rec_argc, i = 0, j, ret;
15298c2ecf20Sopenharmony_ci	const char **rec_argv;
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci	ret = kvm_add_default_arch_event(&argc, argv);
15328c2ecf20Sopenharmony_ci	if (ret)
15338c2ecf20Sopenharmony_ci		return -EINVAL;
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci	rec_argc = argc + 2;
15368c2ecf20Sopenharmony_ci	rec_argv = calloc(rec_argc + 1, sizeof(char *));
15378c2ecf20Sopenharmony_ci	rec_argv[i++] = strdup("record");
15388c2ecf20Sopenharmony_ci	rec_argv[i++] = strdup("-o");
15398c2ecf20Sopenharmony_ci	rec_argv[i++] = strdup(file_name);
15408c2ecf20Sopenharmony_ci	for (j = 1; j < argc; j++, i++)
15418c2ecf20Sopenharmony_ci		rec_argv[i] = argv[j];
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci	BUG_ON(i != rec_argc);
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci	return cmd_record(i, rec_argv);
15468c2ecf20Sopenharmony_ci}
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_cistatic int __cmd_report(const char *file_name, int argc, const char **argv)
15498c2ecf20Sopenharmony_ci{
15508c2ecf20Sopenharmony_ci	int rec_argc, i = 0, j;
15518c2ecf20Sopenharmony_ci	const char **rec_argv;
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci	rec_argc = argc + 2;
15548c2ecf20Sopenharmony_ci	rec_argv = calloc(rec_argc + 1, sizeof(char *));
15558c2ecf20Sopenharmony_ci	rec_argv[i++] = strdup("report");
15568c2ecf20Sopenharmony_ci	rec_argv[i++] = strdup("-i");
15578c2ecf20Sopenharmony_ci	rec_argv[i++] = strdup(file_name);
15588c2ecf20Sopenharmony_ci	for (j = 1; j < argc; j++, i++)
15598c2ecf20Sopenharmony_ci		rec_argv[i] = argv[j];
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci	BUG_ON(i != rec_argc);
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_ci	return cmd_report(i, rec_argv);
15648c2ecf20Sopenharmony_ci}
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_cistatic int
15678c2ecf20Sopenharmony_ci__cmd_buildid_list(const char *file_name, int argc, const char **argv)
15688c2ecf20Sopenharmony_ci{
15698c2ecf20Sopenharmony_ci	int rec_argc, i = 0, j;
15708c2ecf20Sopenharmony_ci	const char **rec_argv;
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci	rec_argc = argc + 2;
15738c2ecf20Sopenharmony_ci	rec_argv = calloc(rec_argc + 1, sizeof(char *));
15748c2ecf20Sopenharmony_ci	rec_argv[i++] = strdup("buildid-list");
15758c2ecf20Sopenharmony_ci	rec_argv[i++] = strdup("-i");
15768c2ecf20Sopenharmony_ci	rec_argv[i++] = strdup(file_name);
15778c2ecf20Sopenharmony_ci	for (j = 1; j < argc; j++, i++)
15788c2ecf20Sopenharmony_ci		rec_argv[i] = argv[j];
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci	BUG_ON(i != rec_argc);
15818c2ecf20Sopenharmony_ci
15828c2ecf20Sopenharmony_ci	return cmd_buildid_list(i, rec_argv);
15838c2ecf20Sopenharmony_ci}
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ciint cmd_kvm(int argc, const char **argv)
15868c2ecf20Sopenharmony_ci{
15878c2ecf20Sopenharmony_ci	const char *file_name = NULL;
15888c2ecf20Sopenharmony_ci	const struct option kvm_options[] = {
15898c2ecf20Sopenharmony_ci		OPT_STRING('i', "input", &file_name, "file",
15908c2ecf20Sopenharmony_ci			   "Input file name"),
15918c2ecf20Sopenharmony_ci		OPT_STRING('o', "output", &file_name, "file",
15928c2ecf20Sopenharmony_ci			   "Output file name"),
15938c2ecf20Sopenharmony_ci		OPT_BOOLEAN(0, "guest", &perf_guest,
15948c2ecf20Sopenharmony_ci			    "Collect guest os data"),
15958c2ecf20Sopenharmony_ci		OPT_BOOLEAN(0, "host", &perf_host,
15968c2ecf20Sopenharmony_ci			    "Collect host os data"),
15978c2ecf20Sopenharmony_ci		OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory",
15988c2ecf20Sopenharmony_ci			   "guest mount directory under which every guest os"
15998c2ecf20Sopenharmony_ci			   " instance has a subdir"),
16008c2ecf20Sopenharmony_ci		OPT_STRING(0, "guestvmlinux", &symbol_conf.default_guest_vmlinux_name,
16018c2ecf20Sopenharmony_ci			   "file", "file saving guest os vmlinux"),
16028c2ecf20Sopenharmony_ci		OPT_STRING(0, "guestkallsyms", &symbol_conf.default_guest_kallsyms,
16038c2ecf20Sopenharmony_ci			   "file", "file saving guest os /proc/kallsyms"),
16048c2ecf20Sopenharmony_ci		OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules,
16058c2ecf20Sopenharmony_ci			   "file", "file saving guest os /proc/modules"),
16068c2ecf20Sopenharmony_ci		OPT_INCR('v', "verbose", &verbose,
16078c2ecf20Sopenharmony_ci			    "be more verbose (show counter open errors, etc)"),
16088c2ecf20Sopenharmony_ci		OPT_END()
16098c2ecf20Sopenharmony_ci	};
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_ci	const char *const kvm_subcommands[] = { "top", "record", "report", "diff",
16128c2ecf20Sopenharmony_ci						"buildid-list", "stat", NULL };
16138c2ecf20Sopenharmony_ci	const char *kvm_usage[] = { NULL, NULL };
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci	perf_host  = 0;
16168c2ecf20Sopenharmony_ci	perf_guest = 1;
16178c2ecf20Sopenharmony_ci
16188c2ecf20Sopenharmony_ci	argc = parse_options_subcommand(argc, argv, kvm_options, kvm_subcommands, kvm_usage,
16198c2ecf20Sopenharmony_ci					PARSE_OPT_STOP_AT_NON_OPTION);
16208c2ecf20Sopenharmony_ci	if (!argc)
16218c2ecf20Sopenharmony_ci		usage_with_options(kvm_usage, kvm_options);
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_ci	if (!perf_host)
16248c2ecf20Sopenharmony_ci		perf_guest = 1;
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci	if (!file_name) {
16278c2ecf20Sopenharmony_ci		file_name = get_filename_for_perf_kvm();
16288c2ecf20Sopenharmony_ci
16298c2ecf20Sopenharmony_ci		if (!file_name) {
16308c2ecf20Sopenharmony_ci			pr_err("Failed to allocate memory for filename\n");
16318c2ecf20Sopenharmony_ci			return -ENOMEM;
16328c2ecf20Sopenharmony_ci		}
16338c2ecf20Sopenharmony_ci	}
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci	if (!strncmp(argv[0], "rec", 3))
16368c2ecf20Sopenharmony_ci		return __cmd_record(file_name, argc, argv);
16378c2ecf20Sopenharmony_ci	else if (!strncmp(argv[0], "rep", 3))
16388c2ecf20Sopenharmony_ci		return __cmd_report(file_name, argc, argv);
16398c2ecf20Sopenharmony_ci	else if (!strncmp(argv[0], "diff", 4))
16408c2ecf20Sopenharmony_ci		return cmd_diff(argc, argv);
16418c2ecf20Sopenharmony_ci	else if (!strncmp(argv[0], "top", 3))
16428c2ecf20Sopenharmony_ci		return cmd_top(argc, argv);
16438c2ecf20Sopenharmony_ci	else if (!strncmp(argv[0], "buildid-list", 12))
16448c2ecf20Sopenharmony_ci		return __cmd_buildid_list(file_name, argc, argv);
16458c2ecf20Sopenharmony_ci#ifdef HAVE_KVM_STAT_SUPPORT
16468c2ecf20Sopenharmony_ci	else if (!strncmp(argv[0], "stat", 4))
16478c2ecf20Sopenharmony_ci		return kvm_cmd_stat(file_name, argc, argv);
16488c2ecf20Sopenharmony_ci#endif
16498c2ecf20Sopenharmony_ci	else
16508c2ecf20Sopenharmony_ci		usage_with_options(kvm_usage, kvm_options);
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci	return 0;
16538c2ecf20Sopenharmony_ci}
1654