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