virtio-blk and virtio-scsi devices will need a way to specify the
mapping between IOThreads and virtqueues. At the moment all virtqueues
are assigned to a single IOThread or the main loop. This single thread
can be a CPU bottleneck, so it is necessary to allow finer-grained
assignment to spread the load.
Introduce DEFINE_PROP_IOTHREAD_VQ_MAPPING_LIST() so devices can take a
parameter that maps virtqueues to IOThreads. The command-line syntax for
this new property is as follows:
--device '{"driver":"foo","iothread-vq-mapping":[{"iothread":"iothread0","vqs":[0,1,2]},...]}'
IOThreads are specified by name and virtqueues are specified by 0-based
index.
It will be common to simply assign virtqueues round-robin across a set
of IOThreads. A convenient syntax that does not require specifying
individual virtqueue indices is available:
--device '{"driver":"foo","iothread-vq-mapping":[{"iothread":"iothread0"},{"iothread":"iothread1"},...]}'
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
qapi/virtio.json | 30 ++++++++++++++++++
include/hw/qdev-properties-system.h | 4 +++
hw/core/qdev-properties-system.c | 47 +++++++++++++++++++++++++++++
3 files changed, 81 insertions(+)
diff --git a/qapi/virtio.json b/qapi/virtio.json
index e6dcee7b83..cb341ae596 100644
--- a/qapi/virtio.json
+++ b/qapi/virtio.json
@@ -928,3 +928,33 @@
'data': { 'path': 'str', 'queue': 'uint16', '*index': 'uint16' },
'returns': 'VirtioQueueElement',
'features': [ 'unstable' ] }
+
+##
+# @IOThreadVirtQueueMapping:
+#
+# Describes the subset of virtqueues assigned to an IOThread.
+#
+# @iothread: the id of IOThread object
+# @vqs: an optional array of virtqueue indices that will be handled by this
+# IOThread. When absent, virtqueues are assigned round-robin across all
+# IOThreadVirtQueueMappings provided. Either all
+# IOThreadVirtQueueMappings must have @vqs or none of them must have it.
+#
+# Since: 8.2
+#
+##
+
+{ 'struct': 'IOThreadVirtQueueMapping',
+ 'data': { 'iothread': 'str', '*vqs': ['uint16'] } }
+
+##
+# @IOThreadVirtQueueMappings:
+#
+# IOThreadVirtQueueMapping list. This struct is not actually used but the
+# IOThreadVirtQueueMappingList type it generates is!
+#
+# Since: 8.2
+##
+
+{ 'struct': 'IOThreadVirtQueueMappings',
+ 'data': { 'mappings': ['IOThreadVirtQueueMapping'] } }
diff --git a/include/hw/qdev-properties-system.h b/include/hw/qdev-properties-system.h
index 0ac327ae60..c526e502c8 100644
--- a/include/hw/qdev-properties-system.h
+++ b/include/hw/qdev-properties-system.h
@@ -22,6 +22,7 @@ extern const PropertyInfo qdev_prop_audiodev;
extern const PropertyInfo qdev_prop_off_auto_pcibar;
extern const PropertyInfo qdev_prop_pcie_link_speed;
extern const PropertyInfo qdev_prop_pcie_link_width;
+extern const PropertyInfo qdev_prop_iothread_vq_mapping_list;
#define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d) \
DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t)
@@ -73,5 +74,8 @@ extern const PropertyInfo qdev_prop_pcie_link_width;
#define DEFINE_PROP_UUID_NODEFAULT(_name, _state, _field) \
DEFINE_PROP(_name, _state, _field, qdev_prop_uuid, QemuUUID)
+#define DEFINE_PROP_IOTHREAD_VQ_MAPPING_LIST(_name, _state, _field) \
+ DEFINE_PROP(_name, _state, _field, qdev_prop_iothread_vq_mapping_list, \
+ IOThreadVirtQueueMappingList *)
#endif
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index 6d5d43eda2..831796e106 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -18,6 +18,7 @@
#include "qapi/qapi-types-block.h"
#include "qapi/qapi-types-machine.h"
#include "qapi/qapi-types-migration.h"
+#include "qapi/qapi-visit-virtio.h"
#include "qapi/qmp/qerror.h"
#include "qemu/ctype.h"
#include "qemu/cutils.h"
@@ -1147,3 +1148,49 @@ const PropertyInfo qdev_prop_uuid = {
.set = set_uuid,
.set_default_value = set_default_uuid_auto,
};
+
+/* --- IOThreadVirtQueueMappingList --- */
+
+static void get_iothread_vq_mapping_list(Object *obj, Visitor *v,
+ const char *name, void *opaque, Error **errp)
+{
+ IOThreadVirtQueueMappingList **prop_ptr =
+ object_field_prop_ptr(obj, opaque);
+ IOThreadVirtQueueMappingList *list = *prop_ptr;
+
+ visit_type_IOThreadVirtQueueMappingList(v, name, &list, errp);
+}
+
+static void set_iothread_vq_mapping_list(Object *obj, Visitor *v,
+ const char *name, void *opaque, Error **errp)
+{
+ IOThreadVirtQueueMappingList **prop_ptr =
+ object_field_prop_ptr(obj, opaque);
+ IOThreadVirtQueueMappingList *list;
+
+ if (!visit_type_IOThreadVirtQueueMappingList(v, name, &list, errp)) {
+ return;
+ }
+
+ qapi_free_IOThreadVirtQueueMappingList(*prop_ptr);
+ *prop_ptr = list;
+}
+
+static void release_iothread_vq_mapping_list(Object *obj,
+ const char *name, void *opaque)
+{
+ IOThreadVirtQueueMappingList **prop_ptr =
+ object_field_prop_ptr(obj, opaque);
+
+ qapi_free_IOThreadVirtQueueMappingList(*prop_ptr);
+ *prop_ptr = NULL;
+}
+
+const PropertyInfo qdev_prop_iothread_vq_mapping_list = {
+ .name = "IOThreadVirtQueueMappingList",
+ .description = "IOThread virtqueue mapping list [{\"iothread\":\"<id>\", "
+ "\"vqs\":[1,2,3,...]},...]",
+ .get = get_iothread_vq_mapping_list,
+ .set = set_iothread_vq_mapping_list,
+ .release = release_iothread_vq_mapping_list,
+};
--
2.41.0
Stefan Hajnoczi <stefanha@redhat.com> writes: > virtio-blk and virtio-scsi devices will need a way to specify the > mapping between IOThreads and virtqueues. At the moment all virtqueues > are assigned to a single IOThread or the main loop. This single thread > can be a CPU bottleneck, so it is necessary to allow finer-grained > assignment to spread the load. > > Introduce DEFINE_PROP_IOTHREAD_VQ_MAPPING_LIST() so devices can take a > parameter that maps virtqueues to IOThreads. The command-line syntax for > this new property is as follows: > > --device '{"driver":"foo","iothread-vq-mapping":[{"iothread":"iothread0","vqs":[0,1,2]},...]}' > > IOThreads are specified by name and virtqueues are specified by 0-based > index. > > It will be common to simply assign virtqueues round-robin across a set > of IOThreads. A convenient syntax that does not require specifying > individual virtqueue indices is available: > > --device '{"driver":"foo","iothread-vq-mapping":[{"iothread":"iothread0"},{"iothread":"iothread1"},...]}' > > Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> > --- > qapi/virtio.json | 30 ++++++++++++++++++ > include/hw/qdev-properties-system.h | 4 +++ > hw/core/qdev-properties-system.c | 47 +++++++++++++++++++++++++++++ > 3 files changed, 81 insertions(+) > > diff --git a/qapi/virtio.json b/qapi/virtio.json > index e6dcee7b83..cb341ae596 100644 > --- a/qapi/virtio.json > +++ b/qapi/virtio.json > @@ -928,3 +928,33 @@ > 'data': { 'path': 'str', 'queue': 'uint16', '*index': 'uint16' }, > 'returns': 'VirtioQueueElement', > 'features': [ 'unstable' ] } > + > +## > +# @IOThreadVirtQueueMapping: > +# > +# Describes the subset of virtqueues assigned to an IOThread. > +# > +# @iothread: the id of IOThread object > +# @vqs: an optional array of virtqueue indices that will be handled by this > +# IOThread. When absent, virtqueues are assigned round-robin across all > +# IOThreadVirtQueueMappings provided. Either all > +# IOThreadVirtQueueMappings must have @vqs or none of them must have it. > +# > +# Since: 8.2 > +# > +## Please format like ## # @IOThreadVirtQueueMapping: # # Describes the subset of virtqueues assigned to an IOThread. # # @iothread: the id of IOThread object # # @vqs: an optional array of virtqueue indices that will be handled by # this IOThread. When absent, virtqueues are assigned round-robin # across all IOThreadVirtQueueMappings provided. Either all # IOThreadVirtQueueMappings must have @vqs or none of them must # have it. # # Since: 8.2 ## to blend in with recent commit a937b6aa739 (qapi: Reformat doc comments to conform to current conventions). > + > +{ 'struct': 'IOThreadVirtQueueMapping', > + 'data': { 'iothread': 'str', '*vqs': ['uint16'] } } > + > +## > +# @IOThreadVirtQueueMappings: > +# > +# IOThreadVirtQueueMapping list. This struct is not actually used but the > +# IOThreadVirtQueueMappingList type it generates is! Two spaces between sentences for consistency, please. Doc comments are QMP reference documentation for users. Does this paragraph belong there? > +# > +# Since: 8.2 > +## > + > +{ 'struct': 'IOThreadVirtQueueMappings', > + 'data': { 'mappings': ['IOThreadVirtQueueMapping'] } } > diff --git a/include/hw/qdev-properties-system.h b/include/hw/qdev-properties-system.h > index 0ac327ae60..c526e502c8 100644 > --- a/include/hw/qdev-properties-system.h > +++ b/include/hw/qdev-properties-system.h > @@ -22,6 +22,7 @@ extern const PropertyInfo qdev_prop_audiodev; > extern const PropertyInfo qdev_prop_off_auto_pcibar; > extern const PropertyInfo qdev_prop_pcie_link_speed; > extern const PropertyInfo qdev_prop_pcie_link_width; > +extern const PropertyInfo qdev_prop_iothread_vq_mapping_list; > > #define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d) \ > DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t) > @@ -73,5 +74,8 @@ extern const PropertyInfo qdev_prop_pcie_link_width; > #define DEFINE_PROP_UUID_NODEFAULT(_name, _state, _field) \ > DEFINE_PROP(_name, _state, _field, qdev_prop_uuid, QemuUUID) > > +#define DEFINE_PROP_IOTHREAD_VQ_MAPPING_LIST(_name, _state, _field) \ > + DEFINE_PROP(_name, _state, _field, qdev_prop_iothread_vq_mapping_list, \ > + IOThreadVirtQueueMappingList *) > > #endif > diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c > index 6d5d43eda2..831796e106 100644 > --- a/hw/core/qdev-properties-system.c > +++ b/hw/core/qdev-properties-system.c > @@ -18,6 +18,7 @@ > #include "qapi/qapi-types-block.h" > #include "qapi/qapi-types-machine.h" > #include "qapi/qapi-types-migration.h" > +#include "qapi/qapi-visit-virtio.h" > #include "qapi/qmp/qerror.h" > #include "qemu/ctype.h" > #include "qemu/cutils.h" > @@ -1147,3 +1148,49 @@ const PropertyInfo qdev_prop_uuid = { > .set = set_uuid, > .set_default_value = set_default_uuid_auto, > }; > + > +/* --- IOThreadVirtQueueMappingList --- */ > + > +static void get_iothread_vq_mapping_list(Object *obj, Visitor *v, > + const char *name, void *opaque, Error **errp) > +{ > + IOThreadVirtQueueMappingList **prop_ptr = > + object_field_prop_ptr(obj, opaque); > + IOThreadVirtQueueMappingList *list = *prop_ptr; > + > + visit_type_IOThreadVirtQueueMappingList(v, name, &list, errp); @list is a copy of the property value. Why do you need to pass a copy to visit_type_IOThreadVirtQueueMappingList()? > +} > + > +static void set_iothread_vq_mapping_list(Object *obj, Visitor *v, > + const char *name, void *opaque, Error **errp) > +{ > + IOThreadVirtQueueMappingList **prop_ptr = > + object_field_prop_ptr(obj, opaque); > + IOThreadVirtQueueMappingList *list; > + > + if (!visit_type_IOThreadVirtQueueMappingList(v, name, &list, errp)) { > + return; > + } > + > + qapi_free_IOThreadVirtQueueMappingList(*prop_ptr); > + *prop_ptr = list; > +} > + > +static void release_iothread_vq_mapping_list(Object *obj, > + const char *name, void *opaque) > +{ > + IOThreadVirtQueueMappingList **prop_ptr = > + object_field_prop_ptr(obj, opaque); > + > + qapi_free_IOThreadVirtQueueMappingList(*prop_ptr); > + *prop_ptr = NULL; > +} > + > +const PropertyInfo qdev_prop_iothread_vq_mapping_list = { > + .name = "IOThreadVirtQueueMappingList", > + .description = "IOThread virtqueue mapping list [{\"iothread\":\"<id>\", " > + "\"vqs\":[1,2,3,...]},...]", > + .get = get_iothread_vq_mapping_list, > + .set = set_iothread_vq_mapping_list, > + .release = release_iothread_vq_mapping_list, > +};
© 2016 - 2023 Red Hat, Inc.