|
@@ -88,7 +88,7 @@ void exit_event_decode_key(struct perf_kvm_stat *kvm,
|
|
|
struct event_key *key,
|
|
|
char *decode)
|
|
|
{
|
|
|
- const char *exit_reason = get_exit_reason(kvm, kvm->exit_reasons,
|
|
|
+ const char *exit_reason = get_exit_reason(kvm, key->exit_reasons,
|
|
|
key->key);
|
|
|
|
|
|
scnprintf(decode, DECODE_STR_LEN, "%s", exit_reason);
|
|
@@ -261,6 +261,43 @@ static bool update_kvm_event(struct kvm_event *event, int vcpu_id,
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+static bool is_child_event(struct perf_kvm_stat *kvm,
|
|
|
+ struct perf_evsel *evsel,
|
|
|
+ struct perf_sample *sample,
|
|
|
+ struct event_key *key)
|
|
|
+{
|
|
|
+ struct child_event_ops *child_ops;
|
|
|
+
|
|
|
+ child_ops = kvm->events_ops->child_ops;
|
|
|
+
|
|
|
+ if (!child_ops)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ for (; child_ops->name; child_ops++) {
|
|
|
+ if (!strcmp(evsel->name, child_ops->name)) {
|
|
|
+ child_ops->get_key(evsel, sample, key);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+static bool handle_child_event(struct perf_kvm_stat *kvm,
|
|
|
+ struct vcpu_event_record *vcpu_record,
|
|
|
+ struct event_key *key,
|
|
|
+ struct perf_sample *sample __maybe_unused)
|
|
|
+{
|
|
|
+ struct kvm_event *event = NULL;
|
|
|
+
|
|
|
+ if (key->key != INVALID_KEY)
|
|
|
+ event = find_create_kvm_event(kvm, key);
|
|
|
+
|
|
|
+ vcpu_record->last_event = event;
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
static bool skip_event(const char *event)
|
|
|
{
|
|
|
const char * const *skip_events;
|
|
@@ -361,7 +398,8 @@ static bool handle_kvm_event(struct perf_kvm_stat *kvm,
|
|
|
struct perf_sample *sample)
|
|
|
{
|
|
|
struct vcpu_event_record *vcpu_record;
|
|
|
- struct event_key key = {.key = INVALID_KEY};
|
|
|
+ struct event_key key = { .key = INVALID_KEY,
|
|
|
+ .exit_reasons = kvm->exit_reasons };
|
|
|
|
|
|
vcpu_record = per_vcpu_record(thread, evsel, sample);
|
|
|
if (!vcpu_record)
|
|
@@ -375,6 +413,9 @@ static bool handle_kvm_event(struct perf_kvm_stat *kvm,
|
|
|
if (kvm->events_ops->is_begin_event(evsel, sample, &key))
|
|
|
return handle_begin_event(kvm, vcpu_record, &key, sample->time);
|
|
|
|
|
|
+ if (is_child_event(kvm, evsel, sample, &key))
|
|
|
+ return handle_child_event(kvm, vcpu_record, &key, sample);
|
|
|
+
|
|
|
if (kvm->events_ops->is_end_event(evsel, sample, &key))
|
|
|
return handle_end_event(kvm, vcpu_record, &key, sample);
|
|
|
|
|
@@ -1143,7 +1184,8 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
|
|
|
{
|
|
|
const struct option kvm_events_report_options[] = {
|
|
|
OPT_STRING(0, "event", &kvm->report_event, "report event",
|
|
|
- "event for reporting: vmexit, mmio, ioport"),
|
|
|
+ "event for reporting: vmexit, "
|
|
|
+ "mmio (x86 only), ioport (x86 only)"),
|
|
|
OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu,
|
|
|
"vcpu id to report"),
|
|
|
OPT_STRING('k', "key", &kvm->sort_key, "sort-key",
|
|
@@ -1249,7 +1291,9 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
|
|
|
"key for sorting: sample(sort by samples number)"
|
|
|
" time (sort by avg time)"),
|
|
|
OPT_U64(0, "duration", &kvm->duration,
|
|
|
- "show events other than HALT that take longer than duration usecs"),
|
|
|
+ "show events other than"
|
|
|
+ " HLT (x86 only) or Wait state (s390 only)"
|
|
|
+ " that take longer than duration usecs"),
|
|
|
OPT_END()
|
|
|
};
|
|
|
const char * const live_usage[] = {
|