Skip to content

Commit

Permalink
qemu_vm.py: implement the iothread scheme
Browse files Browse the repository at this point in the history
implement the iothread scheme.

Signed-off-by: Houqi (Nick) Zuo <[email protected]>
  • Loading branch information
nickzhq committed Mar 19, 2024
1 parent 30f723b commit cf16df1
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 5 deletions.
100 changes: 99 additions & 1 deletion virttest/qemu_devices/qcontainer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand Down
33 changes: 29 additions & 4 deletions virttest/qemu_vm.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -1696,15 +1697,16 @@ def __iothread_conflict_check(params):
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

Expand Down Expand Up @@ -2449,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
Expand Down Expand Up @@ -2496,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"):
Expand Down

0 comments on commit cf16df1

Please sign in to comment.