xref: /openbmc/qemu/tests/migration-stress/guestperf/engine.py (revision 9af3d9a931156142199c61518937506bfa5475f1)
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
27*5984870eSHyman Huangfrom guestperf.report import Report, ReportResult
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
3445f34156SHyman Huang# multifd supported compression algorithms
3545f34156SHyman 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:
19645f34156SHyman Huang            if (scenario._multifd_compression and
19745f34156SHyman Huang                (scenario._multifd_compression not in MULTIFD_CMP_ALGS)):
19845f34156SHyman Huang                    raise Exception("unsupported multifd compression "
19945f34156SHyman Huang                                    "algorithm: %s" %
20045f34156SHyman Huang                                    scenario._multifd_compression)
20145f34156SHyman 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
21745f34156SHyman Huang            if scenario._multifd_compression:
21845f34156SHyman Huang                resp = src.cmd("migrate-set-parameters",
21945f34156SHyman Huang                    multifd_compression=scenario._multifd_compression)
22045f34156SHyman Huang                resp = dst.cmd("migrate-set-parameters",
22145f34156SHyman Huang                    multifd_compression=scenario._multifd_compression)
22245f34156SHyman 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
279*5984870eSHyman Huang                result = ReportResult()
280*5984870eSHyman Huang                if progress._status == "completed" and not paused:
281*5984870eSHyman Huang                    result = ReportResult(True)
282*5984870eSHyman Huang
283*5984870eSHyman Huang                return [progress_history, src_qemu_time, src_vcpu_time, result]
284212c1933SFabiano Rosas
285212c1933SFabiano Rosas            if self._verbose and (loop % 20) == 0:
286212c1933SFabiano Rosas                print("Iter %d: remain %5dMB of %5dMB (total %5dMB @ %5dMb/sec)" % (
287212c1933SFabiano Rosas                    progress._ram._iterations,
288212c1933SFabiano Rosas                    progress._ram._remaining_bytes / (1024 * 1024),
289212c1933SFabiano Rosas                    progress._ram._total_bytes / (1024 * 1024),
290212c1933SFabiano Rosas                    progress._ram._transferred_bytes / (1024 * 1024),
291212c1933SFabiano Rosas                    progress._ram._transfer_rate_mbs,
292212c1933SFabiano Rosas                ))
293212c1933SFabiano Rosas
294212c1933SFabiano Rosas            if progress._ram._iterations > scenario._max_iters:
295212c1933SFabiano Rosas                if self._verbose:
296212c1933SFabiano Rosas                    print("No completion after %d iterations over RAM" % scenario._max_iters)
297212c1933SFabiano Rosas                src.cmd("migrate_cancel")
298212c1933SFabiano Rosas                continue
299212c1933SFabiano Rosas
300212c1933SFabiano Rosas            if time.time() > (start + scenario._max_time):
301212c1933SFabiano Rosas                if self._verbose:
302212c1933SFabiano Rosas                    print("No completion after %d seconds" % scenario._max_time)
303212c1933SFabiano Rosas                src.cmd("migrate_cancel")
304212c1933SFabiano Rosas                continue
305212c1933SFabiano Rosas
306212c1933SFabiano Rosas            if (scenario._post_copy and
307212c1933SFabiano Rosas                progress._ram._iterations >= scenario._post_copy_iters and
308212c1933SFabiano Rosas                not post_copy):
309212c1933SFabiano Rosas                if self._verbose:
310212c1933SFabiano Rosas                    print("Switching to post-copy after %d iterations" % scenario._post_copy_iters)
311212c1933SFabiano Rosas                resp = src.cmd("migrate-start-postcopy")
312212c1933SFabiano Rosas                post_copy = True
313212c1933SFabiano Rosas
314212c1933SFabiano Rosas            if (scenario._pause and
315212c1933SFabiano Rosas                progress._ram._iterations >= scenario._pause_iters and
316212c1933SFabiano Rosas                not paused):
317212c1933SFabiano Rosas                if self._verbose:
318212c1933SFabiano Rosas                    print("Pausing VM after %d iterations" % scenario._pause_iters)
319212c1933SFabiano Rosas                resp = src.cmd("stop")
320212c1933SFabiano Rosas                paused = True
321212c1933SFabiano Rosas
322212c1933SFabiano Rosas    def _is_ppc64le(self):
323212c1933SFabiano Rosas        _, _, _, _, machine = os.uname()
324212c1933SFabiano Rosas        if machine == "ppc64le":
325212c1933SFabiano Rosas            return True
326212c1933SFabiano Rosas        return False
327212c1933SFabiano Rosas
328212c1933SFabiano Rosas    def _get_guest_console_args(self):
329212c1933SFabiano Rosas        if self._is_ppc64le():
330212c1933SFabiano Rosas            return "console=hvc0"
331212c1933SFabiano Rosas        else:
332212c1933SFabiano Rosas            return "console=ttyS0"
333212c1933SFabiano Rosas
334212c1933SFabiano Rosas    def _get_qemu_serial_args(self):
335212c1933SFabiano Rosas        if self._is_ppc64le():
336212c1933SFabiano Rosas            return ["-chardev", "stdio,id=cdev0",
337212c1933SFabiano Rosas                    "-device", "spapr-vty,chardev=cdev0"]
338212c1933SFabiano Rosas        else:
339212c1933SFabiano Rosas            return ["-chardev", "stdio,id=cdev0",
340212c1933SFabiano Rosas                    "-device", "isa-serial,chardev=cdev0"]
341212c1933SFabiano Rosas
342212c1933SFabiano Rosas    def _get_common_args(self, hardware, tunnelled=False):
343212c1933SFabiano Rosas        args = [
344212c1933SFabiano Rosas            "noapic",
345212c1933SFabiano Rosas            "edd=off",
346212c1933SFabiano Rosas            "printk.time=1",
347212c1933SFabiano Rosas            "noreplace-smp",
348212c1933SFabiano Rosas            "cgroup_disable=memory",
349212c1933SFabiano Rosas            "pci=noearly",
350212c1933SFabiano Rosas        ]
351212c1933SFabiano Rosas
352212c1933SFabiano Rosas        args.append(self._get_guest_console_args())
353212c1933SFabiano Rosas
354212c1933SFabiano Rosas        if self._debug:
355212c1933SFabiano Rosas            args.append("debug")
356212c1933SFabiano Rosas        else:
357212c1933SFabiano Rosas            args.append("quiet")
358212c1933SFabiano Rosas
359212c1933SFabiano Rosas        args.append("ramsize=%s" % hardware._mem)
360212c1933SFabiano Rosas
361212c1933SFabiano Rosas        cmdline = " ".join(args)
362212c1933SFabiano Rosas        if tunnelled:
363212c1933SFabiano Rosas            cmdline = "'" + cmdline + "'"
364212c1933SFabiano Rosas
365212c1933SFabiano Rosas        argv = [
366212c1933SFabiano Rosas            "-cpu", "host",
367212c1933SFabiano Rosas            "-kernel", self._kernel,
368212c1933SFabiano Rosas            "-initrd", self._initrd,
369212c1933SFabiano Rosas            "-append", cmdline,
370212c1933SFabiano Rosas            "-m", str((hardware._mem * 1024) + 512),
371212c1933SFabiano Rosas            "-smp", str(hardware._cpus),
372212c1933SFabiano Rosas        ]
373212c1933SFabiano Rosas        if hardware._dirty_ring_size:
374212c1933SFabiano Rosas            argv.extend(["-accel", "kvm,dirty-ring-size=%s" %
375212c1933SFabiano Rosas                         hardware._dirty_ring_size])
376212c1933SFabiano Rosas        else:
377212c1933SFabiano Rosas            argv.extend(["-accel", "kvm"])
378212c1933SFabiano Rosas
379212c1933SFabiano Rosas        argv.extend(self._get_qemu_serial_args())
380212c1933SFabiano Rosas
381212c1933SFabiano Rosas        if self._debug:
382212c1933SFabiano Rosas            argv.extend(["-machine", "graphics=off"])
383212c1933SFabiano Rosas
384212c1933SFabiano Rosas        if hardware._prealloc_pages:
385212c1933SFabiano Rosas            argv_source += ["-mem-path", "/dev/shm",
386212c1933SFabiano Rosas                            "-mem-prealloc"]
387212c1933SFabiano Rosas        if hardware._locked_pages:
388212c1933SFabiano Rosas            argv_source += ["-overcommit", "mem-lock=on"]
389212c1933SFabiano Rosas        if hardware._huge_pages:
390212c1933SFabiano Rosas            pass
391212c1933SFabiano Rosas
392212c1933SFabiano Rosas        return argv
393212c1933SFabiano Rosas
394212c1933SFabiano Rosas    def _get_src_args(self, hardware):
395212c1933SFabiano Rosas        return self._get_common_args(hardware)
396212c1933SFabiano Rosas
39732a1bb21SHyman Huang    def _get_dst_args(self, hardware, uri, defer_migrate):
398212c1933SFabiano Rosas        tunnelled = False
399212c1933SFabiano Rosas        if self._dst_host != "localhost":
400212c1933SFabiano Rosas            tunnelled = True
401212c1933SFabiano Rosas        argv = self._get_common_args(hardware, tunnelled)
40232a1bb21SHyman Huang
40332a1bb21SHyman Huang        if defer_migrate:
40432a1bb21SHyman Huang            return argv + ["-incoming", "defer"]
405212c1933SFabiano Rosas        return argv + ["-incoming", uri]
406212c1933SFabiano Rosas
407212c1933SFabiano Rosas    @staticmethod
408212c1933SFabiano Rosas    def _get_common_wrapper(cpu_bind, mem_bind):
409212c1933SFabiano Rosas        wrapper = []
410212c1933SFabiano Rosas        if len(cpu_bind) > 0 or len(mem_bind) > 0:
411212c1933SFabiano Rosas            wrapper.append("numactl")
412212c1933SFabiano Rosas            if cpu_bind:
413212c1933SFabiano Rosas                wrapper.append("--physcpubind=%s" % ",".join(cpu_bind))
414212c1933SFabiano Rosas            if mem_bind:
415212c1933SFabiano Rosas                wrapper.append("--membind=%s" % ",".join(mem_bind))
416212c1933SFabiano Rosas
417212c1933SFabiano Rosas        return wrapper
418212c1933SFabiano Rosas
419212c1933SFabiano Rosas    def _get_src_wrapper(self, hardware):
420212c1933SFabiano Rosas        return self._get_common_wrapper(hardware._src_cpu_bind, hardware._src_mem_bind)
421212c1933SFabiano Rosas
422212c1933SFabiano Rosas    def _get_dst_wrapper(self, hardware):
423212c1933SFabiano Rosas        wrapper = self._get_common_wrapper(hardware._dst_cpu_bind, hardware._dst_mem_bind)
424212c1933SFabiano Rosas        if self._dst_host != "localhost":
425212c1933SFabiano Rosas            return ["ssh",
426212c1933SFabiano Rosas                    "-R", "9001:localhost:9001",
427212c1933SFabiano Rosas                    self._dst_host] + wrapper
428212c1933SFabiano Rosas        else:
429212c1933SFabiano Rosas            return wrapper
430212c1933SFabiano Rosas
431212c1933SFabiano Rosas    def _get_timings(self, vm):
432212c1933SFabiano Rosas        log = vm.get_log()
433212c1933SFabiano Rosas        if not log:
434212c1933SFabiano Rosas            return []
435212c1933SFabiano Rosas        if self._debug:
436212c1933SFabiano Rosas            print(log)
437212c1933SFabiano Rosas
438212c1933SFabiano Rosas        regex = r"[^\s]+\s\((\d+)\):\sINFO:\s(\d+)ms\scopied\s\d+\sGB\sin\s(\d+)ms"
439212c1933SFabiano Rosas        matcher = re.compile(regex)
440212c1933SFabiano Rosas        records = []
441212c1933SFabiano Rosas        for line in log.split("\n"):
442212c1933SFabiano Rosas            match = matcher.match(line)
443212c1933SFabiano Rosas            if match:
444212c1933SFabiano Rosas                records.append(TimingRecord(int(match.group(1)),
445212c1933SFabiano Rosas                                            int(match.group(2)) / 1000.0,
446212c1933SFabiano Rosas                                            int(match.group(3))))
447212c1933SFabiano Rosas        return records
448212c1933SFabiano Rosas
449212c1933SFabiano Rosas    def run(self, hardware, scenario, result_dir=os.getcwd()):
450212c1933SFabiano Rosas        abs_result_dir = os.path.join(result_dir, scenario._name)
45132a1bb21SHyman Huang        defer_migrate = False
452212c1933SFabiano Rosas
453212c1933SFabiano Rosas        if self._transport == "tcp":
454212c1933SFabiano Rosas            uri = "tcp:%s:9000" % self._dst_host
455212c1933SFabiano Rosas        elif self._transport == "rdma":
456212c1933SFabiano Rosas            uri = "rdma:%s:9000" % self._dst_host
457212c1933SFabiano Rosas        elif self._transport == "unix":
458212c1933SFabiano Rosas            if self._dst_host != "localhost":
459212c1933SFabiano Rosas                raise Exception("Running use unix migration transport for non-local host")
460212c1933SFabiano Rosas            uri = "unix:/var/tmp/qemu-migrate-%d.migrate" % os.getpid()
461212c1933SFabiano Rosas            try:
462212c1933SFabiano Rosas                os.remove(uri[5:])
463212c1933SFabiano Rosas                os.remove(monaddr)
464212c1933SFabiano Rosas            except:
465212c1933SFabiano Rosas                pass
466212c1933SFabiano Rosas
46732a1bb21SHyman Huang        if scenario._multifd:
46832a1bb21SHyman Huang            defer_migrate = True
46932a1bb21SHyman Huang
470212c1933SFabiano Rosas        if self._dst_host != "localhost":
471212c1933SFabiano Rosas            dstmonaddr = ("localhost", 9001)
472212c1933SFabiano Rosas        else:
473212c1933SFabiano Rosas            dstmonaddr = "/var/tmp/qemu-dst-%d-monitor.sock" % os.getpid()
474212c1933SFabiano Rosas        srcmonaddr = "/var/tmp/qemu-src-%d-monitor.sock" % os.getpid()
475212c1933SFabiano Rosas
476212c1933SFabiano Rosas        src = QEMUMachine(self._binary,
477212c1933SFabiano Rosas                          args=self._get_src_args(hardware),
478212c1933SFabiano Rosas                          wrapper=self._get_src_wrapper(hardware),
479212c1933SFabiano Rosas                          name="qemu-src-%d" % os.getpid(),
480212c1933SFabiano Rosas                          monitor_address=srcmonaddr)
481212c1933SFabiano Rosas
482212c1933SFabiano Rosas        dst = QEMUMachine(self._binary,
48332a1bb21SHyman Huang                          args=self._get_dst_args(hardware, uri, defer_migrate),
484212c1933SFabiano Rosas                          wrapper=self._get_dst_wrapper(hardware),
485212c1933SFabiano Rosas                          name="qemu-dst-%d" % os.getpid(),
486212c1933SFabiano Rosas                          monitor_address=dstmonaddr)
487212c1933SFabiano Rosas
488212c1933SFabiano Rosas        try:
489212c1933SFabiano Rosas            src.launch()
490212c1933SFabiano Rosas            dst.launch()
491212c1933SFabiano Rosas
49232a1bb21SHyman Huang            ret = self._migrate(hardware, scenario, src,
49332a1bb21SHyman Huang                                dst, uri, defer_migrate)
494212c1933SFabiano Rosas            progress_history = ret[0]
495212c1933SFabiano Rosas            qemu_timings = ret[1]
496212c1933SFabiano Rosas            vcpu_timings = ret[2]
497*5984870eSHyman Huang            result = ret[3]
498212c1933SFabiano Rosas            if uri[0:5] == "unix:" and os.path.exists(uri[5:]):
499212c1933SFabiano Rosas                os.remove(uri[5:])
500212c1933SFabiano Rosas
501212c1933SFabiano Rosas            if os.path.exists(srcmonaddr):
502212c1933SFabiano Rosas                os.remove(srcmonaddr)
503212c1933SFabiano Rosas
504212c1933SFabiano Rosas            if self._dst_host == "localhost" and os.path.exists(dstmonaddr):
505212c1933SFabiano Rosas                os.remove(dstmonaddr)
506212c1933SFabiano Rosas
507212c1933SFabiano Rosas            if self._verbose:
508212c1933SFabiano Rosas                print("Finished migration")
509212c1933SFabiano Rosas
510212c1933SFabiano Rosas            src.shutdown()
511212c1933SFabiano Rosas            dst.shutdown()
512212c1933SFabiano Rosas
513212c1933SFabiano Rosas            return Report(hardware, scenario, progress_history,
514212c1933SFabiano Rosas                          Timings(self._get_timings(src) + self._get_timings(dst)),
515212c1933SFabiano Rosas                          Timings(qemu_timings),
516212c1933SFabiano Rosas                          Timings(vcpu_timings),
517*5984870eSHyman Huang                          result,
518212c1933SFabiano Rosas                          self._binary, self._dst_host, self._kernel,
519212c1933SFabiano Rosas                          self._initrd, self._transport, self._sleep)
520212c1933SFabiano Rosas        except Exception as e:
521212c1933SFabiano Rosas            if self._debug:
522212c1933SFabiano Rosas                print("Failed: %s" % str(e))
523212c1933SFabiano Rosas            try:
524212c1933SFabiano Rosas                src.shutdown()
525212c1933SFabiano Rosas            except:
526212c1933SFabiano Rosas                pass
527212c1933SFabiano Rosas            try:
528212c1933SFabiano Rosas                dst.shutdown()
529212c1933SFabiano Rosas            except:
530212c1933SFabiano Rosas                pass
531212c1933SFabiano Rosas
532212c1933SFabiano Rosas            if self._debug:
533212c1933SFabiano Rosas                print(src.get_log())
534212c1933SFabiano Rosas                print(dst.get_log())
535212c1933SFabiano Rosas            raise
536212c1933SFabiano Rosas
537