]> xenbits.xensource.com Git - libvirt.git/commitdiff
Only probe qemu for machine types when binary changes
authorMark McLoughlin <markmc@redhat.com>
Fri, 24 Jul 2009 11:34:20 +0000 (12:34 +0100)
committerMark McLoughlin <markmc@redhat.com>
Mon, 27 Jul 2009 14:30:35 +0000 (15:30 +0100)
By probing for qemu machine types, we increased the time of a
GetCapabilities call from 100us to a whopping 60ms.

This patch takes the approach of only probing for machine types
when the mtime of the emulator binary changed since the last time
the capabilities were generated.

* src/capabilities.h: cache the emulator binary mtime

* src/qemu_conf.c: add qemudGetOldMachines() to copy the machine
  types from the old caps struct if the mtime for the binary hasn't
  changed

* src/qemu_conf.h, src/qemu_driver.c: pass the old caps pointer to
  qemudCapsInit()

src/capabilities.h
src/qemu_conf.c
src/qemu_conf.h
src/qemu_driver.c

index aab084c093ecd0688543b903345ea040d445345c..b958d950450de5f1df3619f8bbe487e24700cd5e 100644 (file)
@@ -49,6 +49,7 @@ struct _virCapsGuestDomainInfo {
     char *loader;
     int nmachines;
     virCapsGuestMachinePtr *machines;
+    time_t emulator_mtime; /* do @machines need refreshing? */
 };
 
 typedef struct _virCapsGuestDomain virCapsGuestDomain;
index a3986dff3d13ec0ac24c544babedf6a98cbb9bf3..a9d559e593d66c6ea65fe2a054be06921c21aea3 100644 (file)
@@ -456,8 +456,73 @@ rewait:
     return ret;
 }
 
+static int
+qemudGetOldMachines(const char *ostype,
+                    const char *arch,
+                    int wordsize,
+                    const char *emulator,
+                    time_t emulator_mtime,
+                    virCapsPtr old_caps,
+                    virCapsGuestMachinePtr **machines,
+                    int *nmachines)
+{
+    int i;
+
+    for (i = 0; i < old_caps->nguests; i++) {
+        virCapsGuestPtr guest = old_caps->guests[i];
+        virCapsGuestDomainInfoPtr info = &guest->arch.defaultInfo;
+        virCapsGuestMachinePtr *list;
+
+        if (!STREQ(ostype, guest->ostype) ||
+            !STREQ(arch, guest->arch.name) ||
+            wordsize != guest->arch.wordsize ||
+            !STREQ(emulator, info->emulator))
+            continue;
+
+        if (emulator_mtime != info->emulator_mtime) {
+            VIR_DEBUG("mtime on %s has changed, refreshing machine types",
+                      info->emulator);
+            return 0;
+        }
+
+        /* It sucks to have to dup these, when we're most likely going
+         * to free the old caps anyway - except if an error occurs, we'll
+         * stick with the old caps.
+         * Also, if we get OOM here, just let the caller try and probe
+         * the binary directly, which will probably fail too.
+         */
+        if (VIR_ALLOC_N(list, info->nmachines) < 0)
+            return 0;
+
+        for (i = 0; i < info->nmachines; i++) {
+            if (VIR_ALLOC(list[i]) < 0) {
+                virCapabilitiesFreeMachines(list, info->nmachines);
+                return 0;
+            }
+            if (info->machines[i]->name &&
+                !(list[i]->name = strdup(info->machines[i]->name))) {
+                virCapabilitiesFreeMachines(list, info->nmachines);
+                return 0;
+            }
+            if (info->machines[i]->canonical &&
+                !(list[i]->canonical = strdup(info->machines[i]->canonical))) {
+                virCapabilitiesFreeMachines(list, info->nmachines);
+                return 0;
+            }
+        }
+
+        *machines = list;
+        *nmachines = info->nmachines;
+
+        return 1;
+    }
+
+    return 0;
+}
+
 static int
 qemudCapsInitGuest(virCapsPtr caps,
+                   virCapsPtr old_caps,
                    const char *hostmachine,
                    const struct qemu_arch_info *info,
                    int hvm) {
@@ -467,8 +532,10 @@ qemudCapsInitGuest(virCapsPtr caps,
     int haskqemu = 0;
     const char *kvmbin = NULL;
     const char *binary = NULL;
+    time_t binary_mtime;
     virCapsGuestMachinePtr *machines = NULL;
     int nmachines = 0;
+    struct stat st;
 
     /* Check for existance of base emulator, or alternate base
      * which can be used with magic cpu choice
@@ -507,6 +574,15 @@ qemudCapsInitGuest(virCapsPtr caps,
     if (!binary)
         return 0;
 
+    if (stat(binary, &st) == 0) {
+        binary_mtime = st.st_mtime;
+    } else {
+        char ebuf[1024];
+        VIR_WARN(_("Failed to stat %s, most peculiar : %s"),
+                 binary, virStrerror(errno, ebuf, sizeof(ebuf)));
+        binary_mtime = 0;
+    }
+
     if (info->machine) {
         virCapsGuestMachinePtr machine;
 
@@ -526,9 +602,16 @@ qemudCapsInitGuest(virCapsPtr caps,
 
         machines[0] = machine;
         nmachines = 1;
-
-    } else if (qemudProbeMachineTypes(binary, &machines, &nmachines) < 0)
-        return -1;
+    } else {
+        int probe = 1;
+        if (old_caps && binary_mtime)
+            probe = !qemudGetOldMachines(hvm ? "hvm" : "xen", info->arch,
+                                         info->wordsize, binary, binary_mtime,
+                                         old_caps, &machines, &nmachines);
+        if (probe &&
+            qemudProbeMachineTypes(binary, &machines, &nmachines) < 0)
+            return -1;
+    }
 
     /* We register kvm as the base emulator too, since we can
      * just give -no-kvm to disable acceleration if required */
@@ -548,6 +631,8 @@ qemudCapsInitGuest(virCapsPtr caps,
         return -1;
     }
 
+    guest->arch.defaultInfo.emulator_mtime = binary_mtime;
+
     if (hvm) {
         if (virCapabilitiesAddGuestDomain(guest,
                                           "qemu",
@@ -597,7 +682,7 @@ qemudCapsInitGuest(virCapsPtr caps,
     return 0;
 }
 
-virCapsPtr qemudCapsInit(void) {
+virCapsPtr qemudCapsInit(virCapsPtr old_caps) {
     struct utsname utsname;
     virCapsPtr caps;
     int i;
@@ -626,7 +711,7 @@ virCapsPtr qemudCapsInit(void) {
 
     /* First the pure HVM guests */
     for (i = 0 ; i < ARRAY_CARDINALITY(arch_info_hvm) ; i++)
-        if (qemudCapsInitGuest(caps,
+        if (qemudCapsInitGuest(caps, old_caps,
                                utsname.machine,
                                &arch_info_hvm[i], 1) < 0)
             goto no_memory;
@@ -639,7 +724,7 @@ virCapsPtr qemudCapsInit(void) {
             if (STREQ(arch_info_xen[i].arch, utsname.machine) ||
                 (STREQ(utsname.machine, "x86_64") &&
                  STREQ(arch_info_xen[i].arch, "i686"))) {
-                if (qemudCapsInitGuest(caps,
+                if (qemudCapsInitGuest(caps, old_caps,
                                        utsname.machine,
                                        &arch_info_xen[i], 0) < 0)
                     goto no_memory;
index 316a787e98c7152e14fef4bd5eee1edab6b8a549..ad68e317faf08a04e0be76a318adcf90beff480e 100644 (file)
@@ -125,7 +125,7 @@ struct qemud_driver {
 int qemudLoadDriverConfig(struct qemud_driver *driver,
                           const char *filename);
 
-virCapsPtr  qemudCapsInit               (void);
+virCapsPtr  qemudCapsInit               (virCapsPtr old_caps);
 
 int         qemudExtractVersion         (virConnectPtr conn,
                                          struct qemud_driver *driver);
index d5db9aebf2f296ebac9eff395e53796dcaa54d75..54e0f4fd6e53549d5394e7d74c20e28823f11f73 100644 (file)
@@ -516,7 +516,7 @@ qemudStartup(int privileged) {
                  virStrerror(-rc, buf, sizeof(buf)));
     }
 
-    if ((qemu_driver->caps = qemudCapsInit()) == NULL)
+    if ((qemu_driver->caps = qemudCapsInit(NULL)) == NULL)
         goto out_of_memory;
 
     if (qemudLoadDriverConfig(qemu_driver, driverConf) < 0) {
@@ -2440,7 +2440,7 @@ static char *qemudGetCapabilities(virConnectPtr conn) {
     char *xml = NULL;
 
     qemuDriverLock(driver);
-    if ((caps = qemudCapsInit()) == NULL) {
+    if ((caps = qemudCapsInit(qemu_driver->caps)) == NULL) {
         virReportOOMError(conn);
         goto cleanup;
     }