diff --git a/virttest/qemu_devices/qcontainer.py b/virttest/qemu_devices/qcontainer.py index 209d43bdfb..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 @@ -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( diff --git a/virttest/qemu_vm.py b/virttest/qemu_vm.py index 68bc480391..b54bb3548c 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 @@ -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(max(len(iothread_lst), len(img_pci_mapping))): + 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"):