From dd6ae2d9bb866044b893577f6138621f2a4c64bd Mon Sep 17 00:00:00 2001 From: "Houqi (Nick) Zuo" Date: Wed, 29 Nov 2023 18:33:36 +0800 Subject: [PATCH] qemu_vm.py: implement the iothread scheme. implement the iothread scheme. Signed-off-by: Houqi (Nick) Zuo --- virttest/qemu_devices/qcontainer.py | 104 +++++++++++++++++++++++++++- virttest/qemu_vm.py | 40 ++++++++--- 2 files changed, 133 insertions(+), 11 deletions(-) diff --git a/virttest/qemu_devices/qcontainer.py b/virttest/qemu_devices/qcontainer.py index 623336e0f4..0c77b92d79 100644 --- a/virttest/qemu_devices/qcontainer.py +++ b/virttest/qemu_devices/qcontainer.py @@ -218,6 +218,7 @@ def get_qmp_cmds(qemu_binary, workaround_qemu_qmp_crash=False): self._probe_migration_parameters() self.__iothread_manager = None self.__iothread_supported_devices = set() + self.__iothread_vq_mapping_supported_devices = set() self.temporary_image_snapshots = set() @property @@ -300,11 +301,34 @@ def is_dev_iothread_supported(self, device): return True options = "--device %s,\\?" % device out = self.execute_qemu(options) - if "iothread" in out: + if re.findall("iothread=<[^>]+>+", out): self.__iothread_supported_devices.add(device) return True return False + def is_dev_iothread_vq_supported(self, device): + """Check if dev supports iothread-vq-mapping. + :param device: device to check + :type device: QDevice or string + """ + try: + device = device.get_param("driver") + except AttributeError: + if not isinstance(device, six.string_types): + raise TypeError("device: expected string or QDevice") + if not device: + return False + if device in self.__iothread_vq_mapping_supported_devices: + return True + options = "--device %s,\\?" % device + out = self.execute_qemu(options) + if re.findall("iothread-vq-mapping=<[^>]+>+", out) and ( + not device.startswith("virtio-scsi-pci") + ): + self.__iothread_vq_mapping_supported_devices.add(device) + return True + return False + def allocate_iothread(self, iothread, device): """ Allocate iothread for device to use. @@ -335,6 +359,44 @@ def allocate_iothread(self, iothread, device): ) raise TypeError(err_msg) + def allocate_iothread_vq(self, iothread, device): + """ + Allocate iothread( supporting vq ) for device to use. + + :param iothread: iothread specified in params + could be: + 'auto': allocate iothread based on schems specified by + 'iothread_scheme'. + iothread id: request specific iothread to use. + :param device: device object + :return: iothread object allocated + """ + if self.is_dev_iothread_vq_supported(device): + iothreads = self.iothread_manager.request_iothread(iothread) + iothreads_return = iothreads + if not isinstance(iothreads, Sequence): + iothreads = (iothreads,) + for iothread in iothreads: + dev_iothread_parent = {"busid": iothread.iothread_vq_bus.busid} + if device.parent_bus: + device.parent_bus += (dev_iothread_parent,) + else: + device.parent_bus = (dev_iothread_parent,) + + if isinstance( + self.iothread_manager, vt_iothread.MultiPeerRoundRobinManager + ): + self.iothread_manager.pci_dev_iothread_vq_mapping = { + device.get_qid(): iothreads[0] + } + return iothreads_return + else: + err_msg = "Device %s(%s) not support iothread-vq-mapping" % ( + device.get_aid(), + device.get_param("driver"), + ) + raise TypeError(err_msg) + def _probe_capabilities(self): """Probe capabilities.""" # -blockdev @@ -1985,7 +2047,7 @@ def images_define_by_variables( image_auto_readonly=None, image_discard=None, image_copy_on_read=None, - image_iothread_vq_mapping=None + image_iothread_vq_mapping=None, ): """ Creates related devices by variables @@ -2818,6 +2880,42 @@ def define_hbas( ) for key, value in blk_extra_params: devices[-1].set_param(key, value) + if self.is_dev_iothread_vq_supported(devices[-1]): + if num_queues: + devices[-1].set_param("num-queues", num_queues) + # add iothread-vq-mapping if available + if image_iothread_vq_mapping: + val = [] + for item in image_iothread_vq_mapping.strip().split(" "): + allocated_iothread = self.allocate_iothread_vq( + item.split(":")[0], devices[-1] + ) + mapping = {"iothread": allocated_iothread.get_qid()} + if len(item.split(":")) == 2: + vqs = [int(_) for _ in item.split(":")[-1].split(",")] + mapping["vqs"] = vqs + val.append(mapping) + # FIXME: The reason using set_param() is that the format( + # Example: iothread0:0,1,2 ) can NOT be set by + # Devcontainer.insert() appropriately since the contents + # following after colon are lost. + if ":" in image_iothread_vq_mapping: + devices[-1].set_param("iothread-vq-mapping", val) + + if isinstance( + self.iothread_manager, vt_iothread.MultiPeerRoundRobinManager + ): + mapping = self.iothread_manager.pci_dev_iothread_vq_mapping + if devices[-1].get_qid() in mapping: + num_iothread = len(mapping[devices[-1].get_qid()]) + for i in range(num_iothread): + iothread = self.allocate_iothread_vq("auto", devices[-1]) + iothread.iothread_vq_bus.insert(devices[-1]) + elif isinstance(self.iothread_manager, vt_iothread.FullManager): + iothreads = self.allocate_iothread_vq("auto", devices[-1]) + if iothreads: + for ioth in iothreads: + ioth.iothread_vq_bus.insert(devices[-1]) return devices def images_define_by_params( @@ -2954,7 +3052,7 @@ def images_define_by_params( image_params.get("image_auto_readonly"), image_params.get("image_discard"), image_params.get("image_copy_on_read"), - image_params.get("image_iothread_vq_mapping") + image_params.get("image_iothread_vq_mapping"), ) def serials_define_by_variables( diff --git a/virttest/qemu_vm.py b/virttest/qemu_vm.py index 257666b255..33d13253e9 100644 --- a/virttest/qemu_vm.py +++ b/virttest/qemu_vm.py @@ -46,6 +46,7 @@ utils_vdpa, utils_vsock, virt_vm, + vt_iothread, ) from virttest.qemu_capabilities import Flags from virttest.qemu_devices import qcontainer, qdevices @@ -1685,27 +1686,27 @@ def __iothread_conflict_check(params): :type params: dict """ iothread_scheme = params.get("iothread_scheme") - image_iothread_vq_mapping = params.get( - "image_iothread_vq_mapping") + image_iothread_vq_mapping = params.get("image_iothread_vq_mapping") iothreads_lst = params.objects("iothreads") # The legacy 'iothread_scheme' does NOT support the # parameter 'iothread_vqs_mapping'. If you're going to use the legacy # 'iothread_scheme', the 'iothread_vqs_mapping' must NOT be set. if (iothread_scheme and image_iothread_vq_mapping) or ( - iothread_scheme in ("multipeerroundrobin", "full" - ) and iothreads_lst): + iothread_scheme in ("multipeerroundrobin", "full") and iothreads_lst + ): raise ValueError( "There's a conflict in the configuration! Once " "'iothread_scheme' is set, 'image_iothread_vq_mapping' or" - " 'iothreads' can NOT be set!") + " 'iothreads' can NOT be set!" + ) for image_name in params.objects("images"): image_params = params.object_params(image_name) - if image_params.get( - "image_iothread_vq_mapping") and iothread_scheme: + if image_params.get("image_iothread_vq_mapping") and iothread_scheme: raise ValueError( "There's a conflict in the configuration! Once " "'iothread_scheme' is set, " - "'image_iothread_vq_mapping' can NOT be set!") + "'image_iothread_vq_mapping' can NOT be set!" + ) # End of command line option wrappers @@ -2450,6 +2451,7 @@ def __iothread_conflict_check(params): set_cmdline_format_by_cfg(dev, self._get_cmdline_format_cfg(), "images") devices.insert(dev) + image_devs = [] # Add images (harddrives) for image_name in params.objects("images"): # FIXME: Use qemu_devices for handling indexes @@ -2497,6 +2499,28 @@ def __iothread_conflict_check(params): for _ in devs: set_cmdline_format_by_cfg(_, self._get_cmdline_format_cfg(), "images") devices.insert(_) + image_devs.extend(devs) + # FIXME: Here's a workaround solution about allocating the iothreads. + # Due to adapting the multipeerroundrobin iothread scheme, + # allocating the iothreads has to be executed after all the related + # image devices are created completely. + iothread_lst = [] + img_pci_mapping = [] + for dev in devices: + if isinstance(dev, qdevices.QIOThread): + iothread_lst.append(dev) + for dev in image_devs: + if dev and devices.is_dev_iothread_vq_supported(dev): + img_pci_mapping.append(dev) + + if len(img_pci_mapping) > 0: + if isinstance( + devices.iothread_manager, vt_iothread.MultiPeerRoundRobinManager + ): + for i in range(len(iothread_lst)): + dev = img_pci_mapping[i % len(img_pci_mapping)] + iothread_assigned = devices.allocate_iothread_vq("auto", dev) + iothread_assigned.iothread_vq_bus.insert(dev) # Add filesystems for fs_name in params.objects("filesystems"):