13 дек. 2015 г. 12:53 пользователь "Daniel P. Berrange" <berrange@redhat.com> написал:
>
> The VIR_DOMAIN_STATS_VCPU flag to virDomainListGetStats
> enables reporting of stats about vCPUs. Currently we
> only report the cumulative CPU running time and the
> execution state.
>
> This adds reporting of the wait time - time the vCPU
> wants to run, but the host schedular has something else
> running ahead of it.
>

As i understand this is well known steal time analog that can be viewed inside vm?

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