<p dir="ltr"><br>
13 дек. 2015 г. 12:53 пользователь "Daniel P. Berrange" <<a href="mailto:berrange@redhat.com">berrange@redhat.com</a>> написал:<br>
><br>
> The VIR_DOMAIN_STATS_VCPU flag to virDomainListGetStats<br>
> enables reporting of stats about vCPUs. Currently we<br>
> only report the cumulative CPU running time and the<br>
> execution state.<br>
><br>
> This adds reporting of the wait time - time the vCPU<br>
> wants to run, but the host schedular has something else<br>
> running ahead of it.<br>
><br></p>
<p dir="ltr">As i understand this is well known steal time analog that can be viewed inside vm?</p>
<p dir="ltr">> The data is reported per-vCPU eg<br>
><br>
> $ virsh domstats --vcpu demo<br>
>  Domain: 'demo'<br>
>    vcpu.current=4<br>
>    vcpu.maximum=4<br>
>    vcpu.0.state=1<br>
>    vcpu.0.time=1420000000<br>
>    vcpu.0.wait=18403928<br>
>    vcpu.1.state=1<br>
>    vcpu.1.time=130000000<br>
>    vcpu.1.wait=10612111<br>
>    vcpu.2.state=1<br>
>    vcpu.2.time=110000000<br>
>    vcpu.2.wait=12759501<br>
>    vcpu.3.state=1<br>
>    vcpu.3.time=90000000<br>
>    vcpu.3.wait=21825087<br>
><br>
> In implementing this I notice our reporting of CPU execute<br>
> time has very poor granularity, since we are getting it<br>
> from /proc/$PID/stat. As a future enhancement we should<br>
> prefer to get CPU execute time from /proc/$PID/schedstat<br>
> or /proc/$PID/sched (if either exist on the running kernel)<br>
><br>
> Signed-off-by: Daniel P. Berrange <<a href="mailto:berrange@redhat.com">berrange@redhat.com</a>><br>
> ---<br>
>  src/qemu/qemu_driver.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++--<br>
>  1 file changed, 96 insertions(+), 4 deletions(-)<br>
><br>
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c<br>
> index 783a7cd..5293294 100644<br>
> --- a/src/qemu/qemu_driver.c<br>
> +++ b/src/qemu/qemu_driver.c<br>
> @@ -1361,6 +1361,80 @@ static char *qemuConnectGetCapabilities(virConnectPtr conn) {<br>
><br>
><br>
>  static int<br>
> +qemuGetSchedInfo(unsigned long long *cpuWait,<br>
> +                 pid_t pid, pid_t tid)<br>
> +{<br>
> +    char *proc = NULL;<br>
> +    char *data = NULL;<br>
> +    char **lines = NULL;<br>
> +    size_t i;<br>
> +    int ret = -1;<br>
> +    double val;<br>
> +<br>
> +    *cpuWait = 0;<br>
> +<br>
> +    /* In general, we cannot assume pid_t fits in int; but /proc parsing<br>
> +     * is specific to Linux where int works fine.  */<br>
> +    if (tid)<br>
> +        ret = virAsprintf(&proc, "/proc/%d/task/%d/sched", (int)pid, (int)tid);<br>
> +    else<br>
> +        ret = virAsprintf(&proc, "/proc/%d/sched", (int)pid);<br>
> +    if (ret < 0)<br>
> +        goto cleanup;<br>
> +<br>
> +    /* The file is not guaranteed to exist (needs CONFIG_SCHED_DEBUG) */<br>
> +    if (access(proc, R_OK) < 0)<br>
> +        return 0;<br>
> +<br>
> +    if (virFileReadAll(proc, (1<<16), &data) < 0)<br>
> +        goto cleanup;<br>
> +<br>
> +    lines = virStringSplit(data, "\n", 0);<br>
> +    if (!lines)<br>
> +        goto cleanup;<br>
> +<br>
> +    for (i = 0; lines[i] != NULL; i++) {<br>
> +        const char *line = lines[i];<br>
> +<br>
> +        /* Needs CONFIG_SCHEDSTATS. The second check<br>
> +         * is the old name the kernel used in past */<br>
> +        if (STRPREFIX(line, "se.statistics.wait_sum") ||<br>
> +            STRPREFIX(line, "se.wait_sum")) {<br>
> +            line = strchr(line, ':');<br>
> +            if (!line) {<br>
> +                virReportError(VIR_ERR_INTERNAL_ERROR,<br>
> +                               _("Missing separate in sched info '%s'"),<br>
> +                               lines[i]);<br>
> +                goto cleanup;<br>
> +            }<br>
> +            line++;<br>
> +            while (*line == ' ') {<br>
> +                line++;<br>
> +            }<br>
> +<br>
> +            if (virStrToDouble(line, NULL, &val) < 0) {<br>
> +                virReportError(VIR_ERR_INTERNAL_ERROR,<br>
> +                               _("Unable to parse sched info value '%s'"),<br>
> +                               line);<br>
> +                goto cleanup;<br>
> +            }<br>
> +<br>
> +            *cpuWait = (unsigned long long)(val * 1000000);<br>
> +            break;<br>
> +        }<br>
> +    }<br>
> +<br>
> +    ret = 0;<br>
> +<br>
> + cleanup:<br>
> +    VIR_FREE(data);<br>
> +    VIR_FREE(proc);<br>
> +    VIR_FREE(lines);<br>
> +    return ret;<br>
> +}<br>
> +<br>
> +<br>
> +static int<br>
>  qemuGetProcessInfo(unsigned long long *cpuTime, int *lastCpu, long *vm_rss,<br>
>                     pid_t pid, int tid)<br>
>  {<br>
> @@ -1424,6 +1498,7 @@ qemuGetProcessInfo(unsigned long long *cpuTime, int *lastCpu, long *vm_rss,<br>
>  static int<br>
>  qemuDomainHelperGetVcpus(virDomainObjPtr vm,<br>
>                           virVcpuInfoPtr info,<br>
> +                         unsigned long long *cpuwait,<br>
>                           int maxinfo,<br>
>                           unsigned char *cpumaps,<br>
>                           int maplen)<br>
> @@ -1476,6 +1551,11 @@ qemuDomainHelperGetVcpus(virDomainObjPtr vm,<br>
>              virBitmapFree(map);<br>
>          }<br>
><br>
> +        if (cpuwait) {<br>
> +            if (qemuGetSchedInfo(&(cpuwait[i]), vm->pid, vcpupid) < 0)<br>
> +                return -1;<br>
> +        }<br>
> +<br>
>          ncpuinfo++;<br>
>      }<br>
><br>
> @@ -5517,7 +5597,7 @@ qemuDomainGetVcpus(virDomainPtr dom,<br>
>          goto cleanup;<br>
>      }<br>
><br>
> -    ret = qemuDomainHelperGetVcpus(vm, info, maxinfo, cpumaps, maplen);<br>
> +    ret = qemuDomainHelperGetVcpus(vm, info, NULL, maxinfo, cpumaps, maplen);<br>
><br>
>   cleanup:<br>
>      virDomainObjEndAPI(&vm);<br>
> @@ -19089,6 +19169,7 @@ qemuDomainGetStatsVcpu(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,<br>
>      int ret = -1;<br>
>      char param_name[VIR_TYPED_PARAM_FIELD_LENGTH];<br>
>      virVcpuInfoPtr cpuinfo = NULL;<br>
> +    unsigned long long *cpuwait = NULL;<br>
><br>
>      if (virTypedParamsAddUInt(&record->params,<br>
>                                &record->nparams,<br>
> @@ -19104,10 +19185,12 @@ qemuDomainGetStatsVcpu(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,<br>
>                                virDomainDefGetVcpusMax(dom->def)) < 0)<br>
>          return -1;<br>
><br>
> -    if (VIR_ALLOC_N(cpuinfo, virDomainDefGetVcpus(dom->def)) < 0)<br>
> -        return -1;<br>
> +    if (VIR_ALLOC_N(cpuinfo, virDomainDefGetVcpus(dom->def)) < 0 ||<br>
> +        VIR_ALLOC_N(cpuwait, virDomainDefGetVcpus(dom->def)) < 0)<br>
> +        goto cleanup;<br>
><br>
> -    if (qemuDomainHelperGetVcpus(dom, cpuinfo, virDomainDefGetVcpus(dom->def),<br>
> +    if (qemuDomainHelperGetVcpus(dom, cpuinfo, cpuwait,<br>
> +                                 virDomainDefGetVcpus(dom->def),<br>
>                                   NULL, 0) < 0) {<br>
>          virResetLastError();<br>
>          ret = 0; /* it's ok to be silent and go ahead */<br>
> @@ -19136,12 +19219,21 @@ qemuDomainGetStatsVcpu(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,<br>
>                                      param_name,<br>
>                                      cpuinfo[i].cpuTime) < 0)<br>
>              goto cleanup;<br>
> +        snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,<br>
> +                 "vcpu.%zu.wait", i);<br>
> +        if (virTypedParamsAddULLong(&record->params,<br>
> +                                    &record->nparams,<br>
> +                                    maxparams,<br>
> +                                    param_name,<br>
> +                                    cpuwait[i]) < 0)<br>
> +            goto cleanup;<br>
>      }<br>
><br>
>      ret = 0;<br>
><br>
>   cleanup:<br>
>      VIR_FREE(cpuinfo);<br>
> +    VIR_FREE(cpuwait);<br>
>      return ret;<br>
>  }<br>
><br>
> --<br>
> 2.5.0<br>
><br>
> --<br>
> libvir-list mailing list<br>
> <a href="mailto:libvir-list@redhat.com">libvir-list@redhat.com</a><br>
> <a href="https://www.redhat.com/mailman/listinfo/libvir-list">https://www.redhat.com/mailman/listinfo/libvir-list</a><br>
</p>