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")
    mismatch_text = "Actual number of guest CPUs is not equal to the expected"
    not_equal_text = "CPU quantity mismatched! Guest got %s but expected is %s"
    # 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")

    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: vm.get_cpu_count() == supported_maxcpus,
                               verify_wait_timeout,
                               first=5,
                               step=10):
        logging.error(not_equal_text, vm.get_cpu_count(), supported_maxcpus)
        test.fail(mismatch_text)
    logging.info("CPU quantity is as expected: %s", supported_maxcpus)

    error_context.context("Check CPU topology of guest", logging.info)
    if not cpu_utils.check_guest_cpu_topology(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_guest_cpu_topology(session, os_type, cpuinfo):
        test.fail("CPU topology of guest is not as expected after reboot.")

    error_context.context("Hotunplug all vCPU devices", logging.info)
    for vcpu_device in reversed(vcpu_devices):
        vm.hotunplug_vcpu_device(vcpu_device, 10 * vcpus_count)
    if not utils_misc.wait_for(lambda: vm.get_cpu_count() == smp,
                               verify_wait_timeout,
                               first=5,
                               step=10):
        logging.error(not_equal_text, vm.get_cpu_count(), smp)
        test.fail(mismatch_text)
    logging.info("CPU quantity is as expected after hotunplug: %s", smp)
    session.close()
Exemple #2
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(expected_count):
        if not utils_misc.wait_for(
                lambda: vm.get_cpu_count() == expected_count,
                verify_wait_timeout,
                first=sleep_after_change):
            logging.error(
                "CPU quantity mismatched! Guest got %s but the"
                " expected is %s", vm.get_cpu_count(), expected_count)
            test.fail("Actual number of guest CPUs is not equal to expected")
        logging.info("CPU quantity matched: %s", expected_count)

    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)

    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(expected_vcpus)
            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))
            check_guest_cpu_count(smp)
            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)
    smp = vm.cpuinfo.smp
    maxcpus = vm.cpuinfo.maxcpus
    vcpus_count = vm.params.get_numeric("vcpus_count", 1)
    vcpu_devices = params.objects("vcpu_devices")
    guest_cpu_ids = cpu_utils.get_guest_cpu_ids(session, os_type)

    if hotpluggable_test == "hotplug":
        pluggable_vcpu_dev = vcpu_devices
        pluggable_vcpu = vcpus_count * len(pluggable_vcpu_dev)
    else:
        pluggable_vcpu_dev = vcpu_devices[::-1]
        pluggable_vcpu = -(vcpus_count * len(pluggable_vcpu_dev))
    expected_vcpus = vm.get_cpu_count() + pluggable_vcpu

    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(expected_vcpus)
    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 ("hotunplug" in params.objects("sub_test_after_migrate")
                or sub_test_type == "pause_resume"):
            expected_vcpus -= pluggable_vcpu

    if vm.is_alive():
        session = vm.wait_for_login(timeout=login_timeout)
        check_guest_cpu_count(expected_vcpus)
        if expected_vcpus == 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.")
Exemple #3
0
def run(test, params, env):
    """
    Check guest gets correct vcpu num, cpu cores, processors, sockets, siblings

    1) Boot guest with options: -smp n,cores=x,threads=y,sockets=z...
    2) Check cpu topology

    :param test: QEMU test object.
    :param params: Dictionary with test parameters.
    :param env: Dictionary with the test environment.
    """

    def check(p_name, exp, check_cmd):
        """
        Check the cpu property inside guest
        :param p_name: Property name
        :param exp: The expect value
        :param check_cmd: The param to get check command
        """
        res = session.cmd_output(params[check_cmd]).strip()
        if int(res) != int(exp):
            test.fail('The vcpu %s number inside guest is %s,'
                      ' while it is set to %s' % (p_name, res, exp))

    vm_name = params['main_vm']
    os_type = params['os_type']
    vcpu_threads_list = [1, 2]
    if params['machine_type'] == 'pseries':
        vcpu_threads_list = [1, 2, 4, 8]
    host_cpu = cpu.online_count()
    params['vcpu_cores'] = vcpu_cores = random.randint(1, min(6, host_cpu//2))
    for vcpu_threads in vcpu_threads_list:
        vcpu_sockets = min(max(host_cpu // (vcpu_cores * vcpu_threads), 1),
                           random.randint(1, 6))
        vcpu_sockets = 2 if (os_type == 'Windows' and
                             vcpu_sockets > 2) else vcpu_sockets
        params['vcpu_sockets'] = vcpu_sockets
        params['vcpu_threads'] = vcpu_threads
        params['smp'] = params['vcpu_maxcpus'] = (vcpu_cores *
                                                  vcpu_threads * vcpu_sockets)
        params['start_vm'] = 'yes'
        try:
            env_process.preprocess_vm(test, params, env, vm_name)
        except Exception as e:
            # The cpu topology sometimes will be changed by
            # qemu_vm.VM.make_create_command, and thus cause qemu vm fail to
            # start, which is expected; Modify the value and restart vm in
            # this case, and verify cpu topology inside guest after that
            if 'qemu-kvm: cpu topology' in str(e):
                sockets = int(re.findall(r'sockets\s+\((\d)\)', str(e))[0])
                threads = int(re.findall(r'threads\s+\((\d)\)', str(e))[0])
                cores = int(re.findall(r'cores\s+\((\d)\)', str(e))[0])
                params['smp'] = params['vcpu_maxcpus'] = (sockets *
                                                          threads * cores)
                env_process.preprocess_vm(test, params, env, vm_name)
            else:
                raise
        vm = env.get_vm(vm_name)
        session = vm.wait_for_login()
        check_guest_cpu_topology(session, os_type, vm.cpuinfo)
        if params.get('check_siblings_cmd'):
            check('sibling', vcpu_threads * vcpu_cores, 'check_siblings_cmd')
        vm.destroy()