* [RFC 0/5] accel/kvm: Support KVM PMU filter
@ 2024-07-10 4:51 Zhao Liu
2024-07-10 4:51 ` [RFC 1/5] qapi/qom: Introduce kvm-pmu-filter object Zhao Liu
` (6 more replies)
0 siblings, 7 replies; 15+ messages in thread
From: Zhao Liu @ 2024-07-10 4:51 UTC (permalink / raw)
To: Paolo Bonzini, Eric Blake, Markus Armbruster, Michael Roth,
Daniel P . Berrangé, Eduardo Habkost, Marcelo Tosatti,
Shaoqin Huang, Eric Auger, Peter Maydell, Laurent Vivier,
Thomas Huth, Sebastian Ott, Gavin Shan
Cc: qemu-devel, kvm, qemu-arm, Zhenyu Wang, Dapeng Mi, Yuan Yao,
Xiong Zhang, Mingwei Zhang, Jim Mattson, Zhao Liu
Hi QEMU maintainers, arm and PMU folks,
I picked up Shaoqing's previous work [1] on the KVM PMU filter for arm,
and now is trying to support this feature for x86 with a JSON-compatible
API.
While arm and x86 use different KVM ioctls to configure the PMU filter,
considering they all have similar inputs (PMU event + action), it is
still possible to abstract a generic, cross-architecture kvm-pmu-filter
object and provide users with a sufficiently generic or near-consistent
QAPI interface.
That's what I did in this series, a new kvm-pmu-filter object, with the
API like:
-object '{"qom-type":"kvm-pmu-filter","id":"f0","events":[{"action":"allow","format":"raw","code":"0xc4"}]}'
For i386, this object is inserted into kvm accelerator and is extended
to support fixed-counter and more formats ("x86-default" and
"x86-masked-entry"):
-accel kvm,pmu-filter=f0 \
-object pmu='{"qom-type":"kvm-pmu-filter","id":"f0","x86-fixed-counter":{"action":"allow","bitmap":"0x0"},"events":[{"action":"allow","format":"x86-masked-entry","select":"0xc4","mask":"0xff","match":"0","exclude":true},{"action":"allow","format":"x86-masked-entry","select":"0xc5","mask":"0xff","match":"0","exclude":true}]}'
This object can still be added as the property to the arch CPU if it is
desired as a per CPU feature (as Shaoqin did for arm before).
Welcome your feedback and comments!
Introduction
============
Formats supported in kvm-pmu-filter
-----------------------------------
This series supports 3 formats:
* raw format (general format).
This format indicates the code that has been encoded to be able to
index the PMU events, and which can be delivered directly to the KVM
ioctl. For arm, this means the event code, and for i386, this means
the raw event with the layout like:
select high bit | umask | select low bits
* x86-default format (i386 specific)
x86 commonly uses select&umask to identify PMU events, and this format
is used to support the select&umask. Then QEMU will encode select and
umask into a raw format code.
* x86-masked-entry (i386 specific)
This is a special format that x86's KVM_SET_PMU_EVENT_FILTER supports.
Hexadecimal value string
------------------------
In practice, the values associated with PMU events (code for arm, select&
umask for x86) are often expressed in hexadecimal. Further, from linux
perf related information (tools/perf/pmu-events/arch/*/*/*.json), x86/
arm64/riscv/nds32/powerpc all prefer the hexadecimal numbers and only
s390 uses decimal value.
Therefore, it is necessary to support hexadecimal in order to honor PMU
conventions.
However, unfortunately, standard JSON (RFC 8259) does not support
hexadecimal numbers. So I can only consider using the numeric string in
the QAPI and then parsing it to a number.
To achieve this, I defined two versions of PMU-related structures in
kvm.json:
* a native version that accepts numeric values, which is used for
QEMU's internal code processing,
* and a variant version that accepts numeric string, which is used to
receive user input.
kvm-pmu-filter object will take care of converting the string version
of the event/counter information into the numeric version.
The related implementation can be found in patch 1.
CPU property v.s. KVM property
------------------------------
In Shaoqin's previous implementation [1], KVM PMU filter is made as a
arm CPU property. This is because arm uses a per CPU ioctl
(KVM_SET_DEVICE_ATTR) to configure KVM PMU filter.
However, for x86, the dependent ioctl (KVM_SET_PMU_EVENT_FILTER) is per
VM. In the meantime, considering that for hybrid architecture, maybe in
the future there will be a new per vCPU ioctl, or there will be
practices to support filter fixed counter by configuring CPUIDs.
Based on the above thoughts, for x86, it is not appropriate to make the
current per-VM ioctl-based PMU filter a CPU property. Instead, I make it
a kvm property and configure it via "-accel kvm,pmu-filter=obj_id".
So in summary, it is feasible to use the KVM PMU filter as either a CPU
or a KVM property, depending on whether it is used as a CPU feature or a
VM feature.
The kvm-pmu-filter object, as an abstraction, is general enough to
support filter configurations for different scopes (per-CPU or per-VM).
[1]: https://lore.kernel.org/qemu-devel/20240409024940.180107-1-shahuang@redhat.com/
Thanks and Best Regards,
Zhao
---
Zhao Liu (5):
qapi/qom: Introduce kvm-pmu-filter object
i386/kvm: Support initial KVM PMU filter
i386/kvm: Support event with select&umask format in KVM PMU filter
i386/kvm: Support event with masked entry format in KVM PMU filter
i386/kvm: Support fixed counter in KVM PMU filter
MAINTAINERS | 1 +
accel/kvm/kvm-pmu.c | 367 +++++++++++++++++++++++++++++++++++++
accel/kvm/meson.build | 1 +
include/sysemu/kvm-pmu.h | 43 +++++
include/sysemu/kvm_int.h | 2 +
qapi/kvm.json | 255 ++++++++++++++++++++++++++
qapi/meson.build | 1 +
qapi/qapi-schema.json | 1 +
qapi/qom.json | 3 +
target/i386/kvm/kvm.c | 211 +++++++++++++++++++++
target/i386/kvm/kvm_i386.h | 1 +
11 files changed, 886 insertions(+)
create mode 100644 accel/kvm/kvm-pmu.c
create mode 100644 include/sysemu/kvm-pmu.h
create mode 100644 qapi/kvm.json
--
2.34.1
^ permalink raw reply [flat|nested] 15+ messages in thread
* [RFC 1/5] qapi/qom: Introduce kvm-pmu-filter object
2024-07-10 4:51 [RFC 0/5] accel/kvm: Support KVM PMU filter Zhao Liu
@ 2024-07-10 4:51 ` Zhao Liu
2024-07-10 4:51 ` [RFC 2/5] i386/kvm: Support initial KVM PMU filter Zhao Liu
` (5 subsequent siblings)
6 siblings, 0 replies; 15+ messages in thread
From: Zhao Liu @ 2024-07-10 4:51 UTC (permalink / raw)
To: Paolo Bonzini, Eric Blake, Markus Armbruster, Michael Roth,
Daniel P . Berrangé, Eduardo Habkost, Marcelo Tosatti,
Shaoqin Huang, Eric Auger, Peter Maydell, Laurent Vivier,
Thomas Huth, Sebastian Ott, Gavin Shan
Cc: qemu-devel, kvm, qemu-arm, Zhenyu Wang, Dapeng Mi, Yuan Yao,
Xiong Zhang, Mingwei Zhang, Jim Mattson, Zhao Liu
Introduce the kvm-pmu-filter object and support the PMU event with raw
format.
The raw format, as a native PMU event code representation, can be used
for several architectures.
Considering that PMU event related fields are commonly used in
hexadecimal, define KVMPMURawEventVariant, KVMPMUFilterEventVariant, and
KVMPMUFilterPropertyVariant in kvm.json to support hexadecimal number
strings in JSON.
Additionally, define the corresponding numeric versions of
KVMPMURawEvent, KVMPMUFilterEvent, and KVMPMUFilterProperty in kvm.json.
This allows to handle numeric values more effectively and take advantage
of the qapi helpers.
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
---
MAINTAINERS | 1 +
accel/kvm/kvm-pmu.c | 143 +++++++++++++++++++++++++++++++++++++++
accel/kvm/meson.build | 1 +
include/sysemu/kvm-pmu.h | 29 ++++++++
qapi/kvm.json | 119 ++++++++++++++++++++++++++++++++
qapi/meson.build | 1 +
qapi/qapi-schema.json | 1 +
qapi/qom.json | 3 +
8 files changed, 298 insertions(+)
create mode 100644 accel/kvm/kvm-pmu.c
create mode 100644 include/sysemu/kvm-pmu.h
create mode 100644 qapi/kvm.json
diff --git a/MAINTAINERS b/MAINTAINERS
index 6725913c8b3a..8c36c04a3eb2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -439,6 +439,7 @@ F: accel/kvm/
F: accel/stubs/kvm-stub.c
F: include/hw/kvm/
F: include/sysemu/kvm*.h
+F: qapi/kvm.json
F: scripts/kvm/kvm_flightrecorder
ARM KVM CPUs
diff --git a/accel/kvm/kvm-pmu.c b/accel/kvm/kvm-pmu.c
new file mode 100644
index 000000000000..483d1bdf4807
--- /dev/null
+++ b/accel/kvm/kvm-pmu.c
@@ -0,0 +1,143 @@
+/*
+ * QEMU KVM PMU Abstractions
+ *
+ * Copyright (C) 2024 Intel Corporation.
+ *
+ * Author: Zhao Liu <zhao1.liu@intel.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later. See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "qapi/error.h"
+#include "qapi/qapi-visit-kvm.h"
+#include "qemu/cutils.h"
+#include "qom/object_interfaces.h"
+#include "sysemu/kvm-pmu.h"
+
+static void kvm_pmu_filter_get_event(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ KVMPMUFilter *filter = KVM_PMU_FILTER(obj);
+ KVMPMUFilterEventList *node;
+ KVMPMUFilterEventVariantList *head = NULL;
+ KVMPMUFilterEventVariantList **tail = &head;
+
+ for (node = filter->events; node; node = node->next) {
+ KVMPMUFilterEventVariant *str_event;
+ KVMPMUFilterEvent *event = node->value;
+
+ str_event = g_new(KVMPMUFilterEventVariant, 1);
+ str_event->action = event->action;
+ str_event->format = event->format;
+
+ switch (event->format) {
+ case KVM_PMU_EVENT_FMT_RAW:
+ str_event->u.raw.code = g_strdup_printf("0x%lx",
+ event->u.raw.code);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ QAPI_LIST_APPEND(tail, str_event);
+ }
+
+ visit_type_KVMPMUFilterEventVariantList(v, name, &head, errp);
+ qapi_free_KVMPMUFilterEventVariantList(head);
+}
+
+static void kvm_pmu_filter_set_event(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ KVMPMUFilter *filter = KVM_PMU_FILTER(obj);
+ KVMPMUFilterEventVariantList *list, *node;
+ KVMPMUFilterEventList *head = NULL, *old_head;
+ KVMPMUFilterEventList **tail = &head;
+ int ret, nevents = 0;
+
+ if (!visit_type_KVMPMUFilterEventVariantList(v, name, &list, errp)) {
+ return;
+ }
+
+ for (node = list; node; node = node->next) {
+ KVMPMUFilterEvent *event = g_new(KVMPMUFilterEvent, 1);
+ KVMPMUFilterEventVariant *str_event = node->value;
+
+ event->action = str_event->action;
+ event->format = str_event->format;
+
+ switch (str_event->format) {
+ case KVM_PMU_EVENT_FMT_RAW:
+ ret = qemu_strtou64(str_event->u.raw.code, NULL,
+ 0, &event->u.raw.code);
+ if (ret < 0) {
+ error_setg(errp,
+ "Invalid %s PMU event (code: %s): %s. "
+ "The code must be a uint64 string.",
+ KVMPMUEventEncodeFmt_str(str_event->format),
+ str_event->u.raw.code, strerror(-ret));
+ g_free(event);
+ goto fail;
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ nevents++;
+ QAPI_LIST_APPEND(tail, event);
+ }
+
+ old_head = filter->events;
+ filter->events = head;
+ filter->nevents = nevents;
+
+ qapi_free_KVMPMUFilterEventVariantList(list);
+ qapi_free_KVMPMUFilterEventList(old_head);
+ return;
+
+fail:
+ qapi_free_KVMPMUFilterEventList(head);
+}
+
+static void
+kvm_pmu_filter_class_init(ObjectClass *oc, void *data)
+{
+ object_class_property_add(oc, "events",
+ "KVMPMUFilterEvent",
+ kvm_pmu_filter_get_event,
+ kvm_pmu_filter_set_event,
+ NULL, NULL);
+ object_class_property_set_description(oc, "events",
+ "KVM PMU event list");
+}
+
+static void kvm_pmu_filter_instance_init(Object *obj)
+{
+ KVMPMUFilter *filter = KVM_PMU_FILTER(obj);
+
+ filter->nevents = 0;
+}
+
+static const TypeInfo kvm_pmu_filter_info = {
+ .parent = TYPE_OBJECT,
+ .name = TYPE_KVM_PMU_FILTER,
+ .class_init = kvm_pmu_filter_class_init,
+ .instance_size = sizeof(KVMPMUFilter),
+ .instance_init = kvm_pmu_filter_instance_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_USER_CREATABLE },
+ { }
+ }
+};
+
+static void
+kvm_pmu_event_register_type(void)
+{
+ type_register_static(&kvm_pmu_filter_info);
+}
+
+type_init(kvm_pmu_event_register_type);
diff --git a/accel/kvm/meson.build b/accel/kvm/meson.build
index 397a1fe1fd1e..dfab2854f3a8 100644
--- a/accel/kvm/meson.build
+++ b/accel/kvm/meson.build
@@ -2,6 +2,7 @@ kvm_ss = ss.source_set()
kvm_ss.add(files(
'kvm-all.c',
'kvm-accel-ops.c',
+ 'kvm-pmu.c',
))
specific_ss.add_all(when: 'CONFIG_KVM', if_true: kvm_ss)
diff --git a/include/sysemu/kvm-pmu.h b/include/sysemu/kvm-pmu.h
new file mode 100644
index 000000000000..4707759761f1
--- /dev/null
+++ b/include/sysemu/kvm-pmu.h
@@ -0,0 +1,29 @@
+/*
+ * QEMU KVM PMU Abstraction Header
+ *
+ * Copyright (C) 2024 Intel Corporation.
+ *
+ * Authors:
+ * Zhao Liu <zhao1.liu@intel.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later. See the COPYING file in the top-level directory.
+ */
+
+#ifndef KVM_PMU_H
+#define KVM_PMU_H
+
+#include "qapi/qapi-types-kvm.h"
+#include "qom/object.h"
+
+#define TYPE_KVM_PMU_FILTER "kvm-pmu-filter"
+OBJECT_DECLARE_SIMPLE_TYPE(KVMPMUFilter, KVM_PMU_FILTER)
+
+struct KVMPMUFilter {
+ Object parent_obj;
+
+ uint32_t nevents;
+ KVMPMUFilterEventList *events;
+};
+
+#endif /* KVM_PMU_H */
diff --git a/qapi/kvm.json b/qapi/kvm.json
new file mode 100644
index 000000000000..0619da83c123
--- /dev/null
+++ b/qapi/kvm.json
@@ -0,0 +1,119 @@
+# -*- Mode: Python -*-
+# vim: filetype=python
+
+##
+# = KVM based feature API
+##
+
+##
+# @KVMPMUFilterAction:
+#
+# Actions that KVM PMU filter supports.
+#
+# @deny: disable the PMU event/counter in KVM PMU filter
+#
+# @allow: enable the PMU event/counter in KVM PMU filter
+#
+# Since 9.1
+##
+{ 'enum': 'KVMPMUFilterAction',
+ 'prefix': 'KVM_PMU_FILTER_ACTION',
+ 'data': ['allow', 'deny'] }
+
+##
+# @KVMPMUEventEncodeFmt:
+#
+# Encoding formats of PMU event that QEMU/KVM supports.
+#
+# @raw: the encoded event code that KVM can directly consume.
+#
+# Since 9.1
+##
+{ 'enum': 'KVMPMUEventEncodeFmt',
+ 'prefix': 'KVM_PMU_EVENT_FMT',
+ 'data': ['raw'] }
+
+##
+# @KVMPMURawEvent:
+#
+# Raw PMU event code.
+#
+# @code: the raw value that has been encoded, and QEMU could deliver
+# to KVM directly.
+#
+# Since 9.1
+##
+{ 'struct': 'KVMPMURawEvent',
+ 'data': { 'code': 'uint64' } }
+
+##
+# @KVMPMUFilterEvent:
+#
+# PMU event filtered by KVM.
+#
+# @action: action that KVM PMU filter will take.
+#
+# @format: PMU event format.
+#
+# Since 9.1
+##
+{ 'union': 'KVMPMUFilterEvent',
+ 'base': { 'action': 'KVMPMUFilterAction',
+ 'format': 'KVMPMUEventEncodeFmt' },
+ 'discriminator': 'format',
+ 'data': { 'raw': 'KVMPMURawEvent' } }
+
+##
+# @KVMPMUFilterProperty:
+#
+# Property of KVM PMU Filter.
+#
+# @events: the KVMPMUFilterEvent list.
+#
+# Since 9.1
+##
+{ 'struct': 'KVMPMUFilterProperty',
+ 'data': { '*events': ['KVMPMUFilterEvent'] } }
+
+##
+# @KVMPMURawEventVariant:
+#
+# The variant of KVMPMURawEvent with the string, rather than the
+# numeric value.
+#
+# @code: the raw value that has been encoded, and QEMU could deliver
+# to KVM directly. This field is a uint64 string.
+#
+# Since 9.1
+##
+{ 'struct': 'KVMPMURawEventVariant',
+ 'data': { 'code': 'str' } }
+
+##
+# @KVMPMUFilterEventVariant:
+#
+# The variant of KVMPMUFilterEvent.
+#
+# @action: action that KVM PMU filter will take.
+#
+# @format: PMU event format.
+#
+# Since 9.1
+##
+{ 'union': 'KVMPMUFilterEventVariant',
+ 'base': { 'action': 'KVMPMUFilterAction',
+ 'format': 'KVMPMUEventEncodeFmt' },
+ 'discriminator': 'format',
+ 'data': { 'raw': 'KVMPMURawEventVariant' } }
+
+##
+# @KVMPMUFilterPropertyVariant:
+#
+# The variant of KVMPMUFilterProperty.
+#
+# @events: the KVMPMUFilterEventVariant list.
+#
+# Since 9.1
+##
+{ 'struct': 'KVMPMUFilterPropertyVariant',
+ 'data': { '*events': ['KVMPMUFilterEventVariant'] } }
diff --git a/qapi/meson.build b/qapi/meson.build
index e7bc54e5d047..856439c76b67 100644
--- a/qapi/meson.build
+++ b/qapi/meson.build
@@ -37,6 +37,7 @@ qapi_all_modules = [
'error',
'introspect',
'job',
+ 'kvm',
'machine-common',
'machine',
'machine-target',
diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json
index b1581988e4eb..742818d16e45 100644
--- a/qapi/qapi-schema.json
+++ b/qapi/qapi-schema.json
@@ -64,6 +64,7 @@
{ 'include': 'compat.json' }
{ 'include': 'control.json' }
{ 'include': 'introspect.json' }
+{ 'include': 'kvm.json' }
{ 'include': 'qom.json' }
{ 'include': 'qdev.json' }
{ 'include': 'machine-common.json' }
diff --git a/qapi/qom.json b/qapi/qom.json
index 92b0fea76cb1..40175a97b4dd 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -8,6 +8,7 @@
{ 'include': 'block-core.json' }
{ 'include': 'common.json' }
{ 'include': 'crypto.json' }
+{ 'include': 'kvm.json' }
##
# = QEMU Object Model (QOM)
@@ -1057,6 +1058,7 @@
'if': 'CONFIG_LINUX' },
'iommufd',
'iothread',
+ 'kvm-pmu-filter',
'main-loop',
{ 'name': 'memory-backend-epc',
'if': 'CONFIG_LINUX' },
@@ -1131,6 +1133,7 @@
'if': 'CONFIG_LINUX' },
'iommufd': 'IOMMUFDProperties',
'iothread': 'IothreadProperties',
+ 'kvm-pmu-filter': 'KVMPMUFilterPropertyVariant',
'main-loop': 'MainLoopProperties',
'memory-backend-epc': { 'type': 'MemoryBackendEpcProperties',
'if': 'CONFIG_LINUX' },
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [RFC 2/5] i386/kvm: Support initial KVM PMU filter
2024-07-10 4:51 [RFC 0/5] accel/kvm: Support KVM PMU filter Zhao Liu
2024-07-10 4:51 ` [RFC 1/5] qapi/qom: Introduce kvm-pmu-filter object Zhao Liu
@ 2024-07-10 4:51 ` Zhao Liu
2024-07-10 4:51 ` [RFC 3/5] i386/kvm: Support event with select&umask format in " Zhao Liu
` (4 subsequent siblings)
6 siblings, 0 replies; 15+ messages in thread
From: Zhao Liu @ 2024-07-10 4:51 UTC (permalink / raw)
To: Paolo Bonzini, Eric Blake, Markus Armbruster, Michael Roth,
Daniel P . Berrangé, Eduardo Habkost, Marcelo Tosatti,
Shaoqin Huang, Eric Auger, Peter Maydell, Laurent Vivier,
Thomas Huth, Sebastian Ott, Gavin Shan
Cc: qemu-devel, kvm, qemu-arm, Zhenyu Wang, Dapeng Mi, Yuan Yao,
Xiong Zhang, Mingwei Zhang, Jim Mattson, Zhao Liu
Filter PMU events with raw format in i386 code.
For i386, raw format indicates that the PMU event code is already
encoded according to the KVM ioctl requirements, and can be delivered
directly to KVM without additional encoding work.
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
---
include/sysemu/kvm_int.h | 2 +
target/i386/kvm/kvm.c | 144 +++++++++++++++++++++++++++++++++++++
target/i386/kvm/kvm_i386.h | 1 +
3 files changed, 147 insertions(+)
diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h
index 3f3d13f81669..9ab566cb4494 100644
--- a/include/sysemu/kvm_int.h
+++ b/include/sysemu/kvm_int.h
@@ -14,6 +14,7 @@
#include "qemu/accel.h"
#include "qemu/queue.h"
#include "sysemu/kvm.h"
+#include "sysemu/kvm-pmu.h"
typedef struct KVMSlot
{
@@ -124,6 +125,7 @@ struct KVMState
uint16_t xen_gnttab_max_frames;
uint16_t xen_evtchn_max_pirq;
char *device;
+ KVMPMUFilter *pmu_filter;
};
void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml,
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index becca2efa5b4..e9bf79782316 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -30,6 +30,7 @@
#include "sysemu/sysemu.h"
#include "sysemu/hw_accel.h"
#include "sysemu/kvm_int.h"
+#include "sysemu/kvm-pmu.h"
#include "sysemu/runstate.h"
#include "kvm_i386.h"
#include "../confidential-guest.h"
@@ -2806,6 +2807,16 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
}
}
+ if (s->pmu_filter) {
+ bool r;
+
+ r = kvm_filter_pmu_event(s);
+ if (!r) {
+ error_report("Could not set KVM PMU filter");
+ exit(1);
+ }
+ }
+
return 0;
}
@@ -5363,6 +5374,91 @@ static int kvm_handle_wrmsr(X86CPU *cpu, struct kvm_run *run)
assert(false);
}
+static bool
+kvm_config_pmu_event(KVMPMUFilter *filter,
+ struct kvm_pmu_event_filter *kvm_filter)
+{
+ KVMPMUFilterEventList *events;
+ KVMPMUFilterEvent *event;
+ uint64_t code;
+ int idx = 0;
+
+ kvm_filter->nevents = filter->nevents;
+ events = filter->events;
+ while (events) {
+ assert(idx < kvm_filter->nevents);
+
+ event = events->value;
+ switch (event->format) {
+ case KVM_PMU_EVENT_FMT_RAW:
+ code = event->u.raw.code;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ kvm_filter->events[idx++] = code;
+ events = events->next;
+ }
+
+ return true;
+}
+
+static bool kvm_install_pmu_event_filter(KVMState *s)
+{
+ struct kvm_pmu_event_filter *kvm_filter;
+ KVMPMUFilter *filter = s->pmu_filter;
+ int ret;
+
+ kvm_filter = g_malloc0(sizeof(struct kvm_pmu_event_filter) +
+ filter->nevents * sizeof(uint64_t));
+
+ /*
+ * Currently, kvm-pmu-filter only supports configuring the same
+ * action for PMU events.
+ */
+ switch (filter->events->value->action) {
+ case KVM_PMU_FILTER_ACTION_ALLOW:
+ kvm_filter->action = KVM_PMU_EVENT_ALLOW;
+ break;
+ case KVM_PMU_FILTER_ACTION_DENY:
+ kvm_filter->action = KVM_PMU_EVENT_DENY;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (!kvm_config_pmu_event(filter, kvm_filter)) {
+ goto fail;
+ }
+
+ ret = kvm_vm_ioctl(s, KVM_SET_PMU_EVENT_FILTER, kvm_filter);
+ if (ret) {
+ error_report("KVM_SET_PMU_EVENT_FILTER fails (%s)", strerror(-ret));
+ goto fail;
+ }
+
+ g_free(kvm_filter);
+ return true;
+fail:
+ g_free(kvm_filter);
+ return false;
+}
+
+bool kvm_filter_pmu_event(KVMState *s)
+{
+ if (!kvm_vm_check_extension(s, KVM_CAP_PMU_EVENT_FILTER)) {
+ error_report("KVM PMU filter is not supported by Host.");
+ return false;
+ }
+
+ if (!kvm_install_pmu_event_filter(s)) {
+ return false;
+ }
+
+ return true;
+}
+
static bool has_sgx_provisioning;
static bool __kvm_enable_sgx_provisioning(KVMState *s)
@@ -5958,6 +6054,46 @@ static void kvm_arch_set_xen_evtchn_max_pirq(Object *obj, Visitor *v,
s->xen_evtchn_max_pirq = value;
}
+static void kvm_arch_check_pmu_filter(const Object *obj, const char *name,
+ Object *child, Error **errp)
+{
+ KVMPMUFilter *filter = KVM_PMU_FILTER(child);
+ KVMPMUFilterEventList *events = filter->events;
+ KVMPMUFilterAction action;
+
+ if (!filter->nevents) {
+ error_setg(errp,
+ "Empty KVM PMU filter.");
+ return;
+ }
+
+ action = KVM_PMU_FILTER_ACTION__MAX;
+ while (events) {
+ KVMPMUFilterEvent *event = events->value;
+
+ switch (event->format) {
+ case KVM_PMU_EVENT_FMT_RAW:
+ break;
+ default:
+ error_setg(errp,
+ "Unsupported PMU event format %s.",
+ KVMPMUEventEncodeFmt_str(events->value->format));
+ return;
+ }
+
+ if (action == KVM_PMU_FILTER_ACTION__MAX) {
+ action = event->action;
+ } else if (action != event->action) {
+ /* TODO: Support events with different actions if necessary. */
+ error_setg(errp,
+ "Only support PMU events with the same action");
+ return;
+ }
+
+ events = events->next;
+ }
+}
+
void kvm_arch_accel_class_init(ObjectClass *oc)
{
object_class_property_add_enum(oc, "notify-vmexit", "NotifyVMexitOption",
@@ -5997,6 +6133,14 @@ void kvm_arch_accel_class_init(ObjectClass *oc)
NULL, NULL);
object_class_property_set_description(oc, "xen-evtchn-max-pirq",
"Maximum number of Xen PIRQs");
+
+ object_class_property_add_link(oc, "pmu-filter",
+ TYPE_KVM_PMU_FILTER,
+ offsetof(KVMState, pmu_filter),
+ kvm_arch_check_pmu_filter,
+ OBJ_PROP_LINK_STRONG);
+ object_class_property_set_description(oc, "pmu-filter",
+ "Set the KVM PMU filter");
}
void kvm_set_max_apic_id(uint32_t max_apic_id)
diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h
index 34fc60774b86..5cdc7106424d 100644
--- a/target/i386/kvm/kvm_i386.h
+++ b/target/i386/kvm/kvm_i386.h
@@ -76,6 +76,7 @@ typedef struct kvm_msr_handlers {
bool kvm_filter_msr(KVMState *s, uint32_t msr, QEMURDMSRHandler *rdmsr,
QEMUWRMSRHandler *wrmsr);
+bool kvm_filter_pmu_event(KVMState *s);
#endif /* CONFIG_KVM */
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [RFC 3/5] i386/kvm: Support event with select&umask format in KVM PMU filter
2024-07-10 4:51 [RFC 0/5] accel/kvm: Support KVM PMU filter Zhao Liu
2024-07-10 4:51 ` [RFC 1/5] qapi/qom: Introduce kvm-pmu-filter object Zhao Liu
2024-07-10 4:51 ` [RFC 2/5] i386/kvm: Support initial KVM PMU filter Zhao Liu
@ 2024-07-10 4:51 ` Zhao Liu
2024-07-18 5:28 ` Mi, Dapeng
2024-07-10 4:51 ` [RFC 4/5] i386/kvm: Support event with masked entry " Zhao Liu
` (3 subsequent siblings)
6 siblings, 1 reply; 15+ messages in thread
From: Zhao Liu @ 2024-07-10 4:51 UTC (permalink / raw)
To: Paolo Bonzini, Eric Blake, Markus Armbruster, Michael Roth,
Daniel P . Berrangé, Eduardo Habkost, Marcelo Tosatti,
Shaoqin Huang, Eric Auger, Peter Maydell, Laurent Vivier,
Thomas Huth, Sebastian Ott, Gavin Shan
Cc: qemu-devel, kvm, qemu-arm, Zhenyu Wang, Dapeng Mi, Yuan Yao,
Xiong Zhang, Mingwei Zhang, Jim Mattson, Zhao Liu
The select&umask is the common way for x86 to identify the PMU event,
so support this way as the "x86-default" format in kvm-pmu-filter
object.
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
---
accel/kvm/kvm-pmu.c | 62 ++++++++++++++++++++++++++++++++++++++++
include/sysemu/kvm-pmu.h | 13 +++++++++
qapi/kvm.json | 46 +++++++++++++++++++++++++++--
target/i386/kvm/kvm.c | 5 ++++
4 files changed, 123 insertions(+), 3 deletions(-)
diff --git a/accel/kvm/kvm-pmu.c b/accel/kvm/kvm-pmu.c
index 483d1bdf4807..51d3fba5a72a 100644
--- a/accel/kvm/kvm-pmu.c
+++ b/accel/kvm/kvm-pmu.c
@@ -17,6 +17,8 @@
#include "qom/object_interfaces.h"
#include "sysemu/kvm-pmu.h"
+#define UINT12_MAX (4095)
+
static void kvm_pmu_filter_get_event(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
@@ -38,6 +40,12 @@ static void kvm_pmu_filter_get_event(Object *obj, Visitor *v, const char *name,
str_event->u.raw.code = g_strdup_printf("0x%lx",
event->u.raw.code);
break;
+ case KVM_PMU_EVENT_FMT_X86_DEFAULT:
+ str_event->u.x86_default.select =
+ g_strdup_printf("0x%x", event->u.x86_default.select);
+ str_event->u.x86_default.umask =
+ g_strdup_printf("0x%x", event->u.x86_default.umask);
+ break;
default:
g_assert_not_reached();
}
@@ -83,6 +91,60 @@ static void kvm_pmu_filter_set_event(Object *obj, Visitor *v, const char *name,
goto fail;
}
break;
+ case KVM_PMU_EVENT_FMT_X86_DEFAULT: {
+ uint64_t select, umask;
+
+ ret = qemu_strtou64(str_event->u.x86_default.select, NULL,
+ 0, &select);
+ if (ret < 0) {
+ error_setg(errp,
+ "Invalid %s PMU event (select: %s): %s. "
+ "The select must be a "
+ "12-bit unsigned number string.",
+ KVMPMUEventEncodeFmt_str(str_event->format),
+ str_event->u.x86_default.select,
+ strerror(-ret));
+ g_free(event);
+ goto fail;
+ }
+ if (select > UINT12_MAX) {
+ error_setg(errp,
+ "Invalid %s PMU event (select: %s): "
+ "Numerical result out of range. "
+ "The select must be a "
+ "12-bit unsigned number string.",
+ KVMPMUEventEncodeFmt_str(str_event->format),
+ str_event->u.x86_default.select);
+ g_free(event);
+ goto fail;
+ }
+ event->u.x86_default.select = select;
+
+ ret = qemu_strtou64(str_event->u.x86_default.umask, NULL,
+ 0, &umask);
+ if (ret < 0) {
+ error_setg(errp,
+ "Invalid %s PMU event (umask: %s): %s. "
+ "The umask must be a uint8 string.",
+ KVMPMUEventEncodeFmt_str(str_event->format),
+ str_event->u.x86_default.umask,
+ strerror(-ret));
+ g_free(event);
+ goto fail;
+ }
+ if (umask > UINT8_MAX) {
+ error_setg(errp,
+ "Invalid %s PMU event (umask: %s): "
+ "Numerical result out of range. "
+ "The umask must be a uint8 string.",
+ KVMPMUEventEncodeFmt_str(str_event->format),
+ str_event->u.x86_default.umask);
+ g_free(event);
+ goto fail;
+ }
+ event->u.x86_default.umask = umask;
+ break;
+ }
default:
g_assert_not_reached();
}
diff --git a/include/sysemu/kvm-pmu.h b/include/sysemu/kvm-pmu.h
index 4707759761f1..707f33d604fd 100644
--- a/include/sysemu/kvm-pmu.h
+++ b/include/sysemu/kvm-pmu.h
@@ -26,4 +26,17 @@ struct KVMPMUFilter {
KVMPMUFilterEventList *events;
};
+/*
+ * Stolen from Linux kernel (RAW_EVENT at tools/testing/selftests/kvm/include/
+ * x86_64/pmu.h).
+ *
+ * Encode an eventsel+umask pair into event-select MSR format. Note, this is
+ * technically AMD's format, as Intel's format only supports 8 bits for the
+ * event selector, i.e. doesn't use bits 24:16 for the selector. But, OR-ing
+ * in '0' is a nop and won't clobber the CMASK.
+ */
+#define X86_PMU_RAW_EVENT(eventsel, umask) (((eventsel & 0xf00UL) << 24) | \
+ ((eventsel) & 0xff) | \
+ ((umask) & 0xff) << 8)
+
#endif /* KVM_PMU_H */
diff --git a/qapi/kvm.json b/qapi/kvm.json
index 0619da83c123..0d759884c229 100644
--- a/qapi/kvm.json
+++ b/qapi/kvm.json
@@ -27,11 +27,13 @@
#
# @raw: the encoded event code that KVM can directly consume.
#
+# @x86-default: standard x86 encoding format with select and umask.
+#
# Since 9.1
##
{ 'enum': 'KVMPMUEventEncodeFmt',
'prefix': 'KVM_PMU_EVENT_FMT',
- 'data': ['raw'] }
+ 'data': ['raw', 'x86-default'] }
##
# @KVMPMURawEvent:
@@ -46,6 +48,25 @@
{ 'struct': 'KVMPMURawEvent',
'data': { 'code': 'uint64' } }
+##
+# @KVMPMUX86DefalutEvent:
+#
+# x86 PMU event encoding with select and umask.
+# raw_event = ((select & 0xf00UL) << 24) | \
+# (select) & 0xff) | \
+# ((umask) & 0xff) << 8)
+#
+# @select: x86 PMU event select field, which is a 12-bit unsigned
+# number.
+#
+# @umask: x86 PMU event umask field.
+#
+# Since 9.1
+##
+{ 'struct': 'KVMPMUX86DefalutEvent',
+ 'data': { 'select': 'uint16',
+ 'umask': 'uint8' } }
+
##
# @KVMPMUFilterEvent:
#
@@ -61,7 +82,8 @@
'base': { 'action': 'KVMPMUFilterAction',
'format': 'KVMPMUEventEncodeFmt' },
'discriminator': 'format',
- 'data': { 'raw': 'KVMPMURawEvent' } }
+ 'data': { 'raw': 'KVMPMURawEvent',
+ 'x86-default': 'KVMPMUX86DefalutEvent' } }
##
# @KVMPMUFilterProperty:
@@ -89,6 +111,23 @@
{ 'struct': 'KVMPMURawEventVariant',
'data': { 'code': 'str' } }
+##
+# @KVMPMUX86DefalutEventVariant:
+#
+# The variant of KVMPMUX86DefalutEvent with the string, rather than
+# the numeric value.
+#
+# @select: x86 PMU event select field. This field is a 12-bit
+# unsigned number string.
+#
+# @umask: x86 PMU event umask field. This field is a uint8 string.
+#
+# Since 9.1
+##
+{ 'struct': 'KVMPMUX86DefalutEventVariant',
+ 'data': { 'select': 'str',
+ 'umask': 'str' } }
+
##
# @KVMPMUFilterEventVariant:
#
@@ -104,7 +143,8 @@
'base': { 'action': 'KVMPMUFilterAction',
'format': 'KVMPMUEventEncodeFmt' },
'discriminator': 'format',
- 'data': { 'raw': 'KVMPMURawEventVariant' } }
+ 'data': { 'raw': 'KVMPMURawEventVariant',
+ 'x86-default': 'KVMPMUX86DefalutEventVariant' } }
##
# @KVMPMUFilterPropertyVariant:
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index e9bf79782316..391531c036a6 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -5393,6 +5393,10 @@ kvm_config_pmu_event(KVMPMUFilter *filter,
case KVM_PMU_EVENT_FMT_RAW:
code = event->u.raw.code;
break;
+ case KVM_PMU_EVENT_FMT_X86_DEFAULT:
+ code = X86_PMU_RAW_EVENT(event->u.x86_default.select,
+ event->u.x86_default.umask);
+ break;
default:
g_assert_not_reached();
}
@@ -6073,6 +6077,7 @@ static void kvm_arch_check_pmu_filter(const Object *obj, const char *name,
switch (event->format) {
case KVM_PMU_EVENT_FMT_RAW:
+ case KVM_PMU_EVENT_FMT_X86_DEFAULT:
break;
default:
error_setg(errp,
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [RFC 4/5] i386/kvm: Support event with masked entry format in KVM PMU filter
2024-07-10 4:51 [RFC 0/5] accel/kvm: Support KVM PMU filter Zhao Liu
` (2 preceding siblings ...)
2024-07-10 4:51 ` [RFC 3/5] i386/kvm: Support event with select&umask format in " Zhao Liu
@ 2024-07-10 4:51 ` Zhao Liu
2024-07-10 4:51 ` [RFC 5/5] i386/kvm: Support fixed counter " Zhao Liu
` (2 subsequent siblings)
6 siblings, 0 replies; 15+ messages in thread
From: Zhao Liu @ 2024-07-10 4:51 UTC (permalink / raw)
To: Paolo Bonzini, Eric Blake, Markus Armbruster, Michael Roth,
Daniel P . Berrangé, Eduardo Habkost, Marcelo Tosatti,
Shaoqin Huang, Eric Auger, Peter Maydell, Laurent Vivier,
Thomas Huth, Sebastian Ott, Gavin Shan
Cc: qemu-devel, kvm, qemu-arm, Zhenyu Wang, Dapeng Mi, Yuan Yao,
Xiong Zhang, Mingwei Zhang, Jim Mattson, Zhao Liu
KVM_SET_PMU_EVENT_FILTER of x86 KVM supports masked events mode, which
accepts masked entry format event to flexibly represent a group of PMU
events.
Support masked entry format in kvm-pmu-filter object and handle this in
i386 kvm codes.
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
---
accel/kvm/kvm-pmu.c | 91 +++++++++++++++++++++++++++++++++++++++++++
qapi/kvm.json | 68 ++++++++++++++++++++++++++++++--
target/i386/kvm/kvm.c | 39 +++++++++++++++++++
3 files changed, 195 insertions(+), 3 deletions(-)
diff --git a/accel/kvm/kvm-pmu.c b/accel/kvm/kvm-pmu.c
index 51d3fba5a72a..7a1720c68f8f 100644
--- a/accel/kvm/kvm-pmu.c
+++ b/accel/kvm/kvm-pmu.c
@@ -46,6 +46,16 @@ static void kvm_pmu_filter_get_event(Object *obj, Visitor *v, const char *name,
str_event->u.x86_default.umask =
g_strdup_printf("0x%x", event->u.x86_default.umask);
break;
+ case KVM_PMU_EVENT_FMT_X86_MASKED_ENTRY:
+ str_event->u.x86_masked_entry.select =
+ g_strdup_printf("0x%x", event->u.x86_masked_entry.select);
+ str_event->u.x86_masked_entry.match =
+ g_strdup_printf("0x%x", event->u.x86_masked_entry.match);
+ str_event->u.x86_masked_entry.mask =
+ g_strdup_printf("0x%x", event->u.x86_masked_entry.mask);
+ str_event->u.x86_masked_entry.exclude =
+ event->u.x86_masked_entry.exclude;
+ break;
default:
g_assert_not_reached();
}
@@ -145,6 +155,87 @@ static void kvm_pmu_filter_set_event(Object *obj, Visitor *v, const char *name,
event->u.x86_default.umask = umask;
break;
}
+ case KVM_PMU_EVENT_FMT_X86_MASKED_ENTRY: {
+ uint64_t select, match, mask;
+
+ ret = qemu_strtou64(str_event->u.x86_masked_entry.select,
+ NULL, 0, &select);
+ if (ret < 0) {
+ error_setg(errp,
+ "Invalid %s PMU event (select: %s): %s. "
+ "The select must be a "
+ "12-bit unsigned number string.",
+ KVMPMUEventEncodeFmt_str(str_event->format),
+ str_event->u.x86_masked_entry.select,
+ strerror(-ret));
+ g_free(event);
+ goto fail;
+ }
+ if (select > UINT12_MAX) {
+ error_setg(errp,
+ "Invalid %s PMU event (select: %s): "
+ "Numerical result out of range. "
+ "The select must be a "
+ "12-bit unsigned number string.",
+ KVMPMUEventEncodeFmt_str(str_event->format),
+ str_event->u.x86_masked_entry.select);
+ g_free(event);
+ goto fail;
+ }
+ event->u.x86_masked_entry.select = select;
+
+ ret = qemu_strtou64(str_event->u.x86_masked_entry.match,
+ NULL, 0, &match);
+ if (ret < 0) {
+ error_setg(errp,
+ "Invalid %s PMU event (match: %s): %s. "
+ "The match must be a uint8 string.",
+ KVMPMUEventEncodeFmt_str(str_event->format),
+ str_event->u.x86_masked_entry.match,
+ strerror(-ret));
+ g_free(event);
+ goto fail;
+ }
+ if (match > UINT8_MAX) {
+ error_setg(errp,
+ "Invalid %s PMU event (match: %s): "
+ "Numerical result out of range. "
+ "The match must be a uint8 string.",
+ KVMPMUEventEncodeFmt_str(str_event->format),
+ str_event->u.x86_masked_entry.match);
+ g_free(event);
+ goto fail;
+ }
+ event->u.x86_masked_entry.match = match;
+
+ ret = qemu_strtou64(str_event->u.x86_masked_entry.mask,
+ NULL, 0, &mask);
+ if (ret < 0) {
+ error_setg(errp,
+ "Invalid %s PMU event (mask: %s): %s. "
+ "The mask must be a uint8 string.",
+ KVMPMUEventEncodeFmt_str(str_event->format),
+ str_event->u.x86_masked_entry.mask,
+ strerror(-ret));
+ g_free(event);
+ goto fail;
+ }
+ if (mask > UINT8_MAX) {
+ error_setg(errp,
+ "Invalid %s PMU event (mask: %s): "
+ "Numerical result out of range. "
+ "The mask must be a uint8 string.",
+ KVMPMUEventEncodeFmt_str(str_event->format),
+ str_event->u.x86_masked_entry.mask);
+ g_free(event);
+ goto fail;
+ }
+ event->u.x86_masked_entry.mask = mask;
+
+ event->u.x86_masked_entry.exclude =
+ str_event->u.x86_masked_entry.exclude;
+ break;
+ }
default:
g_assert_not_reached();
}
diff --git a/qapi/kvm.json b/qapi/kvm.json
index 0d759884c229..f4e8854fa6c6 100644
--- a/qapi/kvm.json
+++ b/qapi/kvm.json
@@ -29,11 +29,14 @@
#
# @x86-default: standard x86 encoding format with select and umask.
#
+# @x86-masked-entry: KVM's masked entry format for x86, which could
+# mask bunch of events.
+#
# Since 9.1
##
{ 'enum': 'KVMPMUEventEncodeFmt',
'prefix': 'KVM_PMU_EVENT_FMT',
- 'data': ['raw', 'x86-default'] }
+ 'data': ['raw', 'x86-default', 'x86-masked-entry'] }
##
# @KVMPMURawEvent:
@@ -67,6 +70,40 @@
'data': { 'select': 'uint16',
'umask': 'uint8' } }
+##
+# @KVMPMUX86MaskedEntry:
+#
+# x86 PMU events encoding in KVM masked entry format.
+#
+# Encoding layout:
+# Bits Description
+# ---- -----------
+# 7:0 event select (low bits)
+# 15:8 (umask) match
+# 31:16 unused
+# 35:32 event select (high bits)
+# 36:54 unused
+# 55 exclude bit
+# 63:56 (umask) mask
+#
+# Events are selected by (umask & mask == match)
+#
+# @select: x86 PMU event select, which is a 12-bit unsigned number.
+#
+# @match: umask match.
+#
+# @mask: umask mask
+#
+# @exclude: Whether the matched events are excluded.
+#
+# Since 9.1
+##
+{ 'struct': 'KVMPMUX86MaskedEntry',
+ 'data': { 'select': 'uint16',
+ 'match': 'uint8',
+ 'mask': 'uint8',
+ 'exclude': 'bool' } }
+
##
# @KVMPMUFilterEvent:
#
@@ -83,7 +120,8 @@
'format': 'KVMPMUEventEncodeFmt' },
'discriminator': 'format',
'data': { 'raw': 'KVMPMURawEvent',
- 'x86-default': 'KVMPMUX86DefalutEvent' } }
+ 'x86-default': 'KVMPMUX86DefalutEvent',
+ 'x86-masked-entry': 'KVMPMUX86MaskedEntry' } }
##
# @KVMPMUFilterProperty:
@@ -128,6 +166,29 @@
'data': { 'select': 'str',
'umask': 'str' } }
+##
+# @KVMPMUX86MaskedEntryVariant:
+#
+# The variant of KVMPMUX86MaskedEntry with the string, rather than
+# the numeric value.
+#
+# @select: x86 PMU event select. This field is a 12-bit unsigned
+# number string.
+#
+# @match: umask match. This field is a uint8 string.
+#
+# @mask: umask mask. This field is a uint8 string.
+#
+# @exclude: Whether the matched events are excluded.
+#
+# Since 9.1
+##
+{ 'struct': 'KVMPMUX86MaskedEntryVariant',
+ 'data': { 'select': 'str',
+ 'match': 'str',
+ 'mask': 'str',
+ 'exclude': 'bool' } }
+
##
# @KVMPMUFilterEventVariant:
#
@@ -144,7 +205,8 @@
'format': 'KVMPMUEventEncodeFmt' },
'discriminator': 'format',
'data': { 'raw': 'KVMPMURawEventVariant',
- 'x86-default': 'KVMPMUX86DefalutEventVariant' } }
+ 'x86-default': 'KVMPMUX86DefalutEventVariant',
+ 'x86-masked-entry': 'KVMPMUX86MaskedEntryVariant' } }
##
# @KVMPMUFilterPropertyVariant:
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 391531c036a6..396a93efe745 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -5397,6 +5397,13 @@ kvm_config_pmu_event(KVMPMUFilter *filter,
code = X86_PMU_RAW_EVENT(event->u.x86_default.select,
event->u.x86_default.umask);
break;
+ case KVM_PMU_EVENT_FMT_X86_MASKED_ENTRY:
+ code = KVM_PMU_ENCODE_MASKED_ENTRY(
+ event->u.x86_masked_entry.select,
+ event->u.x86_masked_entry.mask,
+ event->u.x86_masked_entry.match,
+ event->u.x86_masked_entry.exclude ? 1 : 0);
+ break;
default:
g_assert_not_reached();
}
@@ -5432,6 +5439,21 @@ static bool kvm_install_pmu_event_filter(KVMState *s)
g_assert_not_reached();
}
+ /*
+ * The check in kvm_arch_check_pmu_filter() ensures masked entry
+ * format won't be mixed with other formats.
+ */
+ kvm_filter->flags = filter->events->value->format ==
+ KVM_PMU_EVENT_FMT_X86_MASKED_ENTRY ?
+ KVM_PMU_EVENT_FLAG_MASKED_EVENTS : 0;
+
+ if (kvm_filter->flags == KVM_PMU_EVENT_FLAG_MASKED_EVENTS &&
+ !kvm_vm_check_extension(s, KVM_CAP_PMU_EVENT_MASKED_EVENTS)) {
+ error_report("Masked entry format of PMU event "
+ "is not supported by Host.");
+ goto fail;
+ }
+
if (!kvm_config_pmu_event(filter, kvm_filter)) {
goto fail;
}
@@ -6064,6 +6086,7 @@ static void kvm_arch_check_pmu_filter(const Object *obj, const char *name,
KVMPMUFilter *filter = KVM_PMU_FILTER(child);
KVMPMUFilterEventList *events = filter->events;
KVMPMUFilterAction action;
+ uint32_t base_flag;
if (!filter->nevents) {
error_setg(errp,
@@ -6071,13 +6094,22 @@ static void kvm_arch_check_pmu_filter(const Object *obj, const char *name,
return;
}
+ /* Pick the first event's flag as the base one. */
+ base_flag = events->value->format ==
+ KVM_PMU_EVENT_FMT_X86_MASKED_ENTRY ?
+ KVM_PMU_EVENT_FLAG_MASKED_EVENTS : 0;
action = KVM_PMU_FILTER_ACTION__MAX;
while (events) {
KVMPMUFilterEvent *event = events->value;
+ uint32_t flag;
switch (event->format) {
case KVM_PMU_EVENT_FMT_RAW:
case KVM_PMU_EVENT_FMT_X86_DEFAULT:
+ flag = 0;
+ break;
+ case KVM_PMU_EVENT_FMT_X86_MASKED_ENTRY:
+ flag = KVM_PMU_EVENT_FLAG_MASKED_EVENTS;
break;
default:
error_setg(errp,
@@ -6086,6 +6118,13 @@ static void kvm_arch_check_pmu_filter(const Object *obj, const char *name,
return;
}
+ if (flag != base_flag) {
+ error_setg(errp,
+ "Masked entry format cannot be mixed with "
+ "other formats.");
+ return;
+ }
+
if (action == KVM_PMU_FILTER_ACTION__MAX) {
action = event->action;
} else if (action != event->action) {
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [RFC 5/5] i386/kvm: Support fixed counter in KVM PMU filter
2024-07-10 4:51 [RFC 0/5] accel/kvm: Support KVM PMU filter Zhao Liu
` (3 preceding siblings ...)
2024-07-10 4:51 ` [RFC 4/5] i386/kvm: Support event with masked entry " Zhao Liu
@ 2024-07-10 4:51 ` Zhao Liu
2024-07-18 5:27 ` [RFC 0/5] accel/kvm: Support " Mi, Dapeng
2024-08-02 9:01 ` Shaoqin Huang
6 siblings, 0 replies; 15+ messages in thread
From: Zhao Liu @ 2024-07-10 4:51 UTC (permalink / raw)
To: Paolo Bonzini, Eric Blake, Markus Armbruster, Michael Roth,
Daniel P . Berrangé, Eduardo Habkost, Marcelo Tosatti,
Shaoqin Huang, Eric Auger, Peter Maydell, Laurent Vivier,
Thomas Huth, Sebastian Ott, Gavin Shan
Cc: qemu-devel, kvm, qemu-arm, Zhenyu Wang, Dapeng Mi, Yuan Yao,
Xiong Zhang, Mingwei Zhang, Jim Mattson, Zhao Liu
KVM_SET_PMU_EVENT_FILTER of x86 KVM allows user to configure x86 fixed
function counters by a bitmap.
Add the support of x86-fixed-counter in kvm-pmu-filter object and handle
this in i386 kvm codes.
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
---
accel/kvm/kvm-pmu.c | 71 ++++++++++++++++++++++++++++++++++++++++
include/sysemu/kvm-pmu.h | 1 +
qapi/kvm.json | 36 +++++++++++++++++++-
target/i386/kvm/kvm.c | 69 +++++++++++++++++++++++++-------------
4 files changed, 153 insertions(+), 24 deletions(-)
diff --git a/accel/kvm/kvm-pmu.c b/accel/kvm/kvm-pmu.c
index 7a1720c68f8f..bad76482f426 100644
--- a/accel/kvm/kvm-pmu.c
+++ b/accel/kvm/kvm-pmu.c
@@ -256,6 +256,68 @@ fail:
qapi_free_KVMPMUFilterEventList(head);
}
+static void
+kvm_pmu_filter_get_fixed_counter(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ KVMPMUFilter *filter = KVM_PMU_FILTER(obj);
+ KVMPMUX86FixedCounterVariant *str_counter;
+
+ str_counter = g_new(KVMPMUX86FixedCounterVariant, 1);
+ str_counter->action = filter->x86_fixed_counter->action;
+ str_counter->bitmap = g_strdup_printf("0x%x",
+ filter->x86_fixed_counter->bitmap);
+
+ visit_type_KVMPMUX86FixedCounterVariant(v, name, &str_counter, errp);
+ qapi_free_KVMPMUX86FixedCounterVariant(str_counter);
+}
+
+static void
+kvm_pmu_filter_set_fixed_counter(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ KVMPMUFilter *filter = KVM_PMU_FILTER(obj);
+ KVMPMUX86FixedCounterVariant *str_counter;
+ KVMPMUX86FixedCounter *new_counter, *old_counter;
+ uint64_t bitmap;
+ int ret;
+
+ old_counter = filter->x86_fixed_counter;
+ if (!visit_type_KVMPMUX86FixedCounterVariant(v, name,
+ &str_counter, errp)) {
+ return;
+ }
+
+ new_counter = g_new(KVMPMUX86FixedCounter, 1);
+ new_counter->action = str_counter->action;
+
+ ret = qemu_strtou64(str_counter->bitmap, NULL,
+ 0, &bitmap);
+ if (ret < 0) {
+ error_setg(errp,
+ "Invalid x86 fixed counter (bitmap: %s): %s. "
+ "The bitmap must be a uint32 string.",
+ str_counter->bitmap, strerror(-ret));
+ g_free(new_counter);
+ goto fail;
+ }
+ if (bitmap > UINT32_MAX) {
+ error_setg(errp,
+ "Invalid x86 fixed counter (bitmap: %s): "
+ "Numerical result out of range. "
+ "The bitmap must be a uint32 string.",
+ str_counter->bitmap);
+ g_free(new_counter);
+ goto fail;
+ }
+ new_counter->bitmap = bitmap;
+ filter->x86_fixed_counter = new_counter;
+ qapi_free_KVMPMUX86FixedCounter(old_counter);
+
+fail:
+ qapi_free_KVMPMUX86FixedCounterVariant(str_counter);
+}
+
static void
kvm_pmu_filter_class_init(ObjectClass *oc, void *data)
{
@@ -266,6 +328,15 @@ kvm_pmu_filter_class_init(ObjectClass *oc, void *data)
NULL, NULL);
object_class_property_set_description(oc, "events",
"KVM PMU event list");
+
+ object_class_property_add(oc, "x86-fixed-counter",
+ "KVMPMUX86FixedCounter",
+ kvm_pmu_filter_get_fixed_counter,
+ kvm_pmu_filter_set_fixed_counter,
+ NULL, NULL);
+ object_class_property_set_description(oc, "x86-fixed-counter",
+ "Enablement bitmap of "
+ "x86 PMU fixed counter");
}
static void kvm_pmu_filter_instance_init(Object *obj)
diff --git a/include/sysemu/kvm-pmu.h b/include/sysemu/kvm-pmu.h
index 707f33d604fd..e74a6a665565 100644
--- a/include/sysemu/kvm-pmu.h
+++ b/include/sysemu/kvm-pmu.h
@@ -24,6 +24,7 @@ struct KVMPMUFilter {
uint32_t nevents;
KVMPMUFilterEventList *events;
+ KVMPMUX86FixedCounter *x86_fixed_counter;
};
/*
diff --git a/qapi/kvm.json b/qapi/kvm.json
index f4e8854fa6c6..fe9a9ec940be 100644
--- a/qapi/kvm.json
+++ b/qapi/kvm.json
@@ -123,6 +123,21 @@
'x86-default': 'KVMPMUX86DefalutEvent',
'x86-masked-entry': 'KVMPMUX86MaskedEntry' } }
+##
+# @KVMPMUX86FixedCounter:
+#
+# x86 fixed counter that KVM PMU filter supports.
+#
+# @action: action that KVM PMU filter will take.
+#
+# @bitmap: x86 fixed counter bitmap.
+#
+# Since 9.1
+##
+{ 'struct': 'KVMPMUX86FixedCounter',
+ 'data': { 'action': 'KVMPMUFilterAction',
+ 'bitmap': 'uint32' } }
+
##
# @KVMPMUFilterProperty:
#
@@ -208,6 +223,22 @@
'x86-default': 'KVMPMUX86DefalutEventVariant',
'x86-masked-entry': 'KVMPMUX86MaskedEntryVariant' } }
+##
+# @KVMPMUX86FixedCounterVariant:
+#
+# The variant of KVMPMUX86FixedCounter with the string, rather than
+# the numeric value.
+#
+# @action: action that KVM PMU filter will take.
+#
+# @bitmap: x86 fixed counter bitmap. This field is a uint32 string.
+#
+# Since 9.1
+##
+{ 'struct': 'KVMPMUX86FixedCounterVariant',
+ 'data': { 'action': 'KVMPMUFilterAction',
+ 'bitmap': 'str' } }
+
##
# @KVMPMUFilterPropertyVariant:
#
@@ -215,7 +246,10 @@
#
# @events: the KVMPMUFilterEventVariant list.
#
+# @x86-fixed-counter: enablement bitmap of x86 fixed counters.
+#
# Since 9.1
##
{ 'struct': 'KVMPMUFilterPropertyVariant',
- 'data': { '*events': ['KVMPMUFilterEventVariant'] } }
+ 'data': { '*events': ['KVMPMUFilterEventVariant'],
+ '*x86-fixed-counter': 'KVMPMUX86FixedCounterVariant' } }
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 396a93efe745..b350c4123ea2 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -5419,6 +5419,7 @@ static bool kvm_install_pmu_event_filter(KVMState *s)
{
struct kvm_pmu_event_filter *kvm_filter;
KVMPMUFilter *filter = s->pmu_filter;
+ KVMPMUFilterAction action;
int ret;
kvm_filter = g_malloc0(sizeof(struct kvm_pmu_event_filter) +
@@ -5426,9 +5427,14 @@ static bool kvm_install_pmu_event_filter(KVMState *s)
/*
* Currently, kvm-pmu-filter only supports configuring the same
- * action for PMU events.
+ * action for PMU fixed-counters/events.
*/
- switch (filter->events->value->action) {
+ if (filter->x86_fixed_counter) {
+ action = filter->x86_fixed_counter->action;
+ } else {
+ action = filter->events->value->action;
+ }
+ switch (action) {
case KVM_PMU_FILTER_ACTION_ALLOW:
kvm_filter->action = KVM_PMU_EVENT_ALLOW;
break;
@@ -5439,23 +5445,29 @@ static bool kvm_install_pmu_event_filter(KVMState *s)
g_assert_not_reached();
}
- /*
- * The check in kvm_arch_check_pmu_filter() ensures masked entry
- * format won't be mixed with other formats.
- */
- kvm_filter->flags = filter->events->value->format ==
- KVM_PMU_EVENT_FMT_X86_MASKED_ENTRY ?
- KVM_PMU_EVENT_FLAG_MASKED_EVENTS : 0;
-
- if (kvm_filter->flags == KVM_PMU_EVENT_FLAG_MASKED_EVENTS &&
- !kvm_vm_check_extension(s, KVM_CAP_PMU_EVENT_MASKED_EVENTS)) {
- error_report("Masked entry format of PMU event "
- "is not supported by Host.");
- goto fail;
+ if (filter->x86_fixed_counter) {
+ kvm_filter->fixed_counter_bitmap = filter->x86_fixed_counter->bitmap;
}
- if (!kvm_config_pmu_event(filter, kvm_filter)) {
- goto fail;
+ if (filter->nevents) {
+ /*
+ * The check in kvm_arch_check_pmu_filter() ensures masked entry
+ * format won't be mixed with other formats.
+ */
+ kvm_filter->flags = filter->events->value->format ==
+ KVM_PMU_EVENT_FMT_X86_MASKED_ENTRY ?
+ KVM_PMU_EVENT_FLAG_MASKED_EVENTS : 0;
+
+ if (kvm_filter->flags == KVM_PMU_EVENT_FLAG_MASKED_EVENTS &&
+ !kvm_vm_check_extension(s, KVM_CAP_PMU_EVENT_MASKED_EVENTS)) {
+ error_report("Masked entry format of PMU event "
+ "is not supported by Host.");
+ goto fail;
+ }
+
+ if (!kvm_config_pmu_event(filter, kvm_filter)) {
+ goto fail;
+ }
}
ret = kvm_vm_ioctl(s, KVM_SET_PMU_EVENT_FILTER, kvm_filter);
@@ -6088,17 +6100,24 @@ static void kvm_arch_check_pmu_filter(const Object *obj, const char *name,
KVMPMUFilterAction action;
uint32_t base_flag;
- if (!filter->nevents) {
+ if (!filter->x86_fixed_counter && !filter->nevents) {
error_setg(errp,
"Empty KVM PMU filter.");
return;
}
/* Pick the first event's flag as the base one. */
- base_flag = events->value->format ==
- KVM_PMU_EVENT_FMT_X86_MASKED_ENTRY ?
- KVM_PMU_EVENT_FLAG_MASKED_EVENTS : 0;
+ base_flag = 0;
+ if (filter->nevents &&
+ events->value->format == KVM_PMU_EVENT_FMT_X86_MASKED_ENTRY) {
+ base_flag = KVM_PMU_EVENT_FLAG_MASKED_EVENTS;
+ }
+
action = KVM_PMU_FILTER_ACTION__MAX;
+ if (filter->x86_fixed_counter) {
+ action = filter->x86_fixed_counter->action;
+ }
+
while (events) {
KVMPMUFilterEvent *event = events->value;
uint32_t flag;
@@ -6128,9 +6147,13 @@ static void kvm_arch_check_pmu_filter(const Object *obj, const char *name,
if (action == KVM_PMU_FILTER_ACTION__MAX) {
action = event->action;
} else if (action != event->action) {
- /* TODO: Support events with different actions if necessary. */
+ /*
+ * TODO: Support fixed-counters/events with different actions
+ * if necessary.
+ */
error_setg(errp,
- "Only support PMU events with the same action");
+ "Only support PMU fixed-counters/events "
+ "with the same action");
return;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [RFC 0/5] accel/kvm: Support KVM PMU filter
2024-07-10 4:51 [RFC 0/5] accel/kvm: Support KVM PMU filter Zhao Liu
` (4 preceding siblings ...)
2024-07-10 4:51 ` [RFC 5/5] i386/kvm: Support fixed counter " Zhao Liu
@ 2024-07-18 5:27 ` Mi, Dapeng
2024-07-19 8:05 ` Zhao Liu
2024-08-02 9:01 ` Shaoqin Huang
6 siblings, 1 reply; 15+ messages in thread
From: Mi, Dapeng @ 2024-07-18 5:27 UTC (permalink / raw)
To: Zhao Liu, Paolo Bonzini, Eric Blake, Markus Armbruster,
Michael Roth, Daniel P . Berrangé, Eduardo Habkost,
Marcelo Tosatti, Shaoqin Huang, Eric Auger, Peter Maydell,
Laurent Vivier, Thomas Huth, Sebastian Ott, Gavin Shan
Cc: qemu-devel, kvm, qemu-arm, Zhenyu Wang, Dapeng Mi, Yuan Yao,
Xiong Zhang, Mingwei Zhang, Jim Mattson
On 7/10/2024 12:51 PM, Zhao Liu wrote:
> Hi QEMU maintainers, arm and PMU folks,
>
> I picked up Shaoqing's previous work [1] on the KVM PMU filter for arm,
> and now is trying to support this feature for x86 with a JSON-compatible
> API.
>
> While arm and x86 use different KVM ioctls to configure the PMU filter,
> considering they all have similar inputs (PMU event + action), it is
> still possible to abstract a generic, cross-architecture kvm-pmu-filter
> object and provide users with a sufficiently generic or near-consistent
> QAPI interface.
>
> That's what I did in this series, a new kvm-pmu-filter object, with the
> API like:
>
> -object '{"qom-type":"kvm-pmu-filter","id":"f0","events":[{"action":"allow","format":"raw","code":"0xc4"}]}'
I'm not sure why the action is defined to event scope instead of the entire
filter scope. At least for x86 arch, the action is defined to filter scope
in KVM. Do other archs support event scope's action? If the action can be
defined to filter scope, the code could be simplified much.
>
> For i386, this object is inserted into kvm accelerator and is extended
> to support fixed-counter and more formats ("x86-default" and
> "x86-masked-entry"):
>
> -accel kvm,pmu-filter=f0 \
> -object pmu='{"qom-type":"kvm-pmu-filter","id":"f0","x86-fixed-counter":{"action":"allow","bitmap":"0x0"},"events":[{"action":"allow","format":"x86-masked-entry","select":"0xc4","mask":"0xff","match":"0","exclude":true},{"action":"allow","format":"x86-masked-entry","select":"0xc5","mask":"0xff","match":"0","exclude":true}]}'
>
> This object can still be added as the property to the arch CPU if it is
> desired as a per CPU feature (as Shaoqin did for arm before).
>
> Welcome your feedback and comments!
>
>
> Introduction
> ============
>
>
> Formats supported in kvm-pmu-filter
> -----------------------------------
>
> This series supports 3 formats:
>
> * raw format (general format).
>
> This format indicates the code that has been encoded to be able to
> index the PMU events, and which can be delivered directly to the KVM
> ioctl. For arm, this means the event code, and for i386, this means
> the raw event with the layout like:
>
> select high bit | umask | select low bits
>
> * x86-default format (i386 specific)
>
> x86 commonly uses select&umask to identify PMU events, and this format
> is used to support the select&umask. Then QEMU will encode select and
> umask into a raw format code.
>
> * x86-masked-entry (i386 specific)
>
> This is a special format that x86's KVM_SET_PMU_EVENT_FILTER supports.
>
>
> Hexadecimal value string
> ------------------------
>
> In practice, the values associated with PMU events (code for arm, select&
> umask for x86) are often expressed in hexadecimal. Further, from linux
> perf related information (tools/perf/pmu-events/arch/*/*/*.json), x86/
> arm64/riscv/nds32/powerpc all prefer the hexadecimal numbers and only
> s390 uses decimal value.
>
> Therefore, it is necessary to support hexadecimal in order to honor PMU
> conventions.
>
> However, unfortunately, standard JSON (RFC 8259) does not support
> hexadecimal numbers. So I can only consider using the numeric string in
> the QAPI and then parsing it to a number.
>
> To achieve this, I defined two versions of PMU-related structures in
> kvm.json:
> * a native version that accepts numeric values, which is used for
> QEMU's internal code processing,
>
> * and a variant version that accepts numeric string, which is used to
> receive user input.
>
> kvm-pmu-filter object will take care of converting the string version
> of the event/counter information into the numeric version.
>
> The related implementation can be found in patch 1.
>
>
> CPU property v.s. KVM property
> ------------------------------
>
> In Shaoqin's previous implementation [1], KVM PMU filter is made as a
> arm CPU property. This is because arm uses a per CPU ioctl
> (KVM_SET_DEVICE_ATTR) to configure KVM PMU filter.
>
> However, for x86, the dependent ioctl (KVM_SET_PMU_EVENT_FILTER) is per
> VM. In the meantime, considering that for hybrid architecture, maybe in
> the future there will be a new per vCPU ioctl, or there will be
> practices to support filter fixed counter by configuring CPUIDs.
>
> Based on the above thoughts, for x86, it is not appropriate to make the
> current per-VM ioctl-based PMU filter a CPU property. Instead, I make it
> a kvm property and configure it via "-accel kvm,pmu-filter=obj_id".
>
> So in summary, it is feasible to use the KVM PMU filter as either a CPU
> or a KVM property, depending on whether it is used as a CPU feature or a
> VM feature.
>
> The kvm-pmu-filter object, as an abstraction, is general enough to
> support filter configurations for different scopes (per-CPU or per-VM).
Per my understanding, the cpus sharing same uarch should share same perf
events filter. Not sure if there is real requirement to support different
filters on the CPUs with same arch.
>
>
> [1]: https://lore.kernel.org/qemu-devel/20240409024940.180107-1-shahuang@redhat.com/
>
> Thanks and Best Regards,
> Zhao
> ---
> Zhao Liu (5):
> qapi/qom: Introduce kvm-pmu-filter object
> i386/kvm: Support initial KVM PMU filter
> i386/kvm: Support event with select&umask format in KVM PMU filter
> i386/kvm: Support event with masked entry format in KVM PMU filter
> i386/kvm: Support fixed counter in KVM PMU filter
>
> MAINTAINERS | 1 +
> accel/kvm/kvm-pmu.c | 367 +++++++++++++++++++++++++++++++++++++
> accel/kvm/meson.build | 1 +
> include/sysemu/kvm-pmu.h | 43 +++++
> include/sysemu/kvm_int.h | 2 +
> qapi/kvm.json | 255 ++++++++++++++++++++++++++
> qapi/meson.build | 1 +
> qapi/qapi-schema.json | 1 +
> qapi/qom.json | 3 +
> target/i386/kvm/kvm.c | 211 +++++++++++++++++++++
> target/i386/kvm/kvm_i386.h | 1 +
> 11 files changed, 886 insertions(+)
> create mode 100644 accel/kvm/kvm-pmu.c
> create mode 100644 include/sysemu/kvm-pmu.h
> create mode 100644 qapi/kvm.json
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [RFC 3/5] i386/kvm: Support event with select&umask format in KVM PMU filter
2024-07-10 4:51 ` [RFC 3/5] i386/kvm: Support event with select&umask format in " Zhao Liu
@ 2024-07-18 5:28 ` Mi, Dapeng
2024-07-19 8:40 ` Zhao Liu
0 siblings, 1 reply; 15+ messages in thread
From: Mi, Dapeng @ 2024-07-18 5:28 UTC (permalink / raw)
To: Zhao Liu, Paolo Bonzini, Eric Blake, Markus Armbruster,
Michael Roth, Daniel P . Berrangé, Eduardo Habkost,
Marcelo Tosatti, Shaoqin Huang, Eric Auger, Peter Maydell,
Laurent Vivier, Thomas Huth, Sebastian Ott, Gavin Shan
Cc: qemu-devel, kvm, qemu-arm, Zhenyu Wang, Dapeng Mi, Yuan Yao,
Xiong Zhang, Mingwei Zhang, Jim Mattson
On 7/10/2024 12:51 PM, Zhao Liu wrote:
> The select&umask is the common way for x86 to identify the PMU event,
> so support this way as the "x86-default" format in kvm-pmu-filter
> object.
>
> Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
> ---
> accel/kvm/kvm-pmu.c | 62 ++++++++++++++++++++++++++++++++++++++++
> include/sysemu/kvm-pmu.h | 13 +++++++++
> qapi/kvm.json | 46 +++++++++++++++++++++++++++--
> target/i386/kvm/kvm.c | 5 ++++
> 4 files changed, 123 insertions(+), 3 deletions(-)
>
> diff --git a/accel/kvm/kvm-pmu.c b/accel/kvm/kvm-pmu.c
> index 483d1bdf4807..51d3fba5a72a 100644
> --- a/accel/kvm/kvm-pmu.c
> +++ b/accel/kvm/kvm-pmu.c
> @@ -17,6 +17,8 @@
> #include "qom/object_interfaces.h"
> #include "sysemu/kvm-pmu.h"
>
> +#define UINT12_MAX (4095)
> +
> static void kvm_pmu_filter_get_event(Object *obj, Visitor *v, const char *name,
> void *opaque, Error **errp)
> {
> @@ -38,6 +40,12 @@ static void kvm_pmu_filter_get_event(Object *obj, Visitor *v, const char *name,
> str_event->u.raw.code = g_strdup_printf("0x%lx",
> event->u.raw.code);
> break;
> + case KVM_PMU_EVENT_FMT_X86_DEFAULT:
> + str_event->u.x86_default.select =
> + g_strdup_printf("0x%x", event->u.x86_default.select);
> + str_event->u.x86_default.umask =
> + g_strdup_printf("0x%x", event->u.x86_default.umask);
> + break;
> default:
> g_assert_not_reached();
> }
> @@ -83,6 +91,60 @@ static void kvm_pmu_filter_set_event(Object *obj, Visitor *v, const char *name,
> goto fail;
> }
> break;
> + case KVM_PMU_EVENT_FMT_X86_DEFAULT: {
> + uint64_t select, umask;
> +
> + ret = qemu_strtou64(str_event->u.x86_default.select, NULL,
> + 0, &select);
> + if (ret < 0) {
> + error_setg(errp,
> + "Invalid %s PMU event (select: %s): %s. "
> + "The select must be a "
> + "12-bit unsigned number string.",
> + KVMPMUEventEncodeFmt_str(str_event->format),
> + str_event->u.x86_default.select,
> + strerror(-ret));
> + g_free(event);
> + goto fail;
> + }
> + if (select > UINT12_MAX) {
> + error_setg(errp,
> + "Invalid %s PMU event (select: %s): "
> + "Numerical result out of range. "
> + "The select must be a "
> + "12-bit unsigned number string.",
> + KVMPMUEventEncodeFmt_str(str_event->format),
> + str_event->u.x86_default.select);
> + g_free(event);
> + goto fail;
> + }
> + event->u.x86_default.select = select;
> +
> + ret = qemu_strtou64(str_event->u.x86_default.umask, NULL,
> + 0, &umask);
> + if (ret < 0) {
> + error_setg(errp,
> + "Invalid %s PMU event (umask: %s): %s. "
> + "The umask must be a uint8 string.",
> + KVMPMUEventEncodeFmt_str(str_event->format),
> + str_event->u.x86_default.umask,
> + strerror(-ret));
> + g_free(event);
> + goto fail;
> + }
> + if (umask > UINT8_MAX) {
umask is extended to 16 bits from Perfmon v6+. Please notice we need to
upgrade this to 16 bits in the future. More details can be found here.
[PATCH V3 00/13] Support Lunar Lake and Arrow Lake core PMU - kan.liang
(kernel.org)
<https://lore.kernel.org/all/20240626143545.480761-1-kan.liang@linux.intel.com/>
> + error_setg(errp,
> + "Invalid %s PMU event (umask: %s): "
> + "Numerical result out of range. "
> + "The umask must be a uint8 string.",
> + KVMPMUEventEncodeFmt_str(str_event->format),
> + str_event->u.x86_default.umask);
> + g_free(event);
> + goto fail;
> + }
> + event->u.x86_default.umask = umask;
> + break;
> + }
> default:
> g_assert_not_reached();
> }
> diff --git a/include/sysemu/kvm-pmu.h b/include/sysemu/kvm-pmu.h
> index 4707759761f1..707f33d604fd 100644
> --- a/include/sysemu/kvm-pmu.h
> +++ b/include/sysemu/kvm-pmu.h
> @@ -26,4 +26,17 @@ struct KVMPMUFilter {
> KVMPMUFilterEventList *events;
> };
>
> +/*
> + * Stolen from Linux kernel (RAW_EVENT at tools/testing/selftests/kvm/include/
> + * x86_64/pmu.h).
> + *
> + * Encode an eventsel+umask pair into event-select MSR format. Note, this is
> + * technically AMD's format, as Intel's format only supports 8 bits for the
> + * event selector, i.e. doesn't use bits 24:16 for the selector. But, OR-ing
> + * in '0' is a nop and won't clobber the CMASK.
> + */
> +#define X86_PMU_RAW_EVENT(eventsel, umask) (((eventsel & 0xf00UL) << 24) | \
> + ((eventsel) & 0xff) | \
> + ((umask) & 0xff) << 8)
> +
> #endif /* KVM_PMU_H */
> diff --git a/qapi/kvm.json b/qapi/kvm.json
> index 0619da83c123..0d759884c229 100644
> --- a/qapi/kvm.json
> +++ b/qapi/kvm.json
> @@ -27,11 +27,13 @@
> #
> # @raw: the encoded event code that KVM can directly consume.
> #
> +# @x86-default: standard x86 encoding format with select and umask.
> +#
> # Since 9.1
> ##
> { 'enum': 'KVMPMUEventEncodeFmt',
> 'prefix': 'KVM_PMU_EVENT_FMT',
> - 'data': ['raw'] }
> + 'data': ['raw', 'x86-default'] }
>
> ##
> # @KVMPMURawEvent:
> @@ -46,6 +48,25 @@
> { 'struct': 'KVMPMURawEvent',
> 'data': { 'code': 'uint64' } }
>
> +##
> +# @KVMPMUX86DefalutEvent:
> +#
> +# x86 PMU event encoding with select and umask.
> +# raw_event = ((select & 0xf00UL) << 24) | \
> +# (select) & 0xff) | \
> +# ((umask) & 0xff) << 8)
> +#
> +# @select: x86 PMU event select field, which is a 12-bit unsigned
> +# number.
> +#
> +# @umask: x86 PMU event umask field.
> +#
> +# Since 9.1
> +##
> +{ 'struct': 'KVMPMUX86DefalutEvent',
> + 'data': { 'select': 'uint16',
> + 'umask': 'uint8' } }
> +
> ##
> # @KVMPMUFilterEvent:
> #
> @@ -61,7 +82,8 @@
> 'base': { 'action': 'KVMPMUFilterAction',
> 'format': 'KVMPMUEventEncodeFmt' },
> 'discriminator': 'format',
> - 'data': { 'raw': 'KVMPMURawEvent' } }
> + 'data': { 'raw': 'KVMPMURawEvent',
> + 'x86-default': 'KVMPMUX86DefalutEvent' } }
>
> ##
> # @KVMPMUFilterProperty:
> @@ -89,6 +111,23 @@
> { 'struct': 'KVMPMURawEventVariant',
> 'data': { 'code': 'str' } }
>
> +##
> +# @KVMPMUX86DefalutEventVariant:
> +#
> +# The variant of KVMPMUX86DefalutEvent with the string, rather than
> +# the numeric value.
> +#
> +# @select: x86 PMU event select field. This field is a 12-bit
> +# unsigned number string.
> +#
> +# @umask: x86 PMU event umask field. This field is a uint8 string.
> +#
> +# Since 9.1
> +##
> +{ 'struct': 'KVMPMUX86DefalutEventVariant',
> + 'data': { 'select': 'str',
> + 'umask': 'str' } }
> +
> ##
> # @KVMPMUFilterEventVariant:
> #
> @@ -104,7 +143,8 @@
> 'base': { 'action': 'KVMPMUFilterAction',
> 'format': 'KVMPMUEventEncodeFmt' },
> 'discriminator': 'format',
> - 'data': { 'raw': 'KVMPMURawEventVariant' } }
> + 'data': { 'raw': 'KVMPMURawEventVariant',
> + 'x86-default': 'KVMPMUX86DefalutEventVariant' } }
>
> ##
> # @KVMPMUFilterPropertyVariant:
> diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
> index e9bf79782316..391531c036a6 100644
> --- a/target/i386/kvm/kvm.c
> +++ b/target/i386/kvm/kvm.c
> @@ -5393,6 +5393,10 @@ kvm_config_pmu_event(KVMPMUFilter *filter,
> case KVM_PMU_EVENT_FMT_RAW:
> code = event->u.raw.code;
> break;
> + case KVM_PMU_EVENT_FMT_X86_DEFAULT:
> + code = X86_PMU_RAW_EVENT(event->u.x86_default.select,
> + event->u.x86_default.umask);
> + break;
> default:
> g_assert_not_reached();
> }
> @@ -6073,6 +6077,7 @@ static void kvm_arch_check_pmu_filter(const Object *obj, const char *name,
>
> switch (event->format) {
> case KVM_PMU_EVENT_FMT_RAW:
> + case KVM_PMU_EVENT_FMT_X86_DEFAULT:
> break;
> default:
> error_setg(errp,
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [RFC 0/5] accel/kvm: Support KVM PMU filter
2024-07-18 5:27 ` [RFC 0/5] accel/kvm: Support " Mi, Dapeng
@ 2024-07-19 8:05 ` Zhao Liu
0 siblings, 0 replies; 15+ messages in thread
From: Zhao Liu @ 2024-07-19 8:05 UTC (permalink / raw)
To: Mi, Dapeng, Shaoqin Huang, Eric Auger
Cc: Paolo Bonzini, Eric Blake, Markus Armbruster, Michael Roth,
Daniel P . Berrangé, Eduardo Habkost, Marcelo Tosatti,
Peter Maydell, Laurent Vivier, Thomas Huth, Sebastian Ott,
Gavin Shan, qemu-devel, kvm, qemu-arm, Zhenyu Wang, Dapeng Mi,
Yuan Yao, Xiong Zhang, Mingwei Zhang, Jim Mattson, Zhao Liu
Also ping Shaoqin and Eric,
Hopefully I can get your input on interface design to align with the
Arm requirements together!
On Thu, Jul 18, 2024 at 01:27:48PM +0800, Mi, Dapeng wrote:
> Date: Thu, 18 Jul 2024 13:27:48 +0800
> From: "Mi, Dapeng" <dapeng1.mi@linux.intel.com>
> Subject: Re: [RFC 0/5] accel/kvm: Support KVM PMU filter
>
>
> On 7/10/2024 12:51 PM, Zhao Liu wrote:
> > Hi QEMU maintainers, arm and PMU folks,
> >
> > I picked up Shaoqing's previous work [1] on the KVM PMU filter for arm,
> > and now is trying to support this feature for x86 with a JSON-compatible
> > API.
> >
> > While arm and x86 use different KVM ioctls to configure the PMU filter,
> > considering they all have similar inputs (PMU event + action), it is
> > still possible to abstract a generic, cross-architecture kvm-pmu-filter
> > object and provide users with a sufficiently generic or near-consistent
> > QAPI interface.
> >
> > That's what I did in this series, a new kvm-pmu-filter object, with the
> > API like:
> >
> > -object '{"qom-type":"kvm-pmu-filter","id":"f0","events":[{"action":"allow","format":"raw","code":"0xc4"}]}'
>
> I'm not sure why the action is defined to event scope instead of the entire
> filter scope. At least for x86 arch, the action is defined to filter scope
> in KVM. Do other archs support event scope's action? If the action can be
> defined to filter scope, the code could be simplified much.
Yeah, that's fine for x86.
@Shaoqin, hi Shaoqin, if I use a global action for all events, is this
Okay for Arm?
I suppose this should work, since the interface here needs to enumerate
events one by one, and doesn't support a continuous enumeration format
(0x0-0x3) like the previous implementation. Right?
> >
> > For i386, this object is inserted into kvm accelerator and is extended
> > to support fixed-counter and more formats ("x86-default" and
> > "x86-masked-entry"):
> >
> > -accel kvm,pmu-filter=f0 \
> > -object pmu='{"qom-type":"kvm-pmu-filter","id":"f0","x86-fixed-counter":{"action":"allow","bitmap":"0x0"},"events":[{"action":"allow","format":"x86-masked-entry","select":"0xc4","mask":"0xff","match":"0","exclude":true},{"action":"allow","format":"x86-masked-entry","select":"0xc5","mask":"0xff","match":"0","exclude":true}]}'
> >
> > This object can still be added as the property to the arch CPU if it is
> > desired as a per CPU feature (as Shaoqin did for arm before).
> >
> > Welcome your feedback and comments!
> >
> >
> > Introduction
> > ============
> >
> >
> > Formats supported in kvm-pmu-filter
> > -----------------------------------
> >
> > This series supports 3 formats:
> >
> > * raw format (general format).
> >
> > This format indicates the code that has been encoded to be able to
> > index the PMU events, and which can be delivered directly to the KVM
> > ioctl. For arm, this means the event code, and for i386, this means
> > the raw event with the layout like:
> >
> > select high bit | umask | select low bits
> >
> > * x86-default format (i386 specific)
> >
> > x86 commonly uses select&umask to identify PMU events, and this format
> > is used to support the select&umask. Then QEMU will encode select and
> > umask into a raw format code.
> >
> > * x86-masked-entry (i386 specific)
> >
> > This is a special format that x86's KVM_SET_PMU_EVENT_FILTER supports.
> >
> >
> > Hexadecimal value string
> > ------------------------
> >
> > In practice, the values associated with PMU events (code for arm, select&
> > umask for x86) are often expressed in hexadecimal. Further, from linux
> > perf related information (tools/perf/pmu-events/arch/*/*/*.json), x86/
> > arm64/riscv/nds32/powerpc all prefer the hexadecimal numbers and only
> > s390 uses decimal value.
> >
> > Therefore, it is necessary to support hexadecimal in order to honor PMU
> > conventions.
> >
> > However, unfortunately, standard JSON (RFC 8259) does not support
> > hexadecimal numbers. So I can only consider using the numeric string in
> > the QAPI and then parsing it to a number.
> >
> > To achieve this, I defined two versions of PMU-related structures in
> > kvm.json:
> > * a native version that accepts numeric values, which is used for
> > QEMU's internal code processing,
> >
> > * and a variant version that accepts numeric string, which is used to
> > receive user input.
> >
> > kvm-pmu-filter object will take care of converting the string version
> > of the event/counter information into the numeric version.
> >
> > The related implementation can be found in patch 1.
> >
> >
> > CPU property v.s. KVM property
> > ------------------------------
> >
> > In Shaoqin's previous implementation [1], KVM PMU filter is made as a
> > arm CPU property. This is because arm uses a per CPU ioctl
> > (KVM_SET_DEVICE_ATTR) to configure KVM PMU filter.
> >
> > However, for x86, the dependent ioctl (KVM_SET_PMU_EVENT_FILTER) is per
> > VM. In the meantime, considering that for hybrid architecture, maybe in
> > the future there will be a new per vCPU ioctl, or there will be
> > practices to support filter fixed counter by configuring CPUIDs.
> >
> > Based on the above thoughts, for x86, it is not appropriate to make the
> > current per-VM ioctl-based PMU filter a CPU property. Instead, I make it
> > a kvm property and configure it via "-accel kvm,pmu-filter=obj_id".
> >
> > So in summary, it is feasible to use the KVM PMU filter as either a CPU
> > or a KVM property, depending on whether it is used as a CPU feature or a
> > VM feature.
> >
> > The kvm-pmu-filter object, as an abstraction, is general enough to
> > support filter configurations for different scopes (per-CPU or per-VM).
>
> Per my understanding, the cpus sharing same uarch should share same perf
> events filter. Not sure if there is real requirement to support different
> filters on the CPUs with same arch.
The main consideration here is also to align with the underlying ioctl
of the PMU filter, Arm's ioctl is per vCPU and I'm not sure if there
will be a difference between CPUs in the feature.
But this I think could be an arch-specific implementation, x86 needs per
VM then use “-accel kvm,pmu-filter=obj_id”, Arm if it does need per vCPU
then it can be set for Arm CPUs via “-cpu host,pmu-filter=obj_id”. So
the generic part is this kvm-pmu-filter object itself, where exactly it
should be placed/inserted can be decided by the architecture itself.
Hi @Eric and @Shaoqin, do you agree?
Best Regards,
Zhao
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [RFC 3/5] i386/kvm: Support event with select&umask format in KVM PMU filter
2024-07-18 5:28 ` Mi, Dapeng
@ 2024-07-19 8:40 ` Zhao Liu
2024-07-23 5:36 ` Mi, Dapeng
0 siblings, 1 reply; 15+ messages in thread
From: Zhao Liu @ 2024-07-19 8:40 UTC (permalink / raw)
To: Mi, Dapeng
Cc: Paolo Bonzini, Eric Blake, Markus Armbruster, Michael Roth,
Daniel P . Berrangé, Eduardo Habkost, Marcelo Tosatti,
Shaoqin Huang, Eric Auger, Peter Maydell, Laurent Vivier,
Thomas Huth, Sebastian Ott, Gavin Shan, qemu-devel, kvm, qemu-arm,
Zhenyu Wang, Dapeng Mi, Yuan Yao, Xiong Zhang, Mingwei Zhang,
Jim Mattson, Zhao Liu
Hi Dapeng,
On Thu, Jul 18, 2024 at 01:28:25PM +0800, Mi, Dapeng wrote:
[snip]
> > + case KVM_PMU_EVENT_FMT_X86_DEFAULT: {
> > + uint64_t select, umask;
> > +
> > + ret = qemu_strtou64(str_event->u.x86_default.select, NULL,
> > + 0, &select);
> > + if (ret < 0) {
> > + error_setg(errp,
> > + "Invalid %s PMU event (select: %s): %s. "
> > + "The select must be a "
> > + "12-bit unsigned number string.",
> > + KVMPMUEventEncodeFmt_str(str_event->format),
> > + str_event->u.x86_default.select,
> > + strerror(-ret));
> > + g_free(event);
> > + goto fail;
> > + }
> > + if (select > UINT12_MAX) {
> > + error_setg(errp,
> > + "Invalid %s PMU event (select: %s): "
> > + "Numerical result out of range. "
> > + "The select must be a "
> > + "12-bit unsigned number string.",
> > + KVMPMUEventEncodeFmt_str(str_event->format),
> > + str_event->u.x86_default.select);
> > + g_free(event);
> > + goto fail;
> > + }
> > + event->u.x86_default.select = select;
> > +
> > + ret = qemu_strtou64(str_event->u.x86_default.umask, NULL,
> > + 0, &umask);
> > + if (ret < 0) {
> > + error_setg(errp,
> > + "Invalid %s PMU event (umask: %s): %s. "
> > + "The umask must be a uint8 string.",
> > + KVMPMUEventEncodeFmt_str(str_event->format),
> > + str_event->u.x86_default.umask,
> > + strerror(-ret));
> > + g_free(event);
> > + goto fail;
> > + }
> > + if (umask > UINT8_MAX) {
>
> umask is extended to 16 bits from Perfmon v6+. Please notice we need to
> upgrade this to 16 bits in the future. More details can be found here.
> [PATCH V3 00/13] Support Lunar Lake and Arrow Lake core PMU - kan.liang
> (kernel.org)
> <https://lore.kernel.org/all/20240626143545.480761-1-kan.liang@linux.intel.com/>
It's tricky...now I referred the RAW_EVENT format in tools/testing/
selftests/kvm/include/x86_64/pmu.h, which is used in KVM PMU and is
compatible with AMD and Intel.
The current KVM PMU filter for raw code doesn't define the layout in
the standard API like masked entries (KVM_PMU_ENCODE_MASKED_ENTRY), but
actually uses the RAW_EVENT format. So I even plan to move RAW_EVENT
macro into arch/x86/include/uapi/asm/kvm.h...
For the changes you mentioned, I think it would be better for the raw
code layout design not to break RAW_EVENT, so that AMD and Intel can
equally use the same macro to encode. Is it possible for a unified
layout macro?
What about extending RAW_EVENT as the following example? I understand
the umask2 is at bit 40-47.
#define X86_PMU_RAW_EVENT(eventsel, umask) (((eventsel & 0xf00UL) << 24) | \
((eventsel) & 0xff) | \
((umask) & 0xff) << 8) | \
((umask & 0xff00UL << 32)
Thanks,
Zhao
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [RFC 3/5] i386/kvm: Support event with select&umask format in KVM PMU filter
2024-07-19 8:40 ` Zhao Liu
@ 2024-07-23 5:36 ` Mi, Dapeng
0 siblings, 0 replies; 15+ messages in thread
From: Mi, Dapeng @ 2024-07-23 5:36 UTC (permalink / raw)
To: Zhao Liu
Cc: Paolo Bonzini, Eric Blake, Markus Armbruster, Michael Roth,
Daniel P. Berrangé, Eduardo Habkost, Marcelo Tosatti,
Shaoqin Huang, Eric Auger, Peter Maydell, Laurent Vivier,
Thomas Huth, Sebastian Ott, Gavin Shan, qemu-devel, kvm, qemu-arm,
Zhenyu Wang, Dapeng Mi, Yuan Yao, Xiong Zhang, Mingwei Zhang,
Jim Mattson
On 7/19/2024 4:40 PM, Zhao Liu wrote:
> Hi Dapeng,
>
> On Thu, Jul 18, 2024 at 01:28:25PM +0800, Mi, Dapeng wrote:
>
> [snip]
>
>>> + case KVM_PMU_EVENT_FMT_X86_DEFAULT: {
>>> + uint64_t select, umask;
>>> +
>>> + ret = qemu_strtou64(str_event->u.x86_default.select, NULL,
>>> + 0, &select);
>>> + if (ret < 0) {
>>> + error_setg(errp,
>>> + "Invalid %s PMU event (select: %s): %s. "
>>> + "The select must be a "
>>> + "12-bit unsigned number string.",
>>> + KVMPMUEventEncodeFmt_str(str_event->format),
>>> + str_event->u.x86_default.select,
>>> + strerror(-ret));
>>> + g_free(event);
>>> + goto fail;
>>> + }
>>> + if (select > UINT12_MAX) {
>>> + error_setg(errp,
>>> + "Invalid %s PMU event (select: %s): "
>>> + "Numerical result out of range. "
>>> + "The select must be a "
>>> + "12-bit unsigned number string.",
>>> + KVMPMUEventEncodeFmt_str(str_event->format),
>>> + str_event->u.x86_default.select);
>>> + g_free(event);
>>> + goto fail;
>>> + }
>>> + event->u.x86_default.select = select;
>>> +
>>> + ret = qemu_strtou64(str_event->u.x86_default.umask, NULL,
>>> + 0, &umask);
>>> + if (ret < 0) {
>>> + error_setg(errp,
>>> + "Invalid %s PMU event (umask: %s): %s. "
>>> + "The umask must be a uint8 string.",
>>> + KVMPMUEventEncodeFmt_str(str_event->format),
>>> + str_event->u.x86_default.umask,
>>> + strerror(-ret));
>>> + g_free(event);
>>> + goto fail;
>>> + }
>>> + if (umask > UINT8_MAX) {
>> umask is extended to 16 bits from Perfmon v6+. Please notice we need to
>> upgrade this to 16 bits in the future. More details can be found here.
>> [PATCH V3 00/13] Support Lunar Lake and Arrow Lake core PMU - kan.liang
>> (kernel.org)
>> <https://lore.kernel.org/all/20240626143545.480761-1-kan.liang@linux.intel.com/>
> It's tricky...now I referred the RAW_EVENT format in tools/testing/
> selftests/kvm/include/x86_64/pmu.h, which is used in KVM PMU and is
> compatible with AMD and Intel.
>
> The current KVM PMU filter for raw code doesn't define the layout in
> the standard API like masked entries (KVM_PMU_ENCODE_MASKED_ENTRY), but
> actually uses the RAW_EVENT format. So I even plan to move RAW_EVENT
> macro into arch/x86/include/uapi/asm/kvm.h...
For the raw event format, I suppose user should know the event layout and
would directly input the raw event code, qemu may not concern this.
>
> For the changes you mentioned, I think it would be better for the raw
> code layout design not to break RAW_EVENT, so that AMD and Intel can
> equally use the same macro to encode. Is it possible for a unified
> layout macro?
>
> What about extending RAW_EVENT as the following example? I understand
> the umask2 is at bit 40-47.
>
> #define X86_PMU_RAW_EVENT(eventsel, umask) (((eventsel & 0xf00UL) << 24) | \
> ((eventsel) & 0xff) | \
> ((umask) & 0xff) << 8) | \
> ((umask & 0xff00UL << 32)
It's always good if Intel and AMD can share same event layout, the extended
umask field occupies bits [40:47]. So I think we'd better follow this for
the RAW_EVENT as well.
>
> Thanks,
> Zhao
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [RFC 0/5] accel/kvm: Support KVM PMU filter
2024-07-10 4:51 [RFC 0/5] accel/kvm: Support KVM PMU filter Zhao Liu
` (5 preceding siblings ...)
2024-07-18 5:27 ` [RFC 0/5] accel/kvm: Support " Mi, Dapeng
@ 2024-08-02 9:01 ` Shaoqin Huang
2024-08-02 9:37 ` Zhao Liu
6 siblings, 1 reply; 15+ messages in thread
From: Shaoqin Huang @ 2024-08-02 9:01 UTC (permalink / raw)
To: Zhao Liu, Paolo Bonzini, Eric Blake, Markus Armbruster,
Michael Roth, Daniel P . Berrangé, Eduardo Habkost,
Marcelo Tosatti, Eric Auger, Peter Maydell, Laurent Vivier,
Thomas Huth, Sebastian Ott, Gavin Shan
Cc: qemu-devel, kvm, qemu-arm, Zhenyu Wang, Dapeng Mi, Yuan Yao,
Xiong Zhang, Mingwei Zhang, Jim Mattson
Hi Zhao,
On 7/10/24 12:51, Zhao Liu wrote:
> Hi QEMU maintainers, arm and PMU folks,
>
> I picked up Shaoqing's previous work [1] on the KVM PMU filter for arm,
> and now is trying to support this feature for x86 with a JSON-compatible
> API.
>
> While arm and x86 use different KVM ioctls to configure the PMU filter,
> considering they all have similar inputs (PMU event + action), it is
> still possible to abstract a generic, cross-architecture kvm-pmu-filter
> object and provide users with a sufficiently generic or near-consistent
> QAPI interface.
>
> That's what I did in this series, a new kvm-pmu-filter object, with the
> API like:
>
> -object '{"qom-type":"kvm-pmu-filter","id":"f0","events":[{"action":"allow","format":"raw","code":"0xc4"}]}'
>
> For i386, this object is inserted into kvm accelerator and is extended
> to support fixed-counter and more formats ("x86-default" and
> "x86-masked-entry"):
>
> -accel kvm,pmu-filter=f0 \
> -object pmu='{"qom-type":"kvm-pmu-filter","id":"f0","x86-fixed-counter":{"action":"allow","bitmap":"0x0"},"events":[{"action":"allow","format":"x86-masked-entry","select":"0xc4","mask":"0xff","match":"0","exclude":true},{"action":"allow","format":"x86-masked-entry","select":"0xc5","mask":"0xff","match":"0","exclude":true}]}'
What if I want to create the PMU Filter on ARM to deny the event range
[0x5,0x10], and allow deny event 0x13, how should I write the json?
Thanks,
Shaoqin
>
> This object can still be added as the property to the arch CPU if it is
> desired as a per CPU feature (as Shaoqin did for arm before).
>
> Welcome your feedback and comments!
>
>
> Introduction
> ============
>
>
> Formats supported in kvm-pmu-filter
> -----------------------------------
>
> This series supports 3 formats:
>
> * raw format (general format).
>
> This format indicates the code that has been encoded to be able to
> index the PMU events, and which can be delivered directly to the KVM
> ioctl. For arm, this means the event code, and for i386, this means
> the raw event with the layout like:
>
> select high bit | umask | select low bits
>
> * x86-default format (i386 specific)
>
> x86 commonly uses select&umask to identify PMU events, and this format
> is used to support the select&umask. Then QEMU will encode select and
> umask into a raw format code.
>
> * x86-masked-entry (i386 specific)
>
> This is a special format that x86's KVM_SET_PMU_EVENT_FILTER supports.
>
>
> Hexadecimal value string
> ------------------------
>
> In practice, the values associated with PMU events (code for arm, select&
> umask for x86) are often expressed in hexadecimal. Further, from linux
> perf related information (tools/perf/pmu-events/arch/*/*/*.json), x86/
> arm64/riscv/nds32/powerpc all prefer the hexadecimal numbers and only
> s390 uses decimal value.
>
> Therefore, it is necessary to support hexadecimal in order to honor PMU
> conventions.
>
> However, unfortunately, standard JSON (RFC 8259) does not support
> hexadecimal numbers. So I can only consider using the numeric string in
> the QAPI and then parsing it to a number.
>
> To achieve this, I defined two versions of PMU-related structures in
> kvm.json:
> * a native version that accepts numeric values, which is used for
> QEMU's internal code processing,
>
> * and a variant version that accepts numeric string, which is used to
> receive user input.
>
> kvm-pmu-filter object will take care of converting the string version
> of the event/counter information into the numeric version.
>
> The related implementation can be found in patch 1.
>
>
> CPU property v.s. KVM property
> ------------------------------
>
> In Shaoqin's previous implementation [1], KVM PMU filter is made as a
> arm CPU property. This is because arm uses a per CPU ioctl
> (KVM_SET_DEVICE_ATTR) to configure KVM PMU filter.
>
> However, for x86, the dependent ioctl (KVM_SET_PMU_EVENT_FILTER) is per
> VM. In the meantime, considering that for hybrid architecture, maybe in
> the future there will be a new per vCPU ioctl, or there will be
> practices to support filter fixed counter by configuring CPUIDs.
>
> Based on the above thoughts, for x86, it is not appropriate to make the
> current per-VM ioctl-based PMU filter a CPU property. Instead, I make it
> a kvm property and configure it via "-accel kvm,pmu-filter=obj_id".
>
> So in summary, it is feasible to use the KVM PMU filter as either a CPU
> or a KVM property, depending on whether it is used as a CPU feature or a
> VM feature.
>
> The kvm-pmu-filter object, as an abstraction, is general enough to
> support filter configurations for different scopes (per-CPU or per-VM).
>
>
> [1]: https://lore.kernel.org/qemu-devel/20240409024940.180107-1-shahuang@redhat.com/
>
> Thanks and Best Regards,
> Zhao
> ---
> Zhao Liu (5):
> qapi/qom: Introduce kvm-pmu-filter object
> i386/kvm: Support initial KVM PMU filter
> i386/kvm: Support event with select&umask format in KVM PMU filter
> i386/kvm: Support event with masked entry format in KVM PMU filter
> i386/kvm: Support fixed counter in KVM PMU filter
>
> MAINTAINERS | 1 +
> accel/kvm/kvm-pmu.c | 367 +++++++++++++++++++++++++++++++++++++
> accel/kvm/meson.build | 1 +
> include/sysemu/kvm-pmu.h | 43 +++++
> include/sysemu/kvm_int.h | 2 +
> qapi/kvm.json | 255 ++++++++++++++++++++++++++
> qapi/meson.build | 1 +
> qapi/qapi-schema.json | 1 +
> qapi/qom.json | 3 +
> target/i386/kvm/kvm.c | 211 +++++++++++++++++++++
> target/i386/kvm/kvm_i386.h | 1 +
> 11 files changed, 886 insertions(+)
> create mode 100644 accel/kvm/kvm-pmu.c
> create mode 100644 include/sysemu/kvm-pmu.h
> create mode 100644 qapi/kvm.json
>
--
Shaoqin
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [RFC 0/5] accel/kvm: Support KVM PMU filter
2024-08-02 9:01 ` Shaoqin Huang
@ 2024-08-02 9:37 ` Zhao Liu
2024-08-02 9:41 ` Shaoqin Huang
0 siblings, 1 reply; 15+ messages in thread
From: Zhao Liu @ 2024-08-02 9:37 UTC (permalink / raw)
To: Shaoqin Huang
Cc: Paolo Bonzini, Eric Blake, Markus Armbruster, Michael Roth,
Daniel P . Berrangé, Eduardo Habkost, Marcelo Tosatti,
Eric Auger, Peter Maydell, Laurent Vivier, Thomas Huth,
Sebastian Ott, Gavin Shan, qemu-devel, kvm, qemu-arm, Zhenyu Wang,
Dapeng Mi, Yuan Yao, Xiong Zhang, Mingwei Zhang, Jim Mattson
Hello Shaoqin,
On Fri, Aug 02, 2024 at 05:01:47PM +0800, Shaoqin Huang wrote:
> Date: Fri, 2 Aug 2024 17:01:47 +0800
> From: Shaoqin Huang <shahuang@redhat.com>
> Subject: Re: [RFC 0/5] accel/kvm: Support KVM PMU filter
>
> Hi Zhao,
>
> On 7/10/24 12:51, Zhao Liu wrote:
> > Hi QEMU maintainers, arm and PMU folks,
> >
> > I picked up Shaoqing's previous work [1] on the KVM PMU filter for arm,
> > and now is trying to support this feature for x86 with a JSON-compatible
> > API.
> >
> > While arm and x86 use different KVM ioctls to configure the PMU filter,
> > considering they all have similar inputs (PMU event + action), it is
> > still possible to abstract a generic, cross-architecture kvm-pmu-filter
> > object and provide users with a sufficiently generic or near-consistent
> > QAPI interface.
> >
> > That's what I did in this series, a new kvm-pmu-filter object, with the
> > API like:
> >
> > -object '{"qom-type":"kvm-pmu-filter","id":"f0","events":[{"action":"allow","format":"raw","code":"0xc4"}]}'
> >
> > For i386, this object is inserted into kvm accelerator and is extended
> > to support fixed-counter and more formats ("x86-default" and
> > "x86-masked-entry"):
> >
> > -accel kvm,pmu-filter=f0 \
> > -object pmu='{"qom-type":"kvm-pmu-filter","id":"f0","x86-fixed-counter":{"action":"allow","bitmap":"0x0"},"events":[{"action":"allow","format":"x86-masked-entry","select":"0xc4","mask":"0xff","match":"0","exclude":true},{"action":"allow","format":"x86-masked-entry","select":"0xc5","mask":"0xff","match":"0","exclude":true}]}'
>
> What if I want to create the PMU Filter on ARM to deny the event range
> [0x5,0x10], and allow deny event 0x13, how should I write the json?
>
Cuurently this doesn't support the event range (since the raw format of
x86 event cannot be said to be continuous).
So with the basic support, we need to configure events one by one:
-object pmu='{"qom-type":"kvm-pmu-filter","id":"f0","events":[{"action":"allow","format":"raw","code":"0x5"},{"action":"allow","format":"raw","select":"0x6"},{"action":"allow","format":"raw","code":"0x7"},{"action":"allow","format":"raw","code":"0x8"},{"action":"allow","format":"raw","code":"0x9"},{"action":"allow","format":"raw","code":"0x10"},{"action":"deny","format":"raw","code":"0x13"}]}'
This one looks a lot more complicated, but in the future, arm could
further support event-range (maybe implement event-range via mask), but
I think this could be arch-specific format since not all architectures'
events are continuous.
Additional, I'm a bit confused by your example, and I hope you can help
me understand that: when configuring 0x5~0x10 to be allow, isn't it true
that all other events are denied by default, so denying 0x13 again is a
redundant operation? What is the default action for all other events
except 0x5~0x10 and 0x13?
If we specify action as allow for 0x5~0x10 and deny for the rest by
default, then there is no need to set an action for each event but only
a global one (as suggested by Dapeng), so the above command line can be
simplified as:
-object pmu='{"qom-type":"kvm-pmu-filter","id":"f0","action":"allow","events":[{"format":"raw","code":"0x5"},{"format":"raw","select":"0x6"},{"format":"raw","code":"0x7"},{"format":"raw","code":"0x8"},{"format":"raw","code":"0x9"},{"format":"raw","code":"0x10"}]}'
Thanks,
Zhao
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [RFC 0/5] accel/kvm: Support KVM PMU filter
2024-08-02 9:37 ` Zhao Liu
@ 2024-08-02 9:41 ` Shaoqin Huang
2024-08-02 10:03 ` Zhao Liu
0 siblings, 1 reply; 15+ messages in thread
From: Shaoqin Huang @ 2024-08-02 9:41 UTC (permalink / raw)
To: Zhao Liu
Cc: Paolo Bonzini, Eric Blake, Markus Armbruster, Michael Roth,
Daniel P. Berrangé, Eduardo Habkost, Marcelo Tosatti,
Eric Auger, Peter Maydell, Laurent Vivier, Thomas Huth,
Sebastian Ott, Gavin Shan, qemu-devel, kvm, qemu-arm, Zhenyu Wang,
Dapeng Mi, Yuan Yao, Xiong Zhang, Mingwei Zhang, Jim Mattson
Hi Zhao,
On 8/2/24 17:37, Zhao Liu wrote:
> Hello Shaoqin,
>
> On Fri, Aug 02, 2024 at 05:01:47PM +0800, Shaoqin Huang wrote:
>> Date: Fri, 2 Aug 2024 17:01:47 +0800
>> From: Shaoqin Huang <shahuang@redhat.com>
>> Subject: Re: [RFC 0/5] accel/kvm: Support KVM PMU filter
>>
>> Hi Zhao,
>>
>> On 7/10/24 12:51, Zhao Liu wrote:
>>> Hi QEMU maintainers, arm and PMU folks,
>>>
>>> I picked up Shaoqing's previous work [1] on the KVM PMU filter for arm,
>>> and now is trying to support this feature for x86 with a JSON-compatible
>>> API.
>>>
>>> While arm and x86 use different KVM ioctls to configure the PMU filter,
>>> considering they all have similar inputs (PMU event + action), it is
>>> still possible to abstract a generic, cross-architecture kvm-pmu-filter
>>> object and provide users with a sufficiently generic or near-consistent
>>> QAPI interface.
>>>
>>> That's what I did in this series, a new kvm-pmu-filter object, with the
>>> API like:
>>>
>>> -object '{"qom-type":"kvm-pmu-filter","id":"f0","events":[{"action":"allow","format":"raw","code":"0xc4"}]}'
>>>
>>> For i386, this object is inserted into kvm accelerator and is extended
>>> to support fixed-counter and more formats ("x86-default" and
>>> "x86-masked-entry"):
>>>
>>> -accel kvm,pmu-filter=f0 \
>>> -object pmu='{"qom-type":"kvm-pmu-filter","id":"f0","x86-fixed-counter":{"action":"allow","bitmap":"0x0"},"events":[{"action":"allow","format":"x86-masked-entry","select":"0xc4","mask":"0xff","match":"0","exclude":true},{"action":"allow","format":"x86-masked-entry","select":"0xc5","mask":"0xff","match":"0","exclude":true}]}'
>>
>> What if I want to create the PMU Filter on ARM to deny the event range
>> [0x5,0x10], and allow deny event 0x13, how should I write the json?
>>
>
> Cuurently this doesn't support the event range (since the raw format of
> x86 event cannot be said to be continuous).
>
> So with the basic support, we need to configure events one by one:
>
> -object pmu='{"qom-type":"kvm-pmu-filter","id":"f0","events":[{"action":"allow","format":"raw","code":"0x5"},{"action":"allow","format":"raw","select":"0x6"},{"action":"allow","format":"raw","code":"0x7"},{"action":"allow","format":"raw","code":"0x8"},{"action":"allow","format":"raw","code":"0x9"},{"action":"allow","format":"raw","code":"0x10"},{"action":"deny","format":"raw","code":"0x13"}]}'
>
> This one looks a lot more complicated, but in the future, arm could
> further support event-range (maybe implement event-range via mask), but
> I think this could be arch-specific format since not all architectures'
> events are continuous.
>
> Additional, I'm a bit confused by your example, and I hope you can help
> me understand that: when configuring 0x5~0x10 to be allow, isn't it true
> that all other events are denied by default, so denying 0x13 again is a
> redundant operation? What is the default action for all other events
> except 0x5~0x10 and 0x13?
>
> If we specify action as allow for 0x5~0x10 and deny for the rest by
> default, then there is no need to set an action for each event but only
> a global one (as suggested by Dapeng), so the above command line can be
> simplified as:
>
> -object pmu='{"qom-type":"kvm-pmu-filter","id":"f0","action":"allow","events":[{"format":"raw","code":"0x5"},{"format":"raw","select":"0x6"},{"format":"raw","code":"0x7"},{"format":"raw","code":"0x8"},{"format":"raw","code":"0x9"},{"format":"raw","code":"0x10"}]}'
>
Yes you are right. On Arm when you first set the PMU Filter, if the
first filter is allow, then all other event will be denied by default.
The reverse is also the same, if the first filter is deny, then all
other event will be allowed by default.
On ARM the PMU Filter is much more simper than x86 I think. We only need
to care about the special event with allow or deny action.
If we don't support event range filter, I think that's fine. This can be
added in the future.
Thanks,
Shaoqin
> Thanks,
> Zhao
>
--
Shaoqin
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [RFC 0/5] accel/kvm: Support KVM PMU filter
2024-08-02 9:41 ` Shaoqin Huang
@ 2024-08-02 10:03 ` Zhao Liu
0 siblings, 0 replies; 15+ messages in thread
From: Zhao Liu @ 2024-08-02 10:03 UTC (permalink / raw)
To: Shaoqin Huang
Cc: Paolo Bonzini, Eric Blake, Markus Armbruster, Michael Roth,
Daniel P. Berrangé, Eduardo Habkost, Marcelo Tosatti,
Eric Auger, Peter Maydell, Laurent Vivier, Thomas Huth,
Sebastian Ott, Gavin Shan, qemu-devel, kvm, qemu-arm, Zhenyu Wang,
Dapeng Mi, Yuan Yao, Xiong Zhang, Mingwei Zhang, Jim Mattson
On Fri, Aug 02, 2024 at 05:41:57PM +0800, Shaoqin Huang wrote:
> Date: Fri, 2 Aug 2024 17:41:57 +0800
> From: Shaoqin Huang <shahuang@redhat.com>
> Subject: Re: [RFC 0/5] accel/kvm: Support KVM PMU filter
>
> Hi Zhao,
>
> On 8/2/24 17:37, Zhao Liu wrote:
> > Hello Shaoqin,
> >
> > On Fri, Aug 02, 2024 at 05:01:47PM +0800, Shaoqin Huang wrote:
> > > Date: Fri, 2 Aug 2024 17:01:47 +0800
> > > From: Shaoqin Huang <shahuang@redhat.com>
> > > Subject: Re: [RFC 0/5] accel/kvm: Support KVM PMU filter
> > >
> > > Hi Zhao,
> > >
> > > On 7/10/24 12:51, Zhao Liu wrote:
> > > > Hi QEMU maintainers, arm and PMU folks,
> > > >
> > > > I picked up Shaoqing's previous work [1] on the KVM PMU filter for arm,
> > > > and now is trying to support this feature for x86 with a JSON-compatible
> > > > API.
> > > >
> > > > While arm and x86 use different KVM ioctls to configure the PMU filter,
> > > > considering they all have similar inputs (PMU event + action), it is
> > > > still possible to abstract a generic, cross-architecture kvm-pmu-filter
> > > > object and provide users with a sufficiently generic or near-consistent
> > > > QAPI interface.
> > > >
> > > > That's what I did in this series, a new kvm-pmu-filter object, with the
> > > > API like:
> > > >
> > > > -object '{"qom-type":"kvm-pmu-filter","id":"f0","events":[{"action":"allow","format":"raw","code":"0xc4"}]}'
> > > >
> > > > For i386, this object is inserted into kvm accelerator and is extended
> > > > to support fixed-counter and more formats ("x86-default" and
> > > > "x86-masked-entry"):
> > > >
> > > > -accel kvm,pmu-filter=f0 \
> > > > -object pmu='{"qom-type":"kvm-pmu-filter","id":"f0","x86-fixed-counter":{"action":"allow","bitmap":"0x0"},"events":[{"action":"allow","format":"x86-masked-entry","select":"0xc4","mask":"0xff","match":"0","exclude":true},{"action":"allow","format":"x86-masked-entry","select":"0xc5","mask":"0xff","match":"0","exclude":true}]}'
> > >
> > > What if I want to create the PMU Filter on ARM to deny the event range
> > > [0x5,0x10], and allow deny event 0x13, how should I write the json?
> > >
> >
> > Cuurently this doesn't support the event range (since the raw format of
> > x86 event cannot be said to be continuous).
> >
> > So with the basic support, we need to configure events one by one:
> >
> > -object pmu='{"qom-type":"kvm-pmu-filter","id":"f0","events":[{"action":"allow","format":"raw","code":"0x5"},{"action":"allow","format":"raw","select":"0x6"},{"action":"allow","format":"raw","code":"0x7"},{"action":"allow","format":"raw","code":"0x8"},{"action":"allow","format":"raw","code":"0x9"},{"action":"allow","format":"raw","code":"0x10"},{"action":"deny","format":"raw","code":"0x13"}]}'
> >
> > This one looks a lot more complicated, but in the future, arm could
> > further support event-range (maybe implement event-range via mask), but
> > I think this could be arch-specific format since not all architectures'
> > events are continuous.
> >
> > Additional, I'm a bit confused by your example, and I hope you can help
> > me understand that: when configuring 0x5~0x10 to be allow, isn't it true
> > that all other events are denied by default, so denying 0x13 again is a
> > redundant operation? What is the default action for all other events
> > except 0x5~0x10 and 0x13?
> >
> > If we specify action as allow for 0x5~0x10 and deny for the rest by
> > default, then there is no need to set an action for each event but only
> > a global one (as suggested by Dapeng), so the above command line can be
> > simplified as:
> >
> > -object pmu='{"qom-type":"kvm-pmu-filter","id":"f0","action":"allow","events":[{"format":"raw","code":"0x5"},{"format":"raw","select":"0x6"},{"format":"raw","code":"0x7"},{"format":"raw","code":"0x8"},{"format":"raw","code":"0x9"},{"format":"raw","code":"0x10"}]}'
> >
>
> Yes you are right. On Arm when you first set the PMU Filter, if the first
> filter is allow, then all other event will be denied by default. The reverse
> is also the same, if the first filter is deny, then all other event will be
> allowed by default.
>
> On ARM the PMU Filter is much more simper than x86 I think. We only need to
> care about the special event with allow or deny action.
>
> If we don't support event range filter, I think that's fine. This can be
> added in the future.
This is good news for me, I can implement global action in the next
version and iterate further! Thank you for your confirmation!
Regards,
Zhao
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2024-08-02 9:49 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-07-10 4:51 [RFC 0/5] accel/kvm: Support KVM PMU filter Zhao Liu
2024-07-10 4:51 ` [RFC 1/5] qapi/qom: Introduce kvm-pmu-filter object Zhao Liu
2024-07-10 4:51 ` [RFC 2/5] i386/kvm: Support initial KVM PMU filter Zhao Liu
2024-07-10 4:51 ` [RFC 3/5] i386/kvm: Support event with select&umask format in " Zhao Liu
2024-07-18 5:28 ` Mi, Dapeng
2024-07-19 8:40 ` Zhao Liu
2024-07-23 5:36 ` Mi, Dapeng
2024-07-10 4:51 ` [RFC 4/5] i386/kvm: Support event with masked entry " Zhao Liu
2024-07-10 4:51 ` [RFC 5/5] i386/kvm: Support fixed counter " Zhao Liu
2024-07-18 5:27 ` [RFC 0/5] accel/kvm: Support " Mi, Dapeng
2024-07-19 8:05 ` Zhao Liu
2024-08-02 9:01 ` Shaoqin Huang
2024-08-02 9:37 ` Zhao Liu
2024-08-02 9:41 ` Shaoqin Huang
2024-08-02 10:03 ` Zhao Liu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).