[libvirt] PATCH: Implement vCPU cpuTime + cpu fields for QEMU

Daniel P. Berrange berrange at redhat.com
Mon Jul 27 14:48:36 UTC 2009


The qemudDomainGetVcpus() method in QEMU driver has the following long
standing todo item

               /* XXX cpu time, current pCPU mapping */

This has caused confusion for users, because they set affinity and then
wonder why 'virsh vcpuinfo' constantly reports their guest as running
on pCPU 0. This patch implements the missing bits, pulling it out of

  /proc/$PID/task/$TID/stat

ie, the per-vCPU thread status file

Daniel

diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index c594495..388843f 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -2465,24 +2465,44 @@ cleanup:
 }
 
 
-static int qemudGetProcessInfo(unsigned long long *cpuTime, int pid) {
+static int qemudGetProcessInfo(unsigned long long *cpuTime, int *lastCpu, int pid, int tid) {
     char proc[PATH_MAX];
     FILE *pidinfo;
     unsigned long long usertime, systime;
+    int cpu;
+    int ret;
 
-    if (snprintf(proc, sizeof(proc), "/proc/%d/stat", pid) >= (int)sizeof(proc)) {
+    if (tid)
+        ret = snprintf(proc, sizeof(proc), "/proc/%d/task/%d/stat", pid, tid);
+    else
+        ret = snprintf(proc, sizeof(proc), "/proc/%d/stat", pid);
+    if (ret >= (int)sizeof(proc)) {
+        errno = E2BIG;
         return -1;
     }
 
     if (!(pidinfo = fopen(proc, "r"))) {
         /*printf("cannot read pid info");*/
         /* VM probably shut down, so fake 0 */
-        *cpuTime = 0;
+        if (cpuTime)
+            *cpuTime = 0;
+        if (lastCpu)
+            *lastCpu = 0;
         return 0;
     }
 
-    if (fscanf(pidinfo, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %llu %llu", &usertime, &systime) != 2) {
-        qemudDebug("not enough arg");
+    /* See 'man proc' for information about what all these fields are. We're
+     * only interested in a very few of them */
+    if (fscanf(pidinfo,
+               /* pid -> stime */
+               "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %llu %llu"
+               /* cutime -> endcode */
+               "%*d %*d %*d %*d %*d %*u %*u %*d %*u %*u %*u %*u"
+               /* startstack -> processor */
+               "%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %d",
+               &usertime, &systime, &cpu) != 3) {
+        VIR_WARN0("cannot parse process status data");
+        errno = -EINVAL;
         return -1;
     }
 
@@ -2491,9 +2511,14 @@ static int qemudGetProcessInfo(unsigned long long *cpuTime, int pid) {
      * _SC_CLK_TCK is jiffies per second
      * So calulate thus....
      */
-    *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);
+    if (cpuTime)
+        *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);
+    if (lastCpu)
+        *lastCpu = cpu;
+
 
-    qemudDebug("Got %llu %llu %llu", usertime, systime, *cpuTime);
+    VIR_DEBUG("Got status for %d/%d user=%llu sys=%llu cpu=%d",
+              pid, tid, usertime, systime, cpu);
 
     fclose(pidinfo);
 
@@ -3133,7 +3158,7 @@ static int qemudDomainGetInfo(virDomainPtr dom,
     if (!virDomainIsActive(vm)) {
         info->cpuTime = 0;
     } else {
-        if (qemudGetProcessInfo(&(info->cpuTime), vm->pid) < 0) {
+        if (qemudGetProcessInfo(&(info->cpuTime), NULL, vm->pid, 0) < 0) {
             qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, ("cannot read cputime for domain"));
             goto cleanup;
         }
@@ -3676,7 +3701,16 @@ qemudDomainGetVcpus(virDomainPtr dom,
             for (i = 0 ; i < maxinfo ; i++) {
                 info[i].number = i;
                 info[i].state = VIR_VCPU_RUNNING;
-                /* XXX cpu time, current pCPU mapping */
+
+                if (vm->vcpupids != NULL &&
+                    qemudGetProcessInfo(&(info[i].cpuTime),
+                                        &(info[i].cpu),
+                                        vm->pid,
+                                        vm->vcpupids[i]) < 0) {
+                    virReportSystemError(dom->conn, errno, "%s",
+                                         _("cannot get vCPU placement & pCPU time"));
+                    goto cleanup;
+                }
             }
         }
 


-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




More information about the libvir-list mailing list