From 707302b2cfdfeb04068dfae9862b5613ebd11a09 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Fri, 24 Jul 2009 12:34:20 +0100 Subject: [PATCH] Only probe qemu for machine types when binary changes 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 | 1 + src/qemu_conf.c | 97 +++++++++++++++++++++++++++++++++++++++++++--- src/qemu_conf.h | 2 +- src/qemu_driver.c | 4 +- 4 files changed, 95 insertions(+), 9 deletions(-) diff --git a/src/capabilities.h b/src/capabilities.h index aab084c093..b958d95045 100644 --- a/src/capabilities.h +++ b/src/capabilities.h @@ -49,6 +49,7 @@ struct _virCapsGuestDomainInfo { char *loader; int nmachines; virCapsGuestMachinePtr *machines; + time_t emulator_mtime; /* do @machines need refreshing? */ }; typedef struct _virCapsGuestDomain virCapsGuestDomain; diff --git a/src/qemu_conf.c b/src/qemu_conf.c index a3986dff3d..a9d559e593 100644 --- a/src/qemu_conf.c +++ b/src/qemu_conf.c @@ -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; diff --git a/src/qemu_conf.h b/src/qemu_conf.h index 316a787e98..ad68e317fa 100644 --- a/src/qemu_conf.h +++ b/src/qemu_conf.h @@ -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); diff --git a/src/qemu_driver.c b/src/qemu_driver.c index d5db9aebf2..54e0f4fd6e 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -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; }