Skip to content

Commit de17fdf

Browse files
committed
tests: add qrexec performance tests
Add simple connection latency, and throughput tests. Run them with different type of services (scripts, socket, via fork-server or not). They print a test run time for comparison - the lower the better. The tests can be also started outside of the full test run by calling /usr/lib/qubes/tests/qrexec_perf.py. It requires giving names of two existing and running VMs. QubesOS/qubes-issues#5740
1 parent 6cd9523 commit de17fdf

File tree

5 files changed

+375
-0
lines changed

5 files changed

+375
-0
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,8 @@ endif
235235
mkdir -p "$(DESTDIR)$(FILESDIR)"
236236
cp -r templates "$(DESTDIR)$(FILESDIR)/templates"
237237
cp -r tests-data "$(DESTDIR)$(FILESDIR)/tests-data"
238+
mkdir -p "$(DESTDIR)/usr/lib/qubes"
239+
cp -r tests "$(DESTDIR)/usr/lib/qubes/"
238240
rm -f "$(DESTDIR)$(FILESDIR)/templates/README"
239241

240242
mkdir -p "$(DESTDIR)$(DOCDIR)"

qubes/tests/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1825,6 +1825,7 @@ def load_tests(loader, tests, pattern): # pylint: disable=unused-argument
18251825
"qubes.tests.integ.devices_block",
18261826
"qubes.tests.integ.devices_pci",
18271827
"qubes.tests.integ.qrexec",
1828+
"qubes.tests.integ.qrexec_perf",
18281829
"qubes.tests.integ.dom0_update",
18291830
"qubes.tests.integ.vm_update",
18301831
"qubes.tests.integ.network",

qubes/tests/integ/qrexec_perf.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#
2+
# The Qubes OS Project, https://www.qubes-os.org/
3+
#
4+
# Copyright (C) 2025 Marek Marczykowski-Górecki
5+
6+
#
7+
# This program is free software; you can redistribute it and/or modify
8+
# it under the terms of the GNU Lesser General Public License as published by
9+
# the Free Software Foundation; either version 2.1 of the License, or
10+
# (at your option) any later version.
11+
#
12+
# This program is distributed in the hope that it will be useful,
13+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
# GNU Lesser General Public License for more details.
16+
#
17+
# You should have received a copy of the GNU Lesser General Public License along
18+
# with this program; if not, see <http://www.gnu.org/licenses/>.
19+
20+
import asyncio
21+
import os
22+
import subprocess
23+
import sys
24+
import time
25+
26+
import qubes.tests
27+
28+
29+
class TC_00_QrexecPerfMixin:
30+
def setUp(self: qubes.tests.SystemTestCase):
31+
super().setUp()
32+
self.vm1 = self.app.add_new_vm(
33+
"AppVM",
34+
name=self.make_vm_name("vm1"),
35+
label="red",
36+
)
37+
self.vm2 = self.app.add_new_vm(
38+
"AppVM",
39+
name=self.make_vm_name("vm2"),
40+
label="red",
41+
)
42+
self.loop.run_until_complete(
43+
asyncio.gather(
44+
self.vm1.create_on_disk(),
45+
self.vm2.create_on_disk(),
46+
)
47+
)
48+
self.loop.run_until_complete(
49+
asyncio.gather(
50+
self.vm1.start(),
51+
self.vm2.start(),
52+
)
53+
)
54+
55+
def run_test(self, name):
56+
cmd = [
57+
"/usr/lib/qubes/tests/qrexec_perf.py",
58+
f"--vm1={self.vm1.name}",
59+
f"--vm2={self.vm2.name}",
60+
name,
61+
]
62+
p = self.loop.run_until_complete(asyncio.create_subprocess_exec(*cmd))
63+
self.loop.run_until_complete(p.wait())
64+
if p.returncode:
65+
self.fail(f"'{' '.join(cmd)}' failed: {p.returncode}")
66+
67+
def test_000_simple(self):
68+
"""Measure simple exec-based vm-vm calls latency"""
69+
self.loop.run_until_complete(self.wait_for_session(self.vm2))
70+
self.run_test("exec")
71+
72+
def test_010_simple_root(self):
73+
"""Measure simple exec-based vm-vm calls latency, use root to
74+
bypass qrexec-fork-server"""
75+
self.run_test("exec-root")
76+
77+
def test_020_socket(self):
78+
"""Measure simple socket-based vm-vm calls latency"""
79+
self.run_test("socket")
80+
81+
def test_030_socket_root(self):
82+
"""Measure simple socket-based vm-vm calls latency, use root to
83+
bypass qrexec-fork-server"""
84+
self.run_test("socket-root")
85+
86+
def test_100_simple_data_simplex(self):
87+
"""Measure simple exec-based vm-vm calls throughput"""
88+
self.run_test("exec-data-simplex")
89+
90+
def test_110_simple_data_duplex(self):
91+
"""Measure simple exec-based vm-vm calls throughput"""
92+
self.run_test("exec-data-duplex")
93+
94+
def test_120_simple_data_duplex_root(self):
95+
"""Measure simple exec-based vm-vm calls throughput"""
96+
self.run_test("exec-data-duplex-root")
97+
98+
def test_130_socket_data_duplex(self):
99+
"""Measure simple socket-based vm-vm calls throughput"""
100+
self.run_test("socket-data-duplex")
101+
102+
103+
def create_testcases_for_templates():
104+
return qubes.tests.create_testcases_for_templates(
105+
"TC_00_QrexecPerf",
106+
TC_00_QrexecPerfMixin,
107+
qubes.tests.SystemTestCase,
108+
module=sys.modules[__name__],
109+
)
110+
111+
112+
def load_tests(loader, tests, pattern):
113+
tests.addTests(loader.loadTestsFromNames(create_testcases_for_templates()))
114+
return tests
115+
116+
117+
qubes.tests.maybe_create_testcases_on_import(create_testcases_for_templates)

rpm_spec/core-dom0.spec.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,7 @@ done
526526
%{python3_sitelib}/qubes/tests/integ/grub.py
527527
%{python3_sitelib}/qubes/tests/integ/salt.py
528528
%{python3_sitelib}/qubes/tests/integ/qrexec.py
529+
%{python3_sitelib}/qubes/tests/integ/qrexec_perf.py
529530
%{python3_sitelib}/qubes/tests/integ/storage.py
530531
%{python3_sitelib}/qubes/tests/integ/vm_qrexec_gui.py
531532

@@ -547,6 +548,7 @@ done
547548
/usr/lib/qubes/cleanup-dispvms
548549
/usr/lib/qubes/fix-dir-perms.sh
549550
/usr/lib/qubes/startup-misc.sh
551+
/usr/lib/qubes/tests/qrexec_perf.py
550552
%{_unitdir}/[email protected]/30_qubes.conf
551553
%{_unitdir}/qubes-core.service
552554
%{_unitdir}/qubes-qmemman.service

0 commit comments

Comments
 (0)