Example #1
0
def get_cpustats(vm, cpu=None):
    """
    Get the cpustats output of a given domain
    :param vm: VM domain
    :param cpu: Host cpu index, default all cpus
    :return: dict of cpu stats values
    result format:
    {0:[vcputime,emulatortime,cputime]
    ..
    'total':[cputime]}
     """
    host_cpu_online = utils.cpu_online_list()
    cpustats = {}
    if cpu:
        cpustats[cpu] = []
        option = "--start %s --count 1" % cpu
        result = virsh.cpu_stats(vm.name, option)
        if result.exit_status != 0:
            logging.error("cpu stats command failed: %s",
                          results_stderr_52lts(result))
            return None
        output = results_stdout_52lts(result).strip().split()
        if re.match("CPU%s" % cpu, output[0]):
            cpustats[cpu] = [
                float(output[5]),  # vcputime
                float(output[2]) - float(output[5]),  # emulator
                float(output[2])
            ]  # cputime

    else:
        for i in range(len(host_cpu_online)):
            cpustats[host_cpu_online[i]] = []
            option = "--start %s --count 1" % host_cpu_online[i]
            result = virsh.cpu_stats(vm.name, option)
            if result.exit_status != 0:
                logging.error("cpu stats command failed: %s",
                              results_stderr_52lts(result))
                return None
            output = results_stdout_52lts(result).strip().split()
            if re.match("CPU%s" % host_cpu_online[i], output[0]):
                cpustats[host_cpu_online[i]] = [
                    float(output[5]),
                    float(output[2]) - float(output[5]),
                    float(output[2])
                ]
    result = virsh.cpu_stats(vm.name, "--total")
    cpustats["total"] = []
    if result.exit_status != 0:
        logging.error("cpu stats command failed: %s",
                      results_stderr_52lts(result))
        return None
    output = results_stdout_52lts(result).strip().split()
    cpustats["total"] = [float(output[2])]  # cputime
    return cpustats
Example #2
0
def get_cpustats(vm, cpu=None):
    """
    Get the cpustats output of a given domain
    :param vm: VM domain
    :param cpu: Host cpu index, default all cpus
    :return: dict of cpu stats values
    result format:
    {0:[vcputime,emulatortime,cputime]
    ..
    'total':[cputime]}
     """
    host_cpu_online = utils.cpu_online_list()
    cpustats = {}
    if cpu:
        cpustats[cpu] = []
        option = "--start %s --count 1" % cpu
        result = virsh.cpu_stats(vm.name, option)
        if result.exit_status != 0:
            logging.error("cpu stats command failed: %s",
                          results_stderr_52lts(result))
            return None
        output = results_stdout_52lts(result).strip().split()
        if re.match("CPU%s" % cpu, output[0]):
            cpustats[cpu] = [float(output[5]),  # vcputime
                             float(output[2]) - float(output[5]),  # emulator
                             float(output[2])]  # cputime

    else:
        for i in range(len(host_cpu_online)):
            cpustats[host_cpu_online[i]] = []
            option = "--start %s --count 1" % host_cpu_online[i]
            result = virsh.cpu_stats(vm.name, option)
            if result.exit_status != 0:
                logging.error("cpu stats command failed: %s",
                              results_stderr_52lts(result))
                return None
            output = results_stdout_52lts(result).strip().split()
            if re.match("CPU%s" % host_cpu_online[i], output[0]):
                cpustats[host_cpu_online[i]] = [float(output[5]),
                                                float(output[2]) - float(output[5]),
                                                float(output[2])]
    result = virsh.cpu_stats(vm.name, "--total")
    cpustats["total"] = []
    if result.exit_status != 0:
        logging.error("cpu stats command failed: %s",
                      results_stderr_52lts(result))
        return None
    output = results_stdout_52lts(result).strip().split()
    cpustats["total"] = [float(output[2])]  # cputime
    return cpustats
Example #3
0
    # Check vcpu number inside the domian
    if vm.state() == "running":
        session = vm.wait_for_login()
        cmd = "cat /proc/cpuinfo | grep processor | wc -l"
        try:
            output = session.cmd_output(cmd, timeout=10).strip()
        finally:
            session.close()
        if output != expect_vcpu_num[-1]:
            raise error.TestFail("Find %s CPUs in domain but expect %s" %
                                 (output, expect_vcpu_num[-1]))
        else:
            logging.debug("Find %s CPUs in domian as expected", output)

        # Check cpu-stats command, only for running domian
        result = virsh.cpu_stats(vm.name, "", ignore_status=True, debug=True)
        libvirt.check_exit_status(result)


def manipulate_domain(vm_name, vm_operation, recover=False):
    """
    Operate domain to given state or recover it.
    """
    save_file = os.path.join(data_dir.get_tmp_dir(), vm_name + ".save")
    if not recover:
        if vm_operation == "save":
            save_option = ""
            result = virsh.save(vm_name,
                                save_file,
                                save_option,
                                ignore_status=True,
Example #4
0
def run(test, params, env):
    """
    Test virsh cpu-stats command.

    The command can display domain per-CPU and total statistics.
    1. Call virsh cpu-stats [domain]
    2. Call virsh cpu-stats [domain] with valid options
    3. Call virsh cpu-stats [domain] with invalide options
    """

    if not virsh.has_help_command('cpu-stats'):
        raise error.TestNAError("This version of libvirt does not support "
                                "the cpu-stats test")

    vm_name = params.get("main_vm", "vm1")
    vm_ref = params.get("cpu_stats_vm_ref")
    status_error = params.get("status_error", "no")
    options = params.get("cpu_stats_options")
    logging.debug("options are %s", options)

    if vm_ref == "name":
        vm_ref = vm_name

    # get host cpus num
    cpus = multiprocessing.cpu_count()
    logging.debug("host cpu num is %s", cpus)

    # get options and put into a dict
    get_total = re.search('total', options)
    get_start = re.search('start', options)
    get_count = re.search('count', options)

    # command without options
    get_noopt = 0
    if not get_total and not get_start and not get_count:
        get_noopt = 1

    # command with only --total option
    get_totalonly = 0
    if not get_start and not get_count and get_total:
        get_totalonly = 1

    option_dict = {}
    if options.strip():
        option_list = options.split('--')
        logging.debug("option_list is %s", option_list)
        for match in option_list[1:]:
            if get_start or get_count:
                option_dict[match.split(' ')[0]] = match.split(' ')[1]

    # Run virsh command
    cmd_result = virsh.cpu_stats(vm_ref, options,
                                 ignore_status=True, debug=True)
    output = cmd_result.stdout.strip()
    status = cmd_result.exit_status

    # check status_error
    if status_error == "yes":
        if status == 0:
            raise error.TestFail("Run successfully with wrong command!")
    elif status_error == "no":
        if status != 0:
            raise error.TestFail("Run failed with right command")
        else:
            # Get cgroup cpu_time
            if not get_totalonly:
                vm = env.get_vm(vm_ref)
                cgpath = utils_cgroup.resolve_task_cgroup_path(
                    vm.get_pid(), "cpuacct")
                # When a VM has an 'emulator' child cgroup present, we must
                # strip off that suffix when detecting the cgroup for a machine
                if os.path.basename(cgpath) == "emulator":
                    cgpath = os.path.dirname(cgpath)
                usage_file = os.path.join(cgpath, "cpuacct.usage_percpu")
                cgtime = file(usage_file).read().strip().split()
                logging.debug("cgtime get is %s", cgtime)

            # Cut CPUs from output and format to list
            output = re.sub(r'\.', '', output)
            if get_total:
                mt_start = re.search('Total', output).start()
            else:
                mt_start = len(output)
            output_cpus = " ".join(output[:mt_start].split())
            cpus_list = re.compile(r'CPU\d+:').split(output_cpus)

            # conditions that list total time info
            if get_noopt or get_total:
                mt_end = re.search('Total', output).end()
                total_list = output[mt_end + 1:].split()

                total_time = int(total_list[1])
                user_time = int(total_list[4])
                system_time = int(total_list[7])

                # check Total cpu_time >= User + System cpu_time
                if user_time + system_time >= total_time:
                    raise error.TestFail("total cpu_time < user_time + "
                                         "system_time")
                logging.debug("Check total cpu_time %d >= user + system "
                              "cpu_time %d",
                              total_time, user_time + system_time)

            start_num = 0
            if get_start:
                start_num = int(option_dict["start"])

            end_num = int(cpus)
            if get_count:
                count_num = int(option_dict["count"])
                if end_num > start_num + count_num:
                    end_num = start_num + count_num

            # for only give --total option it only shows "Total" cpu info
            if get_totalonly:
                end_num = -1

            # find CPU[N] in output and sum the cpu_time and cgroup cpu_time
            sum_cputime = 0
            sum_cgtime = 0
            logging.debug("start_num %d, end_num %d", start_num, end_num)
            for i in range(start_num, end_num):
                if not re.search('CPU' + "%i" % i, output):
                    raise error.TestFail("Fail to find CPU" + "%i" % i + "in "
                                         "result")
                logging.debug("Check CPU" + "%i" % i + " exist")
                sum_cputime += int(cpus_list[i - start_num + 1].split()[1])
                sum_cgtime += int(cgtime[i])

            # check cgroup cpu_time > sum of cpu_time
            if end_num >= 0:
                if sum_cputime > sum_cgtime:
                    raise error.TestFail("Check sum of cgroup cpu_time < sum "
                                         "of output cpu_time")
                logging.debug("Check sum of cgroup cpu_time %d >= cpu_time %d",
                              sum_cgtime, sum_cputime)

            # check Total cpu_time >= sum of cpu_time when no options
            if get_noopt:
                if total_time < sum_cputime:
                    raise error.TestFail("total time < sum of output cpu_time")
                logging.debug("Check total time %d >= sum of output cpu_time"
                              " %d", total_time, sum_cputime)
    # Check vcpu number inside the domian
    if vm.state() == "running":
        session = vm.wait_for_login()
        cmd = "cat /proc/cpuinfo | grep processor | wc -l"
        try:
            output = session.cmd_output(cmd, timeout=10).strip()
        finally:
            session.close()
        if output != expect_vcpu_num[-1]:
            raise error.TestFail("Find %s CPUs in domain but expect %s"
                                 % (output, expect_vcpu_num[-1]))
        else:
            logging.debug("Find %s CPUs in domian as expected", output)

        # Check cpu-stats command, only for running domian
        result = virsh.cpu_stats(vm.name, "", ignore_status=True, debug=True)
        libvirt.check_exit_status(result)


def manipulate_domain(vm_name, vm_operation, recover=False):
    """
    Operate domain to given state or recover it.
    """
    save_file = os.path.join(data_dir.get_tmp_dir(), vm_name + ".save")
    if not recover:
        if vm_operation == "save":
            save_option = ""
            result = virsh.save(vm_name, save_file, save_option,
                                ignore_status=True, debug=True)
            libvirt.check_exit_status(result)
        elif vm_operation == "managedsave":
Example #6
0
def run(test, params, env):
    """
    Test virsh cpu-stats command.

    The command can display domain per-CPU and total statistics.
    1. Call virsh cpu-stats [domain]
    2. Call virsh cpu-stats [domain] with valid options
    3. Call virsh cpu-stats [domain] with invalid options
    """
    def get_cpuacct_info(suffix):
        """
        Get the CPU accounting info within the vm

        :param suffix: str, suffix of the CPU accounting.(stat/usage/usage_percpu)
        :return: list, the list of CPU accounting info
        """
        if 'cg_obj' not in locals():
            return
        # On cgroup v2 use cpu.stat as a substitute
        if cg_obj.is_cgroup_v2_enabled():
            cg_path = cg_obj.get_cgroup_path("cpu")
            para = ('cpu.%s' % suffix)
        else:
            cg_path = cg_obj.get_cgroup_path("cpuacct")
            para = ('cpuacct.%s' % suffix)
        # We only need the info in file which "emulator" is not in path
        if os.path.basename(cg_path) == "emulator":
            cg_path = os.path.dirname(cg_path)
        usage_file = os.path.join(cg_path, para)
        with open(usage_file, 'r') as f:
            cpuacct_info = f.read().strip().split()
        logging.debug("cpuacct info %s", cpuacct_info)
        return cpuacct_info

    def check_user_and_system_time(total_list):
        user_time = float(total_list[4])
        system_time = float(total_list[7])

        # Check libvirt user and system time between pre and next cgroup time
        # Unit conversion (Unit: second)
        # Default time unit is microseconds on cgroup v2 while 1/100 second on v1
        if cg_obj.is_cgroup_v2_enabled():
            pre_user_time = float(cpuacct_res_pre[3]) / 1000000
            pre_sys_time = float(cpuacct_res_pre[5]) / 1000000
            next_user_time = float(cpuacct_res_next[3]) / 1000000
            next_sys_time = float(cpuacct_res_next[5]) / 1000000
        else:
            pre_user_time = float(cpuacct_res_pre[1]) / 100
            pre_sys_time = float(cpuacct_res_pre[3]) / 100
            next_user_time = float(cpuacct_res_next[1]) / 100
            next_sys_time = float(cpuacct_res_next[3]) / 100

        # check user_time
        if next_user_time >= user_time >= pre_user_time:
            logging.debug("Got the expected user_time: %s", user_time)

        else:
            test.fail("Got unexpected user_time: %s, " % user_time +
                      "should between pre_user_time:%s " % pre_user_time +
                      "and next_user_time:%s" % next_user_time)

        # check system_time
        if next_sys_time >= system_time >= pre_sys_time:
            logging.debug("Got the expected system_time: %s", system_time)

        else:
            test.fail("Got unexpected system_time: %s, " % system_time +
                      "should between pre_sys_time:%s " % pre_sys_time +
                      "and next_sys_time:%s" % next_sys_time)

    if not virsh.has_help_command('cpu-stats'):
        test.cancel("This version of libvirt does not support "
                    "the cpu-stats test")

    vm_name = params.get("main_vm", "vm1")
    vm_ref = params.get("cpu_stats_vm_ref")
    status_error = params.get("status_error", "no")
    options = params.get("cpu_stats_options")
    error_msg = params.get("error_msg", "")
    logging.debug("options are %s", options)

    if vm_ref == "name":
        vm_ref = vm_name

    vm = env.get_vm(vm_ref)
    if vm and vm.get_pid():
        cg_obj = libvirt_cgroup.CgroupTest(vm.get_pid())
    # get host cpus num
    cpus = cpu.online_cpus_count()
    logging.debug("host online cpu num is %s", cpus)

    # get options and put into a dict
    get_total = re.search('total', options)
    get_start = re.search('start', options)
    get_count = re.search('count', options)

    # command without options
    get_noopt = 0
    if not get_total and not get_start and not get_count:
        get_noopt = 1

    # command with only --total option
    get_totalonly = 0
    if not get_start and not get_count and get_total:
        get_totalonly = 1

    option_dict = {}
    if options.strip():
        option_list = options.split('--')
        logging.debug("option_list is %s", option_list)
        for match in option_list[1:]:
            if get_start or get_count:
                option_dict[match.split(' ')[0]] = match.split(' ')[1]

    # check if cpu is enough,if not cancel the test
    if (status_error == "no"):
        cpu_start = int(option_dict.get("start", "0"))
        if cpu_start == 32:
            cpus = cpu.total_cpus_count()
            logging.debug("Host total cpu num: %s", cpus)
        if (cpu_start >= cpus):
            test.cancel("Host cpus are not enough")

    # get CPU accounting info twice to compare with user_time and system_time
    cpuacct_res_pre = get_cpuacct_info('stat')

    # Run virsh command
    cmd_result = virsh.cpu_stats(vm_ref,
                                 options,
                                 ignore_status=True,
                                 debug=True)
    output = cmd_result.stdout.strip()
    status = cmd_result.exit_status

    cpuacct_res_next = get_cpuacct_info('stat')

    # check status_error
    if status_error == "yes":
        if status == 0:
            test.fail("Run successfully with wrong command! Output: {}".format(
                output))
        else:
            # Check error message is expected
            if not re.search(error_msg, cmd_result.stderr.strip()):
                test.fail("Error message is not expected! "
                          "Expected: {} Actual: {}".format(
                              error_msg, cmd_result.stderr.strip()))
    elif status_error == "no":
        if status != 0:
            test.fail("Run failed with right command! Error: {}".format(
                cmd_result.stderr.strip()))
        else:
            # Get cgroup cpu_time
            if not get_totalonly:
                cgtime = get_cpuacct_info('usage_percpu')

            # Cut CPUs from output and format to list
            if get_total:
                mt_start = re.search('Total', output).start()
            else:
                mt_start = len(output)
            output_cpus = " ".join(output[:mt_start].split())
            cpus_list = re.compile(r'CPU\d+:').split(output_cpus)

            # conditions that list total time info
            if get_noopt or get_total:
                mt_end = re.search('Total', output).end()
                total_list = output[mt_end + 1:].split()
                total_time = float(total_list[1])
                check_user_and_system_time(total_list)

            start_num = 0
            if get_start:
                start_num = int(option_dict["start"])

            end_num = int(cpus)
            if get_count:
                count_num = int(option_dict["count"])
                if end_num > start_num + count_num:
                    end_num = start_num + count_num

            # for only give --total option it only shows "Total" cpu info
            if get_totalonly:
                end_num = -1

            # find CPU[N] in output and sum the cpu_time and cgroup cpu_time
            sum_cputime = 0
            sum_cgtime = 0
            logging.debug("start_num %d, end_num %d", start_num, end_num)
            for i in range(start_num, end_num):
                logging.debug("Check CPU" + "%i" % i + " exist")
                sum_cputime += float(cpus_list[i - start_num + 1].split()[1])
                sum_cgtime += float(cgtime[i])
                if not re.search('CPU' + "%i" % i, output):
                    test.fail("Fail to find CPU" + "%i" % i + "in " "result")

            # check cgroup cpu_time > sum of cpu_time
            if end_num >= 0:
                logging.debug("Check sum of cgroup cpu_time %d >= cpu_time %d",
                              sum_cgtime, sum_cputime)
                if sum_cputime > sum_cgtime:
                    test.fail("Check sum of cgroup cpu_time < sum "
                              "of output cpu_time")

            # check Total cpu_time >= sum of cpu_time when no options
            if get_noopt:
                logging.debug(
                    "Check total time %d >= sum of output cpu_time"
                    " %d", total_time, sum_cputime)
                if total_time < sum_cputime:
                    test.fail("total time < sum of output cpu_time")