<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>