Skip to content

Commit f383ef8

Browse files
committed
test: add a test that checks for starved VirtIO devices
Firecracker IO is software emulated by the VMM thread of the Firecracker process. This is a single thread so it could be the case that a single device can starve other devices. This could happen if a guest keeps adding descriptors in a queue while we are processing it. Our emulation logic should include railguards against such behaviour. Add a test that verifies that this is the case. Signed-off-by: Babis Chalios <[email protected]>
1 parent 44be081 commit f383ef8

File tree

1 file changed

+96
-0
lines changed

1 file changed

+96
-0
lines changed

tests/integration_tests/functional/test_drive_virtio.py

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,21 @@
22
# SPDX-License-Identifier: Apache-2.0
33
"""Tests for guest-side operations on /drives resources."""
44

5+
import concurrent
56
import os
7+
import time
68

79
import pytest
810

911
import host_tools.drive as drive_tools
1012
from framework import utils
1113
from framework.utils_drive import partuuid_and_disk_path
14+
from integration_tests.performance.test_block_ab import (
15+
BLOCK_DEVICE_SIZE_MB,
16+
RUNTIME_SEC,
17+
WARMUP_SEC,
18+
prepare_microvm_for_test,
19+
)
1220

1321
MB = 1024 * 1024
1422

@@ -383,3 +391,91 @@ def _check_mount(ssh_connection, dev_path):
383391
assert stderr == ""
384392
_, _, stderr = ssh_connection.run("umount /tmp", timeout=30.0)
385393
assert stderr == ""
394+
395+
396+
def run_fio(microvm, mode, block_size, test_output_dir, fio_engine="libaio"):
397+
"""Run a fio test in the specified mode with block size bs."""
398+
cmd = (
399+
utils.CmdBuilder("fio")
400+
.with_arg(f"--name={mode}-{block_size}")
401+
.with_arg(f"--numjobs={microvm.vcpus_count}")
402+
.with_arg(f"--runtime={RUNTIME_SEC}")
403+
.with_arg("--time_based=1")
404+
.with_arg(f"--ramp_time={WARMUP_SEC}")
405+
.with_arg("--filename=/dev/vdb")
406+
.with_arg("--direct=1")
407+
.with_arg(f"--rw={mode}")
408+
.with_arg("--randrepeat=0")
409+
.with_arg(f"--bs={block_size}")
410+
.with_arg(f"--size={BLOCK_DEVICE_SIZE_MB}M")
411+
.with_arg(f"--ioengine={fio_engine}")
412+
.with_arg("--iodepth=32")
413+
# Set affinity of the entire fio process to a set of vCPUs equal in size to number of workers
414+
.with_arg(
415+
f"--cpus_allowed={','.join(str(i) for i in range(microvm.vcpus_count))}"
416+
)
417+
# Instruct fio to pin one worker per vcpu
418+
.with_arg("--cpus_allowed_policy=split")
419+
.with_arg("--log_avg_msec=1000")
420+
.with_arg(f"--write_bw_log={mode}")
421+
.with_arg("--output-format=json+")
422+
.with_arg("--output=/tmp/fio.json")
423+
)
424+
425+
# Latency measurements only make sense for psync engine
426+
if fio_engine == "psync":
427+
cmd = cmd.with_arg(f"--write_lat_log={mode}")
428+
429+
cmd = cmd.build()
430+
431+
prepare_microvm_for_test(microvm)
432+
433+
with concurrent.futures.ThreadPoolExecutor() as executor:
434+
executor.submit(_run_fio, microvm, test_output_dir)
435+
436+
for _ in range(30):
437+
microvm.ssh.check_output("true")
438+
time.sleep(1)
439+
440+
441+
def _run_fio(microvm, cmd, test_output_dir):
442+
rc, _, stderr = microvm.ssh.run(f"cd /tmp; {cmd}")
443+
assert rc == 0, stderr
444+
assert stderr == ""
445+
446+
microvm.ssh.scp_get("/tmp/fio.json", test_output_dir)
447+
microvm.ssh.scp_get("/tmp/*.log", test_output_dir)
448+
449+
450+
@pytest.mark.parametrize("vcpus", [1, 2], ids=["1vcpu", "2vcpu"])
451+
@pytest.mark.parametrize("fio_mode", ["randread", "randwrite"])
452+
@pytest.mark.parametrize("fio_block_size", [4096], ids=["bs4096"])
453+
@pytest.mark.parametrize("fio_engine", ["libaio", "psync"])
454+
def test_greedy_block(
455+
microvm_factory,
456+
guest_kernel_acpi,
457+
rootfs,
458+
vcpus,
459+
fio_mode,
460+
fio_block_size,
461+
fio_engine,
462+
io_engine,
463+
metrics,
464+
results_dir,
465+
):
466+
"""
467+
Make sure that a guest continuously using the block device
468+
doesn't starve a Network device
469+
"""
470+
vm = microvm_factory.build(guest_kernel_acpi, rootfs, monitor_memory=False)
471+
vm.spawn(log_level="Info", emit_metrics=False)
472+
vm.basic_config(vcpu_count=vcpus, mem_size_mib=1024)
473+
vm.add_net_iface()
474+
475+
# Add a secondary block device for testing
476+
fs = drive_tools.FilesystemFile(os.path.join(vm.fsfiles, "scratch"), 4096)
477+
vm.add_drive("scratch", fs.path, io_engine=io_engine)
478+
479+
vm.start()
480+
481+
cpu_util = run_fio(vm, fio_mode, fio_block_size, results_dir, fio_engine)

0 commit comments

Comments
 (0)