xref: /openbmc/qemu/tests/migration-stress/guestperf/engine.py (revision 45f34156e4d9c3f4215402b34d7da32f00073066)
1212c1933SFabiano Rosas#
2212c1933SFabiano Rosas# Migration test main engine
3212c1933SFabiano Rosas#
4212c1933SFabiano Rosas# Copyright (c) 2016 Red Hat, Inc.
5212c1933SFabiano Rosas#
6212c1933SFabiano Rosas# This library is free software; you can redistribute it and/or
7212c1933SFabiano Rosas# modify it under the terms of the GNU Lesser General Public
8212c1933SFabiano Rosas# License as published by the Free Software Foundation; either
9212c1933SFabiano Rosas# version 2.1 of the License, or (at your option) any later version.
10212c1933SFabiano Rosas#
11212c1933SFabiano Rosas# This library is distributed in the hope that it will be useful,
12212c1933SFabiano Rosas# but WITHOUT ANY WARRANTY; without even the implied warranty of
13212c1933SFabiano Rosas# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14212c1933SFabiano Rosas# Lesser General Public License for more details.
15212c1933SFabiano Rosas#
16212c1933SFabiano Rosas# You should have received a copy of the GNU Lesser General Public
17212c1933SFabiano Rosas# License along with this library; if not, see <http://www.gnu.org/licenses/>.
18212c1933SFabiano Rosas#
19212c1933SFabiano Rosas
20212c1933SFabiano Rosas
21212c1933SFabiano Rosasimport os
22212c1933SFabiano Rosasimport re
23212c1933SFabiano Rosasimport sys
24212c1933SFabiano Rosasimport time
25212c1933SFabiano Rosas
26212c1933SFabiano Rosasfrom guestperf.progress import Progress, ProgressStats
27212c1933SFabiano Rosasfrom guestperf.report import Report
28212c1933SFabiano Rosasfrom guestperf.timings import TimingRecord, Timings
29212c1933SFabiano Rosas
30212c1933SFabiano Rosassys.path.append(os.path.join(os.path.dirname(__file__),
31212c1933SFabiano Rosas                             '..', '..', '..', 'python'))
32212c1933SFabiano Rosasfrom qemu.machine import QEMUMachine
33212c1933SFabiano Rosas
34*45f34156SHyman Huang# multifd supported compression algorithms
35*45f34156SHyman HuangMULTIFD_CMP_ALGS = ("zlib", "zstd", "qpl", "uadk")
36212c1933SFabiano Rosas
37212c1933SFabiano Rosasclass Engine(object):
38212c1933SFabiano Rosas
39212c1933SFabiano Rosas    def __init__(self, binary, dst_host, kernel, initrd, transport="tcp",
40212c1933SFabiano Rosas                 sleep=15, verbose=False, debug=False):
41212c1933SFabiano Rosas
42212c1933SFabiano Rosas        self._binary = binary # Path to QEMU binary
43212c1933SFabiano Rosas        self._dst_host = dst_host # Hostname of target host
44212c1933SFabiano Rosas        self._kernel = kernel # Path to kernel image
45212c1933SFabiano Rosas        self._initrd = initrd # Path to stress initrd
46212c1933SFabiano Rosas        self._transport = transport # 'unix' or 'tcp' or 'rdma'
47212c1933SFabiano Rosas        self._sleep = sleep
48212c1933SFabiano Rosas        self._verbose = verbose
49212c1933SFabiano Rosas        self._debug = debug
50212c1933SFabiano Rosas
51212c1933SFabiano Rosas        if debug:
52212c1933SFabiano Rosas            self._verbose = debug
53212c1933SFabiano Rosas
54212c1933SFabiano Rosas    def _vcpu_timing(self, pid, tid_list):
55212c1933SFabiano Rosas        records = []
56212c1933SFabiano Rosas        now = time.time()
57212c1933SFabiano Rosas
58212c1933SFabiano Rosas        jiffies_per_sec = os.sysconf(os.sysconf_names['SC_CLK_TCK'])
59212c1933SFabiano Rosas        for tid in tid_list:
60212c1933SFabiano Rosas            statfile = "/proc/%d/task/%d/stat" % (pid, tid)
61212c1933SFabiano Rosas            with open(statfile, "r") as fh:
62212c1933SFabiano Rosas                stat = fh.readline()
63212c1933SFabiano Rosas                fields = stat.split(" ")
64212c1933SFabiano Rosas                stime = int(fields[13])
65212c1933SFabiano Rosas                utime = int(fields[14])
66212c1933SFabiano Rosas                records.append(TimingRecord(tid, now, 1000 * (stime + utime) / jiffies_per_sec))
67212c1933SFabiano Rosas        return records
68212c1933SFabiano Rosas
69212c1933SFabiano Rosas    def _cpu_timing(self, pid):
70212c1933SFabiano Rosas        now = time.time()
71212c1933SFabiano Rosas
72212c1933SFabiano Rosas        jiffies_per_sec = os.sysconf(os.sysconf_names['SC_CLK_TCK'])
73212c1933SFabiano Rosas        statfile = "/proc/%d/stat" % pid
74212c1933SFabiano Rosas        with open(statfile, "r") as fh:
75212c1933SFabiano Rosas            stat = fh.readline()
76212c1933SFabiano Rosas            fields = stat.split(" ")
77212c1933SFabiano Rosas            stime = int(fields[13])
78212c1933SFabiano Rosas            utime = int(fields[14])
79212c1933SFabiano Rosas            return TimingRecord(pid, now, 1000 * (stime + utime) / jiffies_per_sec)
80212c1933SFabiano Rosas
81212c1933SFabiano Rosas    def _migrate_progress(self, vm):
82212c1933SFabiano Rosas        info = vm.cmd("query-migrate")
83212c1933SFabiano Rosas
84212c1933SFabiano Rosas        if "ram" not in info:
85212c1933SFabiano Rosas            info["ram"] = {}
86212c1933SFabiano Rosas
87212c1933SFabiano Rosas        return Progress(
88212c1933SFabiano Rosas            info.get("status", "active"),
89212c1933SFabiano Rosas            ProgressStats(
90212c1933SFabiano Rosas                info["ram"].get("transferred", 0),
91212c1933SFabiano Rosas                info["ram"].get("remaining", 0),
92212c1933SFabiano Rosas                info["ram"].get("total", 0),
93212c1933SFabiano Rosas                info["ram"].get("duplicate", 0),
94212c1933SFabiano Rosas                info["ram"].get("skipped", 0),
95212c1933SFabiano Rosas                info["ram"].get("normal", 0),
96212c1933SFabiano Rosas                info["ram"].get("normal-bytes", 0),
97212c1933SFabiano Rosas                info["ram"].get("dirty-pages-rate", 0),
98212c1933SFabiano Rosas                info["ram"].get("mbps", 0),
99212c1933SFabiano Rosas                info["ram"].get("dirty-sync-count", 0)
100212c1933SFabiano Rosas            ),
101212c1933SFabiano Rosas            time.time(),
102212c1933SFabiano Rosas            info.get("total-time", 0),
103212c1933SFabiano Rosas            info.get("downtime", 0),
104212c1933SFabiano Rosas            info.get("expected-downtime", 0),
105212c1933SFabiano Rosas            info.get("setup-time", 0),
106212c1933SFabiano Rosas            info.get("cpu-throttle-percentage", 0),
107212c1933SFabiano Rosas            info.get("dirty-limit-throttle-time-per-round", 0),
108212c1933SFabiano Rosas            info.get("dirty-limit-ring-full-time", 0),
109212c1933SFabiano Rosas        )
110212c1933SFabiano Rosas
11132a1bb21SHyman Huang    def _migrate(self, hardware, scenario, src,
11232a1bb21SHyman Huang                 dst, connect_uri, defer_migrate):
113212c1933SFabiano Rosas        src_qemu_time = []
114212c1933SFabiano Rosas        src_vcpu_time = []
115212c1933SFabiano Rosas        src_pid = src.get_pid()
116212c1933SFabiano Rosas
117212c1933SFabiano Rosas        vcpus = src.cmd("query-cpus-fast")
118212c1933SFabiano Rosas        src_threads = []
119212c1933SFabiano Rosas        for vcpu in vcpus:
120212c1933SFabiano Rosas            src_threads.append(vcpu["thread-id"])
121212c1933SFabiano Rosas
122212c1933SFabiano Rosas        # XXX how to get dst timings on remote host ?
123212c1933SFabiano Rosas
124212c1933SFabiano Rosas        if self._verbose:
125212c1933SFabiano Rosas            print("Sleeping %d seconds for initial guest workload run" % self._sleep)
126212c1933SFabiano Rosas        sleep_secs = self._sleep
127212c1933SFabiano Rosas        while sleep_secs > 1:
128212c1933SFabiano Rosas            src_qemu_time.append(self._cpu_timing(src_pid))
129212c1933SFabiano Rosas            src_vcpu_time.extend(self._vcpu_timing(src_pid, src_threads))
130212c1933SFabiano Rosas            time.sleep(1)
131212c1933SFabiano Rosas            sleep_secs -= 1
132212c1933SFabiano Rosas
133212c1933SFabiano Rosas        if self._verbose:
134212c1933SFabiano Rosas            print("Starting migration")
135212c1933SFabiano Rosas        if scenario._auto_converge:
136212c1933SFabiano Rosas            resp = src.cmd("migrate-set-capabilities",
137212c1933SFabiano Rosas                           capabilities = [
138212c1933SFabiano Rosas                               { "capability": "auto-converge",
139212c1933SFabiano Rosas                                 "state": True }
140212c1933SFabiano Rosas                           ])
141212c1933SFabiano Rosas            resp = src.cmd("migrate-set-parameters",
142212c1933SFabiano Rosas                           cpu_throttle_increment=scenario._auto_converge_step)
143212c1933SFabiano Rosas
144212c1933SFabiano Rosas        if scenario._post_copy:
145212c1933SFabiano Rosas            resp = src.cmd("migrate-set-capabilities",
146212c1933SFabiano Rosas                           capabilities = [
147212c1933SFabiano Rosas                               { "capability": "postcopy-ram",
148212c1933SFabiano Rosas                                 "state": True }
149212c1933SFabiano Rosas                           ])
150212c1933SFabiano Rosas            resp = dst.cmd("migrate-set-capabilities",
151212c1933SFabiano Rosas                           capabilities = [
152212c1933SFabiano Rosas                               { "capability": "postcopy-ram",
153212c1933SFabiano Rosas                                 "state": True }
154212c1933SFabiano Rosas                           ])
155212c1933SFabiano Rosas
156212c1933SFabiano Rosas        resp = src.cmd("migrate-set-parameters",
157212c1933SFabiano Rosas                       max_bandwidth=scenario._bandwidth * 1024 * 1024)
158212c1933SFabiano Rosas
159212c1933SFabiano Rosas        resp = src.cmd("migrate-set-parameters",
160212c1933SFabiano Rosas                       downtime_limit=scenario._downtime)
161212c1933SFabiano Rosas
162212c1933SFabiano Rosas        if scenario._compression_mt:
163212c1933SFabiano Rosas            resp = src.cmd("migrate-set-capabilities",
164212c1933SFabiano Rosas                           capabilities = [
165212c1933SFabiano Rosas                               { "capability": "compress",
166212c1933SFabiano Rosas                                 "state": True }
167212c1933SFabiano Rosas                           ])
168212c1933SFabiano Rosas            resp = src.cmd("migrate-set-parameters",
169212c1933SFabiano Rosas                           compress_threads=scenario._compression_mt_threads)
170212c1933SFabiano Rosas            resp = dst.cmd("migrate-set-capabilities",
171212c1933SFabiano Rosas                           capabilities = [
172212c1933SFabiano Rosas                               { "capability": "compress",
173212c1933SFabiano Rosas                                 "state": True }
174212c1933SFabiano Rosas                           ])
175212c1933SFabiano Rosas            resp = dst.cmd("migrate-set-parameters",
176212c1933SFabiano Rosas                           decompress_threads=scenario._compression_mt_threads)
177212c1933SFabiano Rosas
178212c1933SFabiano Rosas        if scenario._compression_xbzrle:
179212c1933SFabiano Rosas            resp = src.cmd("migrate-set-capabilities",
180212c1933SFabiano Rosas                           capabilities = [
181212c1933SFabiano Rosas                               { "capability": "xbzrle",
182212c1933SFabiano Rosas                                 "state": True }
183212c1933SFabiano Rosas                           ])
184212c1933SFabiano Rosas            resp = dst.cmd("migrate-set-capabilities",
185212c1933SFabiano Rosas                           capabilities = [
186212c1933SFabiano Rosas                               { "capability": "xbzrle",
187212c1933SFabiano Rosas                                 "state": True }
188212c1933SFabiano Rosas                           ])
189212c1933SFabiano Rosas            resp = src.cmd("migrate-set-parameters",
190212c1933SFabiano Rosas                           xbzrle_cache_size=(
191212c1933SFabiano Rosas                               hardware._mem *
192212c1933SFabiano Rosas                               1024 * 1024 * 1024 / 100 *
193212c1933SFabiano Rosas                               scenario._compression_xbzrle_cache))
194212c1933SFabiano Rosas
195212c1933SFabiano Rosas        if scenario._multifd:
196*45f34156SHyman Huang            if (scenario._multifd_compression and
197*45f34156SHyman Huang                (scenario._multifd_compression not in MULTIFD_CMP_ALGS)):
198*45f34156SHyman Huang                    raise Exception("unsupported multifd compression "
199*45f34156SHyman Huang                                    "algorithm: %s" %
200*45f34156SHyman Huang                                    scenario._multifd_compression)
201*45f34156SHyman Huang
202212c1933SFabiano Rosas            resp = src.cmd("migrate-set-capabilities",
203212c1933SFabiano Rosas                           capabilities = [
204212c1933SFabiano Rosas                               { "capability": "multifd",
205212c1933SFabiano Rosas                                 "state": True }
206212c1933SFabiano Rosas                           ])
207212c1933SFabiano Rosas            resp = src.cmd("migrate-set-parameters",
208212c1933SFabiano Rosas                           multifd_channels=scenario._multifd_channels)
209212c1933SFabiano Rosas            resp = dst.cmd("migrate-set-capabilities",
210212c1933SFabiano Rosas                           capabilities = [
211212c1933SFabiano Rosas                               { "capability": "multifd",
212212c1933SFabiano Rosas                                 "state": True }
213212c1933SFabiano Rosas                           ])
214212c1933SFabiano Rosas            resp = dst.cmd("migrate-set-parameters",
215212c1933SFabiano Rosas                           multifd_channels=scenario._multifd_channels)
216212c1933SFabiano Rosas
217*45f34156SHyman Huang            if scenario._multifd_compression:
218*45f34156SHyman Huang                resp = src.cmd("migrate-set-parameters",
219*45f34156SHyman Huang                    multifd_compression=scenario._multifd_compression)
220*45f34156SHyman Huang                resp = dst.cmd("migrate-set-parameters",
221*45f34156SHyman Huang                    multifd_compression=scenario._multifd_compression)
222*45f34156SHyman Huang
223212c1933SFabiano Rosas        if scenario._dirty_limit:
224212c1933SFabiano Rosas            if not hardware._dirty_ring_size:
225212c1933SFabiano Rosas                raise Exception("dirty ring size must be configured when "
226212c1933SFabiano Rosas                                "testing dirty limit migration")
227212c1933SFabiano Rosas
228212c1933SFabiano Rosas            resp = src.cmd("migrate-set-capabilities",
229212c1933SFabiano Rosas                           capabilities = [
230212c1933SFabiano Rosas                               { "capability": "dirty-limit",
231212c1933SFabiano Rosas                                 "state": True }
232212c1933SFabiano Rosas                           ])
233212c1933SFabiano Rosas            resp = src.cmd("migrate-set-parameters",
234212c1933SFabiano Rosas                x_vcpu_dirty_limit_period=scenario._x_vcpu_dirty_limit_period)
235212c1933SFabiano Rosas            resp = src.cmd("migrate-set-parameters",
236212c1933SFabiano Rosas                           vcpu_dirty_limit=scenario._vcpu_dirty_limit)
237212c1933SFabiano Rosas
23832a1bb21SHyman Huang        if defer_migrate:
23932a1bb21SHyman Huang            resp = dst.cmd("migrate-incoming", uri=connect_uri)
240212c1933SFabiano Rosas        resp = src.cmd("migrate", uri=connect_uri)
241212c1933SFabiano Rosas
242212c1933SFabiano Rosas        post_copy = False
243212c1933SFabiano Rosas        paused = False
244212c1933SFabiano Rosas
245212c1933SFabiano Rosas        progress_history = []
246212c1933SFabiano Rosas
247212c1933SFabiano Rosas        start = time.time()
248212c1933SFabiano Rosas        loop = 0
249212c1933SFabiano Rosas        while True:
250212c1933SFabiano Rosas            loop = loop + 1
251212c1933SFabiano Rosas            time.sleep(0.05)
252212c1933SFabiano Rosas
253212c1933SFabiano Rosas            progress = self._migrate_progress(src)
254212c1933SFabiano Rosas            if (loop % 20) == 0:
255212c1933SFabiano Rosas                src_qemu_time.append(self._cpu_timing(src_pid))
256212c1933SFabiano Rosas                src_vcpu_time.extend(self._vcpu_timing(src_pid, src_threads))
257212c1933SFabiano Rosas
258212c1933SFabiano Rosas            if (len(progress_history) == 0 or
259212c1933SFabiano Rosas                (progress_history[-1]._ram._iterations <
260212c1933SFabiano Rosas                 progress._ram._iterations)):
261212c1933SFabiano Rosas                progress_history.append(progress)
262212c1933SFabiano Rosas
263212c1933SFabiano Rosas            if progress._status in ("completed", "failed", "cancelled"):
264212c1933SFabiano Rosas                if progress._status == "completed" and paused:
265212c1933SFabiano Rosas                    dst.cmd("cont")
266212c1933SFabiano Rosas                if progress_history[-1] != progress:
267212c1933SFabiano Rosas                    progress_history.append(progress)
268212c1933SFabiano Rosas
269212c1933SFabiano Rosas                if progress._status == "completed":
270212c1933SFabiano Rosas                    if self._verbose:
271212c1933SFabiano Rosas                        print("Sleeping %d seconds for final guest workload run" % self._sleep)
272212c1933SFabiano Rosas                    sleep_secs = self._sleep
273212c1933SFabiano Rosas                    while sleep_secs > 1:
274212c1933SFabiano Rosas                        time.sleep(1)
275212c1933SFabiano Rosas                        src_qemu_time.append(self._cpu_timing(src_pid))
276212c1933SFabiano Rosas                        src_vcpu_time.extend(self._vcpu_timing(src_pid, src_threads))
277212c1933SFabiano Rosas                        sleep_secs -= 1
278212c1933SFabiano Rosas
279212c1933SFabiano Rosas                return [progress_history, src_qemu_time, src_vcpu_time]
280212c1933SFabiano Rosas
281212c1933SFabiano Rosas            if self._verbose and (loop % 20) == 0:
282212c1933SFabiano Rosas                print("Iter %d: remain %5dMB of %5dMB (total %5dMB @ %5dMb/sec)" % (
283212c1933SFabiano Rosas                    progress._ram._iterations,
284212c1933SFabiano Rosas                    progress._ram._remaining_bytes / (1024 * 1024),
285212c1933SFabiano Rosas                    progress._ram._total_bytes / (1024 * 1024),
286212c1933SFabiano Rosas                    progress._ram._transferred_bytes / (1024 * 1024),
287212c1933SFabiano Rosas                    progress._ram._transfer_rate_mbs,
288212c1933SFabiano Rosas                ))
289212c1933SFabiano Rosas
290212c1933SFabiano Rosas            if progress._ram._iterations > scenario._max_iters:
291212c1933SFabiano Rosas                if self._verbose:
292212c1933SFabiano Rosas                    print("No completion after %d iterations over RAM" % scenario._max_iters)
293212c1933SFabiano Rosas                src.cmd("migrate_cancel")
294212c1933SFabiano Rosas                continue
295212c1933SFabiano Rosas
296212c1933SFabiano Rosas            if time.time() > (start + scenario._max_time):
297212c1933SFabiano Rosas                if self._verbose:
298212c1933SFabiano Rosas                    print("No completion after %d seconds" % scenario._max_time)
299212c1933SFabiano Rosas                src.cmd("migrate_cancel")
300212c1933SFabiano Rosas                continue
301212c1933SFabiano Rosas
302212c1933SFabiano Rosas            if (scenario._post_copy and
303212c1933SFabiano Rosas                progress._ram._iterations >= scenario._post_copy_iters and
304212c1933SFabiano Rosas                not post_copy):
305212c1933SFabiano Rosas                if self._verbose:
306212c1933SFabiano Rosas                    print("Switching to post-copy after %d iterations" % scenario._post_copy_iters)
307212c1933SFabiano Rosas                resp = src.cmd("migrate-start-postcopy")
308212c1933SFabiano Rosas                post_copy = True
309212c1933SFabiano Rosas
310212c1933SFabiano Rosas            if (scenario._pause and
311212c1933SFabiano Rosas                progress._ram._iterations >= scenario._pause_iters and
312212c1933SFabiano Rosas                not paused):
313212c1933SFabiano Rosas                if self._verbose:
314212c1933SFabiano Rosas                    print("Pausing VM after %d iterations" % scenario._pause_iters)
315212c1933SFabiano Rosas                resp = src.cmd("stop")
316212c1933SFabiano Rosas                paused = True
317212c1933SFabiano Rosas
318212c1933SFabiano Rosas    def _is_ppc64le(self):
319212c1933SFabiano Rosas        _, _, _, _, machine = os.uname()
320212c1933SFabiano Rosas        if machine == "ppc64le":
321212c1933SFabiano Rosas            return True
322212c1933SFabiano Rosas        return False
323212c1933SFabiano Rosas
324212c1933SFabiano Rosas    def _get_guest_console_args(self):
325212c1933SFabiano Rosas        if self._is_ppc64le():
326212c1933SFabiano Rosas            return "console=hvc0"
327212c1933SFabiano Rosas        else:
328212c1933SFabiano Rosas            return "console=ttyS0"
329212c1933SFabiano Rosas
330212c1933SFabiano Rosas    def _get_qemu_serial_args(self):
331212c1933SFabiano Rosas        if self._is_ppc64le():
332212c1933SFabiano Rosas            return ["-chardev", "stdio,id=cdev0",
333212c1933SFabiano Rosas                    "-device", "spapr-vty,chardev=cdev0"]
334212c1933SFabiano Rosas        else:
335212c1933SFabiano Rosas            return ["-chardev", "stdio,id=cdev0",
336212c1933SFabiano Rosas                    "-device", "isa-serial,chardev=cdev0"]
337212c1933SFabiano Rosas
338212c1933SFabiano Rosas    def _get_common_args(self, hardware, tunnelled=False):
339212c1933SFabiano Rosas        args = [
340212c1933SFabiano Rosas            "noapic",
341212c1933SFabiano Rosas            "edd=off",
342212c1933SFabiano Rosas            "printk.time=1",
343212c1933SFabiano Rosas            "noreplace-smp",
344212c1933SFabiano Rosas            "cgroup_disable=memory",
345212c1933SFabiano Rosas            "pci=noearly",
346212c1933SFabiano Rosas        ]
347212c1933SFabiano Rosas
348212c1933SFabiano Rosas        args.append(self._get_guest_console_args())
349212c1933SFabiano Rosas
350212c1933SFabiano Rosas        if self._debug:
351212c1933SFabiano Rosas            args.append("debug")
352212c1933SFabiano Rosas        else:
353212c1933SFabiano Rosas            args.append("quiet")
354212c1933SFabiano Rosas
355212c1933SFabiano Rosas        args.append("ramsize=%s" % hardware._mem)
356212c1933SFabiano Rosas
357212c1933SFabiano Rosas        cmdline = " ".join(args)
358212c1933SFabiano Rosas        if tunnelled:
359212c1933SFabiano Rosas            cmdline = "'" + cmdline + "'"
360212c1933SFabiano Rosas
361212c1933SFabiano Rosas        argv = [
362212c1933SFabiano Rosas            "-cpu", "host",
363212c1933SFabiano Rosas            "-kernel", self._kernel,
364212c1933SFabiano Rosas            "-initrd", self._initrd,
365212c1933SFabiano Rosas            "-append", cmdline,
366212c1933SFabiano Rosas            "-m", str((hardware._mem * 1024) + 512),
367212c1933SFabiano Rosas            "-smp", str(hardware._cpus),
368212c1933SFabiano Rosas        ]
369212c1933SFabiano Rosas        if hardware._dirty_ring_size:
370212c1933SFabiano Rosas            argv.extend(["-accel", "kvm,dirty-ring-size=%s" %
371212c1933SFabiano Rosas                         hardware._dirty_ring_size])
372212c1933SFabiano Rosas        else:
373212c1933SFabiano Rosas            argv.extend(["-accel", "kvm"])
374212c1933SFabiano Rosas
375212c1933SFabiano Rosas        argv.extend(self._get_qemu_serial_args())
376212c1933SFabiano Rosas
377212c1933SFabiano Rosas        if self._debug:
378212c1933SFabiano Rosas            argv.extend(["-machine", "graphics=off"])
379212c1933SFabiano Rosas
380212c1933SFabiano Rosas        if hardware._prealloc_pages:
381212c1933SFabiano Rosas            argv_source += ["-mem-path", "/dev/shm",
382212c1933SFabiano Rosas                            "-mem-prealloc"]
383212c1933SFabiano Rosas        if hardware._locked_pages:
384212c1933SFabiano Rosas            argv_source += ["-overcommit", "mem-lock=on"]
385212c1933SFabiano Rosas        if hardware._huge_pages:
386212c1933SFabiano Rosas            pass
387212c1933SFabiano Rosas
388212c1933SFabiano Rosas        return argv
389212c1933SFabiano Rosas
390212c1933SFabiano Rosas    def _get_src_args(self, hardware):
391212c1933SFabiano Rosas        return self._get_common_args(hardware)
392212c1933SFabiano Rosas
39332a1bb21SHyman Huang    def _get_dst_args(self, hardware, uri, defer_migrate):
394212c1933SFabiano Rosas        tunnelled = False
395212c1933SFabiano Rosas        if self._dst_host != "localhost":
396212c1933SFabiano Rosas            tunnelled = True
397212c1933SFabiano Rosas        argv = self._get_common_args(hardware, tunnelled)
39832a1bb21SHyman Huang
39932a1bb21SHyman Huang        if defer_migrate:
40032a1bb21SHyman Huang            return argv + ["-incoming", "defer"]
401212c1933SFabiano Rosas        return argv + ["-incoming", uri]
402212c1933SFabiano Rosas
403212c1933SFabiano Rosas    @staticmethod
404212c1933SFabiano Rosas    def _get_common_wrapper(cpu_bind, mem_bind):
405212c1933SFabiano Rosas        wrapper = []
406212c1933SFabiano Rosas        if len(cpu_bind) > 0 or len(mem_bind) > 0:
407212c1933SFabiano Rosas            wrapper.append("numactl")
408212c1933SFabiano Rosas            if cpu_bind:
409212c1933SFabiano Rosas                wrapper.append("--physcpubind=%s" % ",".join(cpu_bind))
410212c1933SFabiano Rosas            if mem_bind:
411212c1933SFabiano Rosas                wrapper.append("--membind=%s" % ",".join(mem_bind))
412212c1933SFabiano Rosas
413212c1933SFabiano Rosas        return wrapper
414212c1933SFabiano Rosas
415212c1933SFabiano Rosas    def _get_src_wrapper(self, hardware):
416212c1933SFabiano Rosas        return self._get_common_wrapper(hardware._src_cpu_bind, hardware._src_mem_bind)
417212c1933SFabiano Rosas
418212c1933SFabiano Rosas    def _get_dst_wrapper(self, hardware):
419212c1933SFabiano Rosas        wrapper = self._get_common_wrapper(hardware._dst_cpu_bind, hardware._dst_mem_bind)
420212c1933SFabiano Rosas        if self._dst_host != "localhost":
421212c1933SFabiano Rosas            return ["ssh",
422212c1933SFabiano Rosas                    "-R", "9001:localhost:9001",
423212c1933SFabiano Rosas                    self._dst_host] + wrapper
424212c1933SFabiano Rosas        else:
425212c1933SFabiano Rosas            return wrapper
426212c1933SFabiano Rosas
427212c1933SFabiano Rosas    def _get_timings(self, vm):
428212c1933SFabiano Rosas        log = vm.get_log()
429212c1933SFabiano Rosas        if not log:
430212c1933SFabiano Rosas            return []
431212c1933SFabiano Rosas        if self._debug:
432212c1933SFabiano Rosas            print(log)
433212c1933SFabiano Rosas
434212c1933SFabiano Rosas        regex = r"[^\s]+\s\((\d+)\):\sINFO:\s(\d+)ms\scopied\s\d+\sGB\sin\s(\d+)ms"
435212c1933SFabiano Rosas        matcher = re.compile(regex)
436212c1933SFabiano Rosas        records = []
437212c1933SFabiano Rosas        for line in log.split("\n"):
438212c1933SFabiano Rosas            match = matcher.match(line)
439212c1933SFabiano Rosas            if match:
440212c1933SFabiano Rosas                records.append(TimingRecord(int(match.group(1)),
441212c1933SFabiano Rosas                                            int(match.group(2)) / 1000.0,
442212c1933SFabiano Rosas                                            int(match.group(3))))
443212c1933SFabiano Rosas        return records
444212c1933SFabiano Rosas
445212c1933SFabiano Rosas    def run(self, hardware, scenario, result_dir=os.getcwd()):
446212c1933SFabiano Rosas        abs_result_dir = os.path.join(result_dir, scenario._name)
44732a1bb21SHyman Huang        defer_migrate = False
448212c1933SFabiano Rosas
449212c1933SFabiano Rosas        if self._transport == "tcp":
450212c1933SFabiano Rosas            uri = "tcp:%s:9000" % self._dst_host
451212c1933SFabiano Rosas        elif self._transport == "rdma":
452212c1933SFabiano Rosas            uri = "rdma:%s:9000" % self._dst_host
453212c1933SFabiano Rosas        elif self._transport == "unix":
454212c1933SFabiano Rosas            if self._dst_host != "localhost":
455212c1933SFabiano Rosas                raise Exception("Running use unix migration transport for non-local host")
456212c1933SFabiano Rosas            uri = "unix:/var/tmp/qemu-migrate-%d.migrate" % os.getpid()
457212c1933SFabiano Rosas            try:
458212c1933SFabiano Rosas                os.remove(uri[5:])
459212c1933SFabiano Rosas                os.remove(monaddr)
460212c1933SFabiano Rosas            except:
461212c1933SFabiano Rosas                pass
462212c1933SFabiano Rosas
46332a1bb21SHyman Huang        if scenario._multifd:
46432a1bb21SHyman Huang            defer_migrate = True
46532a1bb21SHyman Huang
466212c1933SFabiano Rosas        if self._dst_host != "localhost":
467212c1933SFabiano Rosas            dstmonaddr = ("localhost", 9001)
468212c1933SFabiano Rosas        else:
469212c1933SFabiano Rosas            dstmonaddr = "/var/tmp/qemu-dst-%d-monitor.sock" % os.getpid()
470212c1933SFabiano Rosas        srcmonaddr = "/var/tmp/qemu-src-%d-monitor.sock" % os.getpid()
471212c1933SFabiano Rosas
472212c1933SFabiano Rosas        src = QEMUMachine(self._binary,
473212c1933SFabiano Rosas                          args=self._get_src_args(hardware),
474212c1933SFabiano Rosas                          wrapper=self._get_src_wrapper(hardware),
475212c1933SFabiano Rosas                          name="qemu-src-%d" % os.getpid(),
476212c1933SFabiano Rosas                          monitor_address=srcmonaddr)
477212c1933SFabiano Rosas
478212c1933SFabiano Rosas        dst = QEMUMachine(self._binary,
47932a1bb21SHyman Huang                          args=self._get_dst_args(hardware, uri, defer_migrate),
480212c1933SFabiano Rosas                          wrapper=self._get_dst_wrapper(hardware),
481212c1933SFabiano Rosas                          name="qemu-dst-%d" % os.getpid(),
482212c1933SFabiano Rosas                          monitor_address=dstmonaddr)
483212c1933SFabiano Rosas
484212c1933SFabiano Rosas        try:
485212c1933SFabiano Rosas            src.launch()
486212c1933SFabiano Rosas            dst.launch()
487212c1933SFabiano Rosas
48832a1bb21SHyman Huang            ret = self._migrate(hardware, scenario, src,
48932a1bb21SHyman Huang                                dst, uri, defer_migrate)
490212c1933SFabiano Rosas            progress_history = ret[0]
491212c1933SFabiano Rosas            qemu_timings = ret[1]
492212c1933SFabiano Rosas            vcpu_timings = ret[2]
493212c1933SFabiano Rosas            if uri[0:5] == "unix:" and os.path.exists(uri[5:]):
494212c1933SFabiano Rosas                os.remove(uri[5:])
495212c1933SFabiano Rosas
496212c1933SFabiano Rosas            if os.path.exists(srcmonaddr):
497212c1933SFabiano Rosas                os.remove(srcmonaddr)
498212c1933SFabiano Rosas
499212c1933SFabiano Rosas            if self._dst_host == "localhost" and os.path.exists(dstmonaddr):
500212c1933SFabiano Rosas                os.remove(dstmonaddr)
501212c1933SFabiano Rosas
502212c1933SFabiano Rosas            if self._verbose:
503212c1933SFabiano Rosas                print("Finished migration")
504212c1933SFabiano Rosas
505212c1933SFabiano Rosas            src.shutdown()
506212c1933SFabiano Rosas            dst.shutdown()
507212c1933SFabiano Rosas
508212c1933SFabiano Rosas            return Report(hardware, scenario, progress_history,
509212c1933SFabiano Rosas                          Timings(self._get_timings(src) + self._get_timings(dst)),
510212c1933SFabiano Rosas                          Timings(qemu_timings),
511212c1933SFabiano Rosas                          Timings(vcpu_timings),
512212c1933SFabiano Rosas                          self._binary, self._dst_host, self._kernel,
513212c1933SFabiano Rosas                          self._initrd, self._transport, self._sleep)
514212c1933SFabiano Rosas        except Exception as e:
515212c1933SFabiano Rosas            if self._debug:
516212c1933SFabiano Rosas                print("Failed: %s" % str(e))
517212c1933SFabiano Rosas            try:
518212c1933SFabiano Rosas                src.shutdown()
519212c1933SFabiano Rosas            except:
520212c1933SFabiano Rosas                pass
521212c1933SFabiano Rosas            try:
522212c1933SFabiano Rosas                dst.shutdown()
523212c1933SFabiano Rosas            except:
524212c1933SFabiano Rosas                pass
525212c1933SFabiano Rosas
526212c1933SFabiano Rosas            if self._debug:
527212c1933SFabiano Rosas                print(src.get_log())
528212c1933SFabiano Rosas                print(dst.get_log())
529212c1933SFabiano Rosas            raise
530212c1933SFabiano Rosas
531