[libvirt] [PATCH v2 05/10] Determine whether to start balloon memory stats gathering.

John Ferlan jferlan at redhat.com
Thu Jul 11 16:28:51 UTC 2013


On 07/11/2013 10:05 AM, Michal Privoznik wrote:
> On 08.07.2013 21:20, John Ferlan wrote:
>> At vm startup, reconnect, and attach - check for the presence of the balloon
>> driver and save the path in the private area of the driver.  This path will
>> remain constant throughout the life of the domain and can then be used rather
>> than attempting to find the path each time balloon driver statistics are
>> fetched or the collection period changes. The qom object model model requires
>> setting object properties after device startup.  That is, it's not possible
>> to pass the period along via the startup code as it won't be recognized.
>> If a balloon driver path is found a check of the existing collection period
>> will be made against the saved domain value in order to determine if an
>> adjustment needs to be made to the period to start or stop collecting stats
>> ---
>>  src/qemu/qemu_monitor.c      | 130 +++++++++++++++++++++++++++++++++++++++++++
>>  src/qemu/qemu_monitor.h      |   2 +
>>  src/qemu/qemu_monitor_json.c |  42 ++++++++++++++
>>  src/qemu/qemu_monitor_json.h |   3 +
>>  src/qemu/qemu_process.c      |  21 ++++++-
>>  5 files changed, 196 insertions(+), 2 deletions(-)
>>
>> diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
>> index fe5ab0a..038c9e8 100644
>> --- a/src/qemu/qemu_monitor.c
>> +++ b/src/qemu/qemu_monitor.c
>> @@ -83,6 +83,9 @@ struct _qemuMonitor {
>>  
>>      /* cache of query-command-line-options results */
>>      virJSONValuePtr options;
>> +
>> +    /* If found, path to the virtio memballoon driver */
>> +    char *balloonpath;
>>  };
>>  
>>  static virClassPtr qemuMonitorClass;
>> @@ -248,6 +251,7 @@ static void qemuMonitorDispose(void *obj)
>>      virCondDestroy(&mon->notify);
>>      VIR_FREE(mon->buffer);
>>      virJSONValueFree(mon->options);
>> +    VIR_FREE(mon->balloonpath);
>>  }
>>  
>>  
>> @@ -929,6 +933,107 @@ qemuMonitorSetOptions(qemuMonitorPtr mon, virJSONValuePtr options)
>>      mon->options = options;
>>  }
>>  
>> +/* Search the qom objects for the balloon driver object by it's known name
>> + * of "virtio-balloon-pci".  The entry for the driver will be found in the
>> + * returned 'type' field using the syntax "child<virtio-balloon-pci>".
>> + *
>> + * Once found, check the entry to ensure it has the correct property listed.
>> + * If it does not, then obtaining statistics from qemu will not be possible.
>> + * This feature was added to qemu 1.5.
>> + *
>> + * This procedure will be call recursively until found or the qom-list is
>> + * exhausted.
>> + *
>> + * Returns:
>> + *
>> + *   1  - Found
>> + *   0  - Not found still looking
>> + *  -1  - Error bail out
>> + *
>> + * NOTE: This assumes we have already called qemuDomainObjEnterMonitor()
>> + */
>> +static int
>> +qemuMonitorFindBalloonObjectPath(qemuMonitorPtr mon,
>> +                                 virDomainObjPtr vm,
>> +                                 const char *curpath)
>> +{
>> +    int i,j;
> 
> size_t i,j, npaths = 0, nprops = 0;
> 

yep...

>> +    int npaths = 0;
>> +    int nprops = 0;
>> +    int ret = 0;
>> +    char *nextpath = NULL;
>> +    qemuMonitorJSONListPathPtr *paths = NULL;
>> +    qemuMonitorJSONListPathPtr *bprops = NULL;
>> +
>> +    /* Not supported */
>> +    if (vm->def->memballoon &&
>> +        vm->def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO) {
>> +        VIR_DEBUG("Model must be virtio to get memballoon path");
>> +        return -1;
>> +    }
>> +
>> +    /* Already set and won't change */
>> +    if (mon->balloonpath)
>> +        return 1;
>> +
>> +    VIR_DEBUG("Searching for Balloon Object Path starting at %s", curpath);
>> +
>> +    npaths = qemuMonitorJSONGetObjectListPaths(mon, curpath, &paths);
>> +
>> +    for (i = 0; i < npaths && ret == 0; i++) {
>> +
>> +        if (STREQ_NULLABLE(paths[i]->type, "link<virtio-balloon-pci>")) {
>> +            VIR_DEBUG("Path to <virtio-balloon-pci> is '%s/%s'",
>> +                      curpath, paths[i]->name);
>> +            if (virAsprintf(&nextpath, "%s/%s", curpath, paths[i]->name) < 0) {
>> +                ret = -1;
>> +                goto cleanup;
>> +            }
>> +
>> +            /* Now look at the each of the property entries to determine
>> +             * whether "guest-stats-polling-interval" exists.  If not,
>> +             * then this version of qemu/kvm does not support the feature.
>> +             */
>> +            nprops = qemuMonitorJSONGetObjectListPaths(mon, nextpath, &bprops);
>> +            for (j = 0; j < nprops; j++) {
>> +                if (STREQ(bprops[j]->name, "guest-stats-polling-interval")) {
>> +                    mon->balloonpath = nextpath;
>> +                    nextpath = NULL;
>> +                    ret = 1;
>> +                    goto cleanup;
> 
> Maybe I'd add VIR_DEBUG() here to log the path.
> 

Funny - I did have one at one time along with a boatload more to print
each return along the way.  It got lost while I was stripping out the
extraneous debug code.

>> +                }
>> +            }
>> +
>> +            /* If we get here, we found the path, but not the property */
>> +            VIR_DEBUG("Property 'guest-stats-polling-interval' not found");
>> +            ret = -1;
>> +            goto cleanup;
>> +        }
>> +
>> +        /* Type entries that begin with "child<" are a branch that can be
>> +         * traversed looking for more entries
>> +         */
>> +        if (paths[i]->type && STRPREFIX(paths[i]->type, "child<")) {
>> +            if (virAsprintf(&nextpath, "%s/%s", curpath, paths[i]->name) < 0) {
>> +                virReportOOMError();
>> +                ret = -1;
>> +                goto cleanup;
>> +            }
>> +            ret = qemuMonitorFindBalloonObjectPath(mon, vm, nextpath);
>> +        }
>> +    }
>> +
>> +cleanup:
>> +    for (i = 0; i < npaths; i++)
>> +        qemuMonitorJSONListPathFree(paths[i]);
>> +    VIR_FREE(paths);
>> +    for (j = 0; j < nprops; j++)
>> +        qemuMonitorJSONListPathFree(bprops[j]);
>> +    VIR_FREE(bprops);
>> +    VIR_FREE(nextpath);
>> +    return ret;
>> +}
>> +
>>  int qemuMonitorHMPCommandWithFd(qemuMonitorPtr mon,
>>                                  const char *cmd,
>>                                  int scm_fd,
>> @@ -1390,6 +1495,31 @@ int qemuMonitorGetMemoryStats(qemuMonitorPtr mon,
>>      return ret;
>>  }
>>  
>> +int qemuMonitorSetMemoryStatsPeriod(qemuMonitorPtr mon,
>> +                                    int period)
>> +{
>> +    int ret = -1;
>> +    VIR_DEBUG("mon=%p period=%d", mon, period);
>> +
>> +    if (!mon) {
>> +        virReportError(VIR_ERR_INVALID_ARG, "%s",
>> +                       _("monitor must not be NULL"));
>> +        return -1;
>> +    }
>> +
>> +    if (!mon->json) {
>> +        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
>> +                       _("JSON monitor is required"));
>> +        return -1;
>> +    }
>> +
>> +    if (qemuMonitorFindBalloonObjectPath(mon, mon->vm, "/") == 1) {
>> +        ret = qemuMonitorJSONSetMemoryStatsPeriod(mon, mon->balloonpath,
>> +                                                  period);
>> +    }
>> +    return ret;
>> +}
>> +
>>  int
>>  qemuMonitorBlockIOStatusToError(const char *status)
>>  {
>> diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
>> index 78011ee..12b730a 100644
>> --- a/src/qemu/qemu_monitor.h
>> +++ b/src/qemu/qemu_monitor.h
>> @@ -265,6 +265,8 @@ int qemuMonitorGetBalloonInfo(qemuMonitorPtr mon,
>>  int qemuMonitorGetMemoryStats(qemuMonitorPtr mon,
>>                                virDomainMemoryStatPtr stats,
>>                                unsigned int nr_stats);
>> +int qemuMonitorSetMemoryStatsPeriod(qemuMonitorPtr mon,
>> +                                    int period);
>>  
>>  int qemuMonitorBlockIOStatusToError(const char *status);
>>  virHashTablePtr qemuMonitorGetBlockInfo(qemuMonitorPtr mon);
>> diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
>> index 9487955..2d7f9b6 100644
>> --- a/src/qemu/qemu_monitor_json.c
>> +++ b/src/qemu/qemu_monitor_json.c
>> @@ -1495,6 +1495,48 @@ cleanup:
>>  }
>>  
>>  
>> +/*
>> + * Using the provided balloonpath, determine if we need to set the
> 
> s/balloonpath/balloon path/
> 

balloonpath is the variable name...

>> + * collection interval property to enable statistics gathering.
>> + */
>> +int
>> +qemuMonitorJSONSetMemoryStatsPeriod(qemuMonitorPtr mon,
>> +                                    char *balloonpath,
>> +                                    int period)
>> +{
>> +    qemuMonitorJSONObjectProperty prop;
>> +
>> +    /* Get the current value of the stats polling interval */
>> +    memset(&prop, 0, sizeof(qemuMonitorJSONObjectProperty));
>> +    prop.type = QEMU_MONITOR_OBJECT_PROPERTY_INT;
>> +    if (qemuMonitorJSONGetObjectProperty(mon, balloonpath,
>> +                                         "guest-stats-polling-interval",
>> +                                         &prop) < 0) {
>> +        VIR_DEBUG("Failed to get polling interval for balloon driver");
>> +        return 0;
> 
> Shouldn't we return -1 here? I mean, if caller requires us to set an
> interval, we should error out if we fail. Why are we querying for the
> interval prior setting it anyway?
> 

I struggled with this return as well when I first added the code - I
think this was added before saving the path and before checking in the
path code that we our path had a polling-interval property.

So, considering the "current" design it's duplicitous to get the value
and check it against the current setting before setting, so I've removed it.


>> +    }
>> +
>> +    VIR_DEBUG("memballoon period=%d 'guest-stats-polling-interval'=%d",
>> +              period,  prop.val.i);
>> +
>> +    /* Same value - no need to set */
>> +    if (period == prop.val.i)
>> +        return 0;
>> +
>> +    /* Set to the value in memballoon (could enable or disable) */
>> +    memset(&prop, 0, sizeof(qemuMonitorJSONObjectProperty));
>> +    prop.type = QEMU_MONITOR_OBJECT_PROPERTY_INT;
>> +    prop.val.i = period;
>> +    if (qemuMonitorJSONSetObjectProperty(mon, balloonpath,
>> +                                         "guest-stats-polling-interval",
>> +                                         &prop) < 0) {
>> +        VIR_DEBUG("Failed to set polling interval for balloon driver");
> 
> This is unnecessary as long as qemuMonitorJSONSetObjectProperty reports
> error on retval < 0, which it does.
> 

OK gone.

>> +        return -1;
>> +    }
>> +    return 0;
>> +}
>> +
>> +
>>  int qemuMonitorJSONGetBlockInfo(qemuMonitorPtr mon,
>>                                  virHashTablePtr table)
>>  {
>> diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
>> index fd0dedd..b0068ff 100644
>> --- a/src/qemu/qemu_monitor_json.h
>> +++ b/src/qemu/qemu_monitor_json.h
>> @@ -61,6 +61,9 @@ int qemuMonitorJSONGetBalloonInfo(qemuMonitorPtr mon,
>>  int qemuMonitorJSONGetMemoryStats(qemuMonitorPtr mon,
>>                                    virDomainMemoryStatPtr stats,
>>                                    unsigned int nr_stats);
>> +int qemuMonitorJSONSetMemoryStatsPeriod(qemuMonitorPtr mon,
>> +                                        char *balloonpath,
>> +                                        int period);
>>  int qemuMonitorJSONGetBlockInfo(qemuMonitorPtr mon,
>>                                  virHashTablePtr table);
>>  int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
>> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
>> index f8c652f..fd3b7a8 100644
>> --- a/src/qemu/qemu_process.c
>> +++ b/src/qemu/qemu_process.c
>> @@ -3091,6 +3091,13 @@ qemuProcessReconnect(void *opaque)
>>      if (qemuProcessRecoverJob(driver, obj, conn, &oldjob) < 0)
>>          goto error;
>>  
>> +    if (obj->def->memballoon) {
>> +        qemuDomainObjEnterMonitor(driver, obj);
>> +        qemuMonitorSetMemoryStatsPeriod(priv->mon,
>> +                                        obj->def->memballoon->period);
>> +        qemuDomainObjExitMonitor(driver, obj);
>> +    }
>> +
> 
> Why do we want to enable this on ProcessReconnect?
> 

Before I had a way to dynamically set the period I only had the period
in the XML file, thus this was the only way to "get" the stats to show
up for a running guest when I installed the new code and restarted
libvirtd.

Tks,

John

>>      /* update domain state XML with possibly updated state in virDomainObj */
>>      if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, obj) < 0)
>>          goto error;
>> @@ -3910,6 +3917,9 @@ int qemuProcessStart(virConnectPtr conn,
>>          goto cleanup;
>>      }
>>      qemuDomainObjEnterMonitor(driver, vm);
>> +    if (vm->def->memballoon)
>> +        qemuMonitorSetMemoryStatsPeriod(priv->mon,
>> +                                        vm->def->memballoon->period);
> 
> It makes sense here.
> 
>>      if (qemuMonitorSetBalloon(priv->mon, cur_balloon) < 0) {
>>          qemuDomainObjExitMonitor(driver, vm);
>>          goto cleanup;
>> @@ -4439,11 +4449,18 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED,
>>      if (!virDomainObjIsActive(vm))
>>          goto cleanup;
>>  
>> -    if (running)
>> +    if (running) {
>>          virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
>>                               VIR_DOMAIN_RUNNING_UNPAUSED);
>> -    else
>> +        if (vm->def->memballoon) {
>> +            qemuDomainObjEnterMonitor(driver, vm);
>> +            qemuMonitorSetMemoryStatsPeriod(priv->mon,
>> +                                            vm->def->memballoon->period);
>> +            qemuDomainObjExitMonitor(driver, vm);
>> +        }
>> +    } else {
>>          virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, reason);
>> +    }
>>  
>>      VIR_DEBUG("Writing domain status to disk");
>>      if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
>>
> 
> Michal
> 




More information about the libvir-list mailing list