Exemple #1
0
def run(test, params, env):
    """
    Test hotplug/hotunplug of vcpu device.

    1) Boot up guest w/o vcpu device.
    2) Hot plug/unplug vcpu devices and check successfully or not. (qemu side)
    3) Check if the number of CPUs in guest changes accordingly. (guest side)
    4) Do sub test after hot plug/unplug.
    5) Recheck the number of CPUs in guest.
    6) Check the CPU topology of guest. (if all vcpu plugged)

    :param test:   QEMU test object.
    :param params: Dictionary with the test parameters.
    :param env:    Dictionary with test environment.
    """
    def check_guest_cpu_count():
        if not utils_misc.wait_for(
                lambda: cpu_utils.check_if_vm_vcpus_match_qemu(vm),
                verify_wait_timeout,
                first=sleep_after_change):
            test.fail("Actual number of guest CPUs is not equal to expected")

    def sub_hotunplug():
        error_context.context(
            "Hotunplug vcpu devices after vcpu %s" % hotpluggable_test,
            logging.info)
        for plugged_dev in pluggable_vcpu_dev[::-1]:
            try:
                vm.hotunplug_vcpu_device(plugged_dev)
            except VMDeviceCheckError:
                if not vm.is_paused():
                    raise
                logging.warning(
                    "%s can not be unplugged directly because "
                    "guest is paused, will check again after "
                    "resume", plugged_dev)
                vm.params["vcpu_enable_%s" % plugged_dev] = "no"

    def sub_reboot():
        error_context.context("Reboot guest after vcpu %s" % hotpluggable_test,
                              logging.info)
        vm.reboot(session=session,
                  method=params["reboot_method"],
                  timeout=login_timeout)

    def sub_shutdown():
        error_context.context(
            "Shutdown guest after vcpu %s" % hotpluggable_test, logging.info)
        shutdown_method = params["shutdown_method"]
        if shutdown_method == "shell":
            session.sendline(params["shutdown_command"])
            error_context.context("waiting VM to go down (guest shell cmd)",
                                  logging.info)
        elif shutdown_method == "system_powerdown":
            vm.monitor.system_powerdown()
            error_context.context("waiting VM to go down (qemu monitor cmd)",
                                  logging.info)
        if not vm.wait_for_shutdown(360):
            test.fail("Guest refuses to go down after vcpu %s" %
                      hotpluggable_test)

    def sub_migrate():
        sub_migrate_reboot = sub_reboot
        sub_migrate_hotunplug = sub_hotunplug
        error_context.context(
            "Migrate guest after vcpu %s" % hotpluggable_test, logging.info)
        vm.migrate()
        vm.verify_alive()
        sub_test_after_migrate = params.objects("sub_test_after_migrate")
        while sub_test_after_migrate:
            check_guest_cpu_count()
            sub_test = sub_test_after_migrate.pop(0)
            error_context.context("%s after migration completed" % sub_test)
            eval("sub_migrate_%s" % sub_test)()

    def sub_online_offline():
        error_context.context(
            "Offline then online guest CPUs after vcpu %s" % hotpluggable_test,
            logging.info)
        cpu_ids = list(current_guest_cpu_ids - guest_cpu_ids)
        cpu_ids.sort()
        cmd = "echo %d > /sys/devices/system/cpu/cpu%d/online"
        try:
            for cpu_id in cpu_ids[::-1]:
                session.cmd(cmd % (0, cpu_id))
            if not cpu_utils.check_if_vm_vcpu_match(cpu_count_before_test, vm):
                test.fail(
                    "Actual number of guest CPUs is not equal to expected")
            for cpu_id in cpu_ids:
                session.cmd(cmd % (1, cpu_id))
        except ShellCmdError as err:
            logging.error(str(err))
            test.error("Failed to change the CPU state on guest.")

    def sub_pause_resume():
        error_context.context("Pause guest to hotunplug all vcpu devices",
                              logging.info)
        vm.pause()
        sub_hotunplug()
        error_context.context("Resume guest after hotunplug")
        vm.resume()

    login_timeout = params.get_numeric("login_timeout", 360)
    sleep_after_change = params.get_numeric("sleep_after_cpu_change", 30)
    os_type = params["os_type"]
    hotpluggable_test = params["hotpluggable_test"]
    verify_wait_timeout = params.get_numeric("verify_wait_timeout", 60)
    sub_test_type = params.get("sub_test_type")
    check_cpu_topology = params.get_boolean("check_cpu_topology", True)

    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()
    session = vm.wait_for_login(timeout=login_timeout)
    cpu_count_before_test = vm.get_cpu_count()
    maxcpus = vm.cpuinfo.maxcpus
    vcpu_devices = params.objects("vcpu_devices")
    guest_cpu_ids = cpu_utils.get_guest_cpu_ids(session, os_type)

    error_context.context("Check the number of guest CPUs after startup",
                          logging.info)
    if not cpu_utils.check_if_vm_vcpus_match_qemu(vm):
        test.error("The number of guest CPUs is not equal to the qemu command "
                   "line configuration")

    if hotpluggable_test == "hotplug":
        pluggable_vcpu_dev = vcpu_devices
    else:
        pluggable_vcpu_dev = vcpu_devices[::-1]

    if params.get_boolean("workaround_need"):
        win_wora.modify_driver(params, session)

    if params.get("pause_vm_before_hotplug", "no") == "yes":
        error_context.context("Pause guest before %s" % hotpluggable_test,
                              logging.info)
        vm.pause()

    error_context.context("%s all vcpu devices" % hotpluggable_test,
                          logging.info)
    for vcpu_dev in pluggable_vcpu_dev:
        getattr(vm, "%s_vcpu_device" % hotpluggable_test)(vcpu_dev)
    if vm.is_paused():
        error_context.context("Resume guest after %s" % hotpluggable_test,
                              logging.info)
        vm.resume()

    check_guest_cpu_count()
    current_guest_cpu_ids = cpu_utils.get_guest_cpu_ids(session, os_type)

    if sub_test_type:
        eval("sub_%s" % sub_test_type)()
        # Close old session since guest maybe dead/reboot
        if session:
            session.close()

    if vm.is_alive():
        session = vm.wait_for_login(timeout=login_timeout)
        check_guest_cpu_count()
        if vm.get_cpu_count() == maxcpus and check_cpu_topology:
            if not cpu_utils.check_guest_cpu_topology(session, os_type,
                                                      vm.cpuinfo):
                session.close()
                test.fail("CPU topology of guest is inconsistent with "
                          "expectations.")
def run(test, params, env):
    """
    Test hotplug vcpu devices with specified numa nodes.

    1) Boot up guest without vcpu device and with multi numa nodes.
    2) Hotplug vcpu devices and check successfully or not. (qemu side)
    3) Check if the number of CPUs in guest changes accordingly. (guest side)
    4) Check numa info in guest
    5) Hotunplug vcpu devices
    6) Recheck the numa info in guest

    :param test:   QEMU test object.
    :param params: Dictionary with the test parameters.
    :param env:    Dictionary with test environment.
    """
    def assign_numa_cpus(nodes, count):
        """Average allocation of cpu to each node."""
        cpus = list(map(str, range(maxcpus)))
        avg_count = maxcpus / float(len(nodes))
        if avg_count % count != 0:
            avg_count = round(avg_count / count) * count
        numa_cpus_list = []

        last = 0.0
        while last < maxcpus:
            numa_cpus_list.append(cpus[int(last):int(last + avg_count)])
            last += avg_count
        return dict(zip(nodes, numa_cpus_list))

    def get_guest_numa_cpus_info():
        """Get guest numa information via numactl"""
        # Skip this step on windows guest
        if os_type == "windows":
            return
        numa_out = session.cmd_output("numactl -H | grep cpus")
        numa_cpus_info = re.findall(r"^node (\d+) cpus:([\d| ]*)$", numa_out,
                                    re.M)
        return dict(map(lambda x: (x[0], x[1].split()), numa_cpus_info))

    os_type = params["os_type"]
    machine = params["machine_type"]
    login_timeout = params.get_numeric("login_timeout", 360)
    vm = env.get_vm(params["main_vm"])
    maxcpus = vm.cpuinfo.maxcpus
    alignment = vm.cpuinfo.threads if machine.startswith("pseries") else 1
    if not params.objects("vcpu_devices"):
        vcpus_count = (vm.cpuinfo.threads
                       if machine.startswith("pseries") else 1)
        pluggable_cpus = vm.cpuinfo.maxcpus // vcpus_count // 2
        params["vcpu_devices"] = " ".join(
            ["vcpu%d" % (count + 1) for count in range(pluggable_cpus)])
        vm.destroy()
        if len(params.objects("vcpu_devices")) < 2:
            test.cancel("Insufficient maxcpus for multi-CPU hotplug")
        params["paused_after_start_vm"] = "no"

    error_context.base_context("Define the cpu list for each numa node",
                               logging.info)
    numa_nodes = params.objects("guest_numa_nodes")
    node_ids = [params["numa_nodeid_%s" % node] for node in numa_nodes]
    node_cpus_mapping = assign_numa_cpus(node_ids, alignment)
    for node in numa_nodes:
        params["numa_cpus_%s" % node] = ",".join(
            node_cpus_mapping[params["numa_nodeid_%s" % node]])

    error_context.context("Launch the guest with our assigned numa node",
                          logging.info)
    vcpu_devices = params.objects("vcpu_devices")
    vm.create(params=params)
    if vm.is_paused():
        vm.resume()
    session = vm.wait_for_login(timeout=login_timeout)

    if params.get_boolean("workaround_need"):
        win_wora.modify_driver(params, session)

    error_context.context("Check the number of guest CPUs after startup",
                          logging.info)
    if not cpu_utils.check_if_vm_vcpus_match_qemu(vm):
        test.error("The number of guest CPUs is not equal to the qemu command "
                   "line configuration")

    if os_type == "linux" and not utils_package.package_install(
            "numactl", session):
        test.cancel("Please install numactl to proceed")
    numa_before_plug = get_guest_numa_cpus_info()
    for vcpu_dev in vcpu_devices:
        error_context.context("hotplug vcpu device: %s" % vcpu_dev,
                              logging.info)
        vm.hotplug_vcpu_device(vcpu_dev)
    if not utils_misc.wait_for(
            lambda: cpu_utils.check_if_vm_vcpus_match_qemu(vm), 10):
        test.fail("Actual number of guest CPUs is not equal to expected")

    if os_type == "linux":
        error_context.context("Check the CPU information of each numa node",
                              logging.info)
        guest_numa_cpus = get_guest_numa_cpus_info()
        for node_id, node_cpus in node_cpus_mapping.items():
            try:
                if guest_numa_cpus[node_id] != node_cpus:
                    logging.debug("Current guest numa info:\n%s",
                                  session.cmd_output("numactl -H"))
                    test.fail("The cpu obtained by guest is inconsistent with "
                              "we assigned.")
            except KeyError:
                test.error("Could not find node %s in guest." % node_id)
        logging.info("Number of each CPU in guest matches what we assign.")

        for vcpu_dev in vcpu_devices[::-1]:
            error_context.context("hotunplug vcpu device: %s" % vcpu_dev,
                                  logging.info)
            vm.hotunplug_vcpu_device(vcpu_dev)
        if not utils_misc.wait_for(
                lambda: cpu_utils.check_if_vm_vcpus_match_qemu(vm), 10):
            test.fail("Actual number of guest CPUs is not equal to expected")
        if get_guest_numa_cpus_info() != numa_before_plug:
            logging.debug("Current guest numa info:\n%s",
                          session.cmd_output("numactl -H"))
            test.fail("Numa info of guest is incorrect after vcpu hotunplug.")
def run(test, params, env):
    """
    Test hotplug invalid vcpu device.

    1) Boot up guest without vcpu device.
    2) Hotplug an invalid vcpu device we want
    3) Check error messages and analyze if it is correct

    :param test: QEMU test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environment.
    """
    not_match_err = ("Hotplug %s failed but the error description does not "
                     "match: '%s'")
    expected_info = "Hotplug %s failed as expected, error description: '%s'"
    hotplug_pass_err = "Still able to hotplug %s via qmp"

    def hotplug_inuse_vcpu():
        """Hotplug 2 in use vcpu devices: main vcpu and duplicate vcpu"""
        # Main vCPU
        main_vcpu_props = {}
        for vcpu_prop in vcpu_props:
            main_vcpu_props.setdefault(vcpu_prop, "0")
        vm.params["vcpu_props_main_vcpu"] = json.dumps(main_vcpu_props)
        error_context.context("Define the invalid vcpu: %s" % "main_vcpu",
                              logging.info)
        in_use_vcpu_dev = vm.devices.vcpu_device_define_by_params(
            vm.params, "main_vcpu")
        try:
            error_context.context("Hotplug the main vcpu", logging.info)
            in_use_vcpu_dev.enable(vm.monitor)
        except QMPCmdError as err:
            qmp_desc = err.data["desc"]
            if not re.match(error_desc.format("0"), qmp_desc):
                test.error(not_match_err % ("main vcpu", qmp_desc))
            logging.info(expected_info, "main vcpu", qmp_desc)
        else:
            test.fail(hotplug_pass_err % "main vcpu")

        # New vCPU
        error_context.context("hotplug vcpu device: %s" % vcpu_device_id,
                              logging.info)
        vm.hotplug_vcpu_device(vcpu_device_id)
        if not utils_misc.wait_for(
                lambda: cpu_utils.check_if_vm_vcpus_match_qemu(vm), 10):
            test.fail("Actual number of guest CPUs is not equal to expected")

        # Duplicate vCPU
        duplicate_vcpu_params = vm.devices.get_by_qid(
            vcpu_device_id)[0].params.copy()
        del duplicate_vcpu_params["id"]
        vm.params["vcpu_props_duplicate_vcpu"] = json.dumps(
            duplicate_vcpu_params)
        duplicate_vcpu_dev = vm.devices.vcpu_device_define_by_params(
            vm.params, "duplicate_vcpu")
        try:
            error_context.context("hotplug the duplicate vcpu", logging.info)
            duplicate_vcpu_dev.enable(vm.monitor)
        except QMPCmdError as err:
            dev_count = maxcpus
            if 'ppc64' in arch_name:
                dev_count //= threads
            qmp_desc = err.data["desc"]
            if not re.match(error_desc.format(str(dev_count - 1)), qmp_desc):
                test.error(not_match_err % ("duplicate vcpu", qmp_desc))
            logging.info(expected_info, "duplicate vcpu", qmp_desc)
        else:
            test.fail(hotplug_pass_err % "duplicate vcpu")

    def hotplug_invalid_vcpu():
        """Hotplug a vcpu device with invalid property id"""
        vcpu_device = vm.devices.get_by_qid(vcpu_device_id)[0]
        vm.devices.remove(vcpu_device)
        for invalid_id in params.objects("invalid_ids"):
            vcpu_device.set_param(params["invalid_property"], invalid_id)
            try:
                vcpu_device.enable(vm.monitor)
            except QMPCmdError as err:
                qmp_desc = err.data["desc"]
                if "ppc64" in arch_name:
                    # When the invalid_id is positive or negative, the initial
                    # letter format is different
                    qmp_desc = qmp_desc.lower()
                if error_desc.format(invalid_id) != qmp_desc:
                    test.error(not_match_err % ("invalid vcpu", qmp_desc))
                logging.info(expected_info, "invalid vcpu", qmp_desc)
            else:
                test.fail(hotplug_pass_err % "invalid vcpu")

    def hotplug_outofrange_vcpu():
        """Hotplug a vcpu device with out of range property id"""
        vcpu_device = vm.devices.get_by_qid(vcpu_device_id)[0]
        vm.devices.remove(vcpu_device)
        outofrange_vcpu_num = max(vcpu_bus.addr_lengths)
        vcpu_device.set_param(vcpu_props[0], outofrange_vcpu_num)
        try:
            vcpu_device.enable(vm.monitor)
        except QMPCmdError as err:
            qmp_desc = err.data["desc"]
            if error_desc.format(outofrange_vcpu_num, vcpu_props[0],
                                 (vcpu_bus.addr_lengths[0] - 1)) != qmp_desc:
                test.error(not_match_err % ("out_of_range vcpu", qmp_desc))
            logging.info(expected_info, "out_of_range vcpu", qmp_desc)
        else:
            test.fail(hotplug_pass_err % "out_of_range vcpu")

    arch_name = params.get('vm_arch_name', arch.ARCH)
    vcpu_device_id = params["vcpu_devices"]
    error_desc = params["error_desc"]
    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()
    session = vm.wait_for_login()

    if params.get_boolean("workaround_need"):
        win_wora.modify_driver(params, session)

    error_context.context("Check the number of guest CPUs after startup",
                          logging.info)
    if not cpu_utils.check_if_vm_vcpus_match_qemu(vm):
        test.error("The number of guest CPUs is not equal to the qemu command "
                   "line configuration")

    vcpu_bus = vm.devices.get_buses({'aobject': 'vcpu'})[0]
    vcpu_props = vcpu_bus.addr_items
    maxcpus = vm.cpuinfo.maxcpus
    threads = vm.cpuinfo.threads

    invalid_hotplug_tests = {
        "in_use_vcpu": hotplug_inuse_vcpu,
        "invalid_vcpu": hotplug_invalid_vcpu,
        "out_of_range_vcpu": hotplug_outofrange_vcpu
    }
    invalid_hotplug_tests[params["execute_test"]]()
    session.close()
Exemple #4
0
def run(test, params, env):
    """
    Test hotplug maximum vCPU device.

    1) Launch a guest without vCPU device.
    2) Hotplug all vCPU devices and check successfully or not. (qemu side)
    3) Check if the number of CPUs in guest changes accordingly. (guest side)
    4) Reboot guest.
    5) Hotunplug all vCPU devices and check successfully or not. (qemu side)

    :param test:   QEMU test object.
    :param params: Dictionary with the test parameters.
    :param env:    Dictionary with test environment.
    """
    os_type = params["os_type"]
    machine_type = params["machine_type"]
    reboot_timeout = params.get_numeric("reboot_timeout")
    offline_vcpu_after_hotplug = params.get_boolean(
        "offline_vcpu_after_hotplug")
    mismatch_text = "Actual number of guest CPUs is not equal to the expected"
    # Many vCPUs will be plugged, it takes some time to bring them online.
    verify_wait_timeout = params.get_numeric("verify_wait_timeout", 300)
    qemu_binary = utils_misc.get_qemu_binary(params)
    machine_info = utils_qemu.get_machines_info(qemu_binary)[machine_type]
    machine_info = re.search(r'\(alias of (\S+)\)', machine_info)
    current_machine = machine_info.group(1) if machine_info else machine_type
    supported_maxcpus = (params.get_numeric("vcpu_maxcpus")
                         or utils_qemu.get_maxcpus_hard_limit(
                             qemu_binary, current_machine))
    if not params.get_boolean("allow_pcpu_overcommit"):
        supported_maxcpus = min(supported_maxcpus, cpu.online_count())

    logging.info("Define the CPU topology of guest")
    vcpu_devices = []
    if (cpu.get_vendor() == "amd" and params.get_numeric("vcpu_threads") != 1):
        test.cancel("AMD cpu does not support multi threads")
    elif machine_type.startswith("pseries"):
        host_kernel_ver = uname()[2].split("-")[0]
        if params.get_numeric("vcpu_threads") == 8:
            supported_maxcpus -= divmod(supported_maxcpus, 8)[1]
            vcpu_devices = [
                "vcpu%d" % c for c in range(1, supported_maxcpus // 8)
            ]
        # The maximum value of vcpu_id in 'linux-3.x' is 2048, so
        # (vcpu_id * ms->smp.threads / spapr->vsmt) <= 256, need to adjust it
        elif (supported_maxcpus > 256
              and host_kernel_ver not in VersionInterval("[4, )")):
            supported_maxcpus = 256
    vcpu_devices = vcpu_devices or [
        "vcpu%d" % vcpu for vcpu in range(1, supported_maxcpus)
    ]
    params["vcpu_maxcpus"] = str(supported_maxcpus)
    params["vcpu_devices"] = " ".join(vcpu_devices)
    params["start_vm"] = "yes"

    vm = env.get_vm(params["main_vm"])
    vm.create(params=params)
    vm.verify_alive()
    session = vm.wait_for_login()
    cpuinfo = vm.cpuinfo
    smp = cpuinfo.smp
    vcpus_count = vm.params.get_numeric("vcpus_count")

    if params.get_boolean("workaround_need"):
        win_wora.modify_driver(params, session)

    error_context.context("Check the number of guest CPUs after startup",
                          logging.info)
    if not cpu_utils.check_if_vm_vcpus_match_qemu(vm):
        test.error("The number of guest CPUs is not equal to the qemu command "
                   "line configuration")

    error_context.context("Hotplug all vCPU devices", logging.info)
    for vcpu_device in vcpu_devices:
        vm.hotplug_vcpu_device(vcpu_device)

    error_context.context("Check Number of vCPU in guest", logging.info)
    if not utils_misc.wait_for(
            lambda: cpu_utils.check_if_vm_vcpus_match_qemu(vm),
            verify_wait_timeout,
            first=5,
            step=10):
        test.fail(mismatch_text)

    if params.get_boolean("check_cpu_topology", True):
        error_context.context("Check CPU topology of guest", logging.info)
        if not cpu_utils.check_if_vm_vcpu_topology_match(
                session, os_type, cpuinfo):
            test.fail("CPU topology of guest is not as expected.")
        session = vm.reboot(session, timeout=reboot_timeout)
        if not cpu_utils.check_if_vm_vcpu_topology_match(
                session, os_type, cpuinfo):
            test.fail("CPU topology of guest is not as expected after reboot.")

    if os_type == "linux":
        error_context.context("Hotunplug all vCPU devices", logging.info)
        if offline_vcpu_after_hotplug:
            hotplugged_vcpu = range(smp, supported_maxcpus)
            vcpu_list = "%d-%d" % (hotplugged_vcpu[0], hotplugged_vcpu[-1])
            logging.info("Offline vCPU: %s.", vcpu_list)
            session.cmd("chcpu -d %s" % vcpu_list,
                        timeout=len(hotplugged_vcpu))
            if vm.get_cpu_count() != smp:
                test.error("Failed to offline all hotplugged vCPU.")
        for vcpu_device in reversed(vcpu_devices):
            vm.hotunplug_vcpu_device(vcpu_device, 10 * vcpus_count)
        if not utils_misc.wait_for(
                lambda: cpu_utils.check_if_vm_vcpus_match_qemu(vm),
                verify_wait_timeout,
                first=5,
                step=10):
            test.fail(mismatch_text)
        session.close()
Exemple #5
0
def run(test, params, env):
    """
    Test hotplug vcpu devices and execute stress test.

    1) Boot up guest without vcpu device.
    2) Hotplug vcpu devices and check successfully or not. (qemu side)
    3) Check if the number of CPUs in guest changes accordingly. (guest side)
    4) Execute stress test on all hotplugged vcpu devices
    5) Hotunplug vcpu devices during stress test
    6) Recheck the number of CPUs in guest.

    :param test:   QEMU test object.
    :param params: Dictionary with the test parameters.
    :param env:    Dictionary with test environment.
    """
    def heavyload_install():
        if session.cmd_status(test_installed_cmd) != 0:
            logging.warning("Could not find installed heavyload in guest, will"
                            " install it via winutils.iso ")
            winutil_drive = utils_misc.get_winutils_vol(session)
            if not winutil_drive:
                test.cancel("WIN_UTILS CDROM not found.")
            install_cmd = params["install_cmd"] % winutil_drive
            session.cmd(install_cmd)

    os_type = params["os_type"]
    vm_arch_name = params.get('vm_arch_name', arch.ARCH)
    login_timeout = params.get_numeric("login_timeout", 360)
    stress_duration = params.get_numeric("stress_duration", 180)
    verify_wait_timeout = params.get_numeric("verify_wait_timeout", 60)
    vcpu_devices = params.objects("vcpu_devices")

    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()
    session = vm.wait_for_login(timeout=login_timeout)

    if params.get_boolean("workaround_need"):
        win_wora.modify_driver(params, session)

    error_context.context("Check the number of guest CPUs after startup",
                          logging.info)
    if not cpu_utils.check_if_vm_vcpus_match_qemu(vm):
        test.error("The number of guest CPUs is not equal to the qemu command "
                   "line configuration")

    guest_cpu_ids = cpu_utils.get_guest_cpu_ids(session, os_type)
    for vcpu_dev in vcpu_devices:
        error_context.context("Hotplug vcpu device: %s" % vcpu_dev,
                              logging.info)
        vm.hotplug_vcpu_device(vcpu_dev)
    if not utils_misc.wait_for(
            lambda: cpu_utils.check_if_vm_vcpus_match_qemu(vm),
            verify_wait_timeout):
        test.fail("Actual number of guest CPUs is not equal to expected")

    if os_type == "linux":
        stress_args = params["stress_args"]
        stress_tool = cpu_utils.VMStressBinding(vm,
                                                params,
                                                stress_args=stress_args)
        current_guest_cpu_ids = cpu_utils.get_guest_cpu_ids(session, os_type)
        plugged_cpu_ids = list(current_guest_cpu_ids - guest_cpu_ids)
        plugged_cpu_ids.sort()
        for cpu_id in plugged_cpu_ids:
            error_context.context(
                "Run stress on vCPU(%d) inside guest." % cpu_id, logging.info)
            stress_tool.load_stress_tool(cpu_id)
        error_context.context(
            "Successfully launched stress sessions, execute "
            "stress test for %d seconds" % stress_duration, logging.info)
        time.sleep(stress_duration)
        if utils_package.package_install("sysstat", session):
            error_context.context("Check usage of guest CPUs", logging.info)
            mpstat_cmd = "mpstat 1 5 -P %s | cat" % ",".join(
                map(str, plugged_cpu_ids))
            mpstat_out = session.cmd_output(mpstat_cmd)
            cpu_stat = dict(
                re.findall(r"Average:\s+(\d+)\s+(\d+\.\d+)", mpstat_out, re.M))
            for cpu_id in plugged_cpu_ids:
                cpu_usage_rate = float(cpu_stat[str(cpu_id)])
                if cpu_usage_rate < 50:
                    test.error("Stress test on vCPU(%s) failed, usage rate: "
                               "%.2f%%" % (cpu_id, cpu_usage_rate))
                logging.info("Usage rate of vCPU(%s) is: %.2f%%", cpu_id,
                             cpu_usage_rate)
        if not vm_arch_name.startswith("s390"):
            for vcpu_dev in vcpu_devices:
                error_context.context("Hotunplug vcpu device: %s" % vcpu_dev,
                                      logging.info)
                vm.hotunplug_vcpu_device(vcpu_dev)
                # Drift the running stress task to other vCPUs
                time.sleep(random.randint(5, 10))
            if not cpu_utils.check_if_vm_vcpus_match_qemu(vm):
                test.fail("Actual number of guest CPUs is not equal to "
                          "expected")
        stress_tool.unload_stress()
        stress_tool.clean()
    else:
        install_path = params["install_path"]
        test_installed_cmd = 'dir "%s" | findstr /I heavyload' % install_path
        heavyload_install()
        error_context.context("Run heavyload inside guest.", logging.info)
        heavyload_bin = r'"%s\heavyload.exe" ' % install_path
        heavyload_options = [
            "/CPU %d" % vm.get_cpu_count(),
            "/DURATION %d" % (stress_duration // 60), "/AUTOEXIT", "/START"
        ]
        start_cmd = heavyload_bin + " ".join(heavyload_options)
        stress_tool = BackgroundTest(
            session.cmd, (start_cmd, stress_duration, stress_duration))
        stress_tool.start()
        if not utils_misc.wait_for(
                stress_tool.is_alive, verify_wait_timeout, first=5):
            test.error("Failed to start heavyload process.")
        stress_tool.join(stress_duration)

    session.close()