[libvirt] [PATCHv7 17/18] qemu: Report cache occupancy (CMT) with domstats

Wang, Huaqiang huaqiang.wang at intel.com
Mon Nov 12 12:03:24 UTC 2018



On 11/6/2018 4:04 AM, John Ferlan wrote:
> On 10/22/18 4:01 AM, Wang Huaqiang wrote:
>> Adding the interface in qemu to report CMT statistic information
>> through command 'virsh domstats --cpu-total'.
>>
>> Below is a typical output:
>>
>>           # virsh domstats 1 --cpu-total
>>           Domain: 'ubuntu16.04-base'
>>             ...
>>             cpu.cache.monitor.count=2
>>             cpu.cache.monitor.0.name=vcpus_1
>>             cpu.cache.monitor.0.vcpus=1
>>             cpu.cache.monitor.0.bank.count=2
>>             cpu.cache.monitor.0.bank.0.id=0
>>             cpu.cache.monitor.0.bank.0.bytes=4505600
>>             cpu.cache.monitor.0.bank.1.id=1
>>             cpu.cache.monitor.0.bank.1.bytes=5586944
>>             cpu.cache.monitor.1.name=vcpus_4-6
>>             cpu.cache.monitor.1.vcpus=4,5,6
>>             cpu.cache.monitor.1.bank.count=2
>>             cpu.cache.monitor.1.bank.0.id=0
>>             cpu.cache.monitor.1.bank.0.bytes=17571840
>>             cpu.cache.monitor.1.bank.1.id=1
>>             cpu.cache.monitor.1.bank.1.bytes=29106176
>>
>> Signed-off-by: Wang Huaqiang<huaqiang.wang at intel.com>
>> ---
>>   src/libvirt-domain.c     |   9 ++
>>   src/libvirt_private.syms |   1 +
>>   src/qemu/qemu_driver.c   | 229 +++++++++++++++++++++++++++++++++++++++++++++++
>>   src/util/virresctrl.c    | 130 +++++++++++++++++++++++++++
>>   src/util/virresctrl.h    |  12 +++
>>   5 files changed, 381 insertions(+)
>>
> I have a feeling I'll be asking for this to be split up a bit, but let's
> see...  There's *util, *qemu, and *API code in the same patch.



>> diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
>> index 7690339..4895f9f 100644
>> --- a/src/libvirt-domain.c
>> +++ b/src/libvirt-domain.c
>> @@ -11345,6 +11345,15 @@ virConnectGetDomainCapabilities(virConnectPtr conn,
>>    *     "cpu.user" - user cpu time spent in nanoseconds as unsigned long long.
>>    *     "cpu.system" - system cpu time spent in nanoseconds as unsigned long
>>    *                    long.
>> + *     "cpu.cache.monitor.count" - tocal cache monitoring groups
>> + *     "cpu.cache.monitor.M.name" - name of cache monitoring group 'M'
>> + *     "cpu.cache.monitor.M.vcpus" - vcpus for cache monitoring group 'M'
>> + *     "cpu.cache.monitor.M.bank.count" - total bank number of cache monitoring
>> + *                    group 'M'
>> + *     "cpu.cache.monitor.M.bank.N.id" - OS assigned cache bank id for cache
>> + *                    'N' in cache monitoring group 'M'
>> + *     "cpu.cache.monitor.M.bank.N.bytes" - monitor's cache occupancy of cache
>> + *                    bank 'N' in cache monitoring group 'M'
>>    *
>>    * VIR_DOMAIN_STATS_BALLOON:
>>    *     Return memory balloon device information.
>> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
>> index 91801ed..4551767 100644
>> --- a/src/libvirt_private.syms
>> +++ b/src/libvirt_private.syms
>> @@ -2683,6 +2683,7 @@ virResctrlInfoNew;
>>   virResctrlMonitorAddPID;
>>   virResctrlMonitorCreate;
>>   virResctrlMonitorDeterminePath;
>> +virResctrlMonitorGetCacheOccupancy;
>>   virResctrlMonitorGetID;
>>   virResctrlMonitorIsRunning;
>>   virResctrlMonitorNew;
>> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
>> index 12a5f8f..9828118 100644
>> --- a/src/qemu/qemu_driver.c
>> +++ b/src/qemu/qemu_driver.c
>> @@ -102,6 +102,7 @@
>>   #include "virnuma.h"
>>   #include "dirname.h"
>>   #include "netdev_bandwidth_conf.h"
>> +#include "c-ctype.h"
> Ahh.. this one's a red flag...  Says to me that something should move to
> a util function...

Got.  Header file will be removed (actually I planned to remove all code 
using it.)

>>   
>>   #define VIR_FROM_THIS VIR_FROM_QEMU
>>   
>> @@ -19698,6 +19699,230 @@ typedef enum {
>>   #define HAVE_JOB(flags) ((flags) & QEMU_DOMAIN_STATS_HAVE_JOB)
>>   
>>   
>> +/* In terms of the output of virBitmapFormat, both '1-3' and '1,3' are valid
>> + * outputs and represent different vcpu set. But it is not easy to
>> + * differentiate these two vcpu set formats at first glance.
>> + *
>> + * This function could be used to clear this ambiguity, it substitutes all '-'
>> + * with ',' while generates semantically correct vcpu set.
>> + * e.g. vcpu set string '1-3' will be replaced by string '1,2,3'. */
>> +static char *
>> +qemuDomainVcpuFormatHelper(const char *vcpus)
>> +{
>> +    size_t i = 0;
>> +    int last = 0;
>> +    int start = 0;
>> +    char * tmp = NULL;
>> +    bool firstnum = true;
>> +    const char *cur = vcpus;
>> +    virBuffer buf = VIR_BUFFER_INITIALIZER;
>> +    char *ret = NULL;
>> +
>> +    if (virStringIsEmpty(cur))
>> +        return NULL;
>> +
>> +    while (*cur != '\0') {
>> +        if (!c_isdigit(*cur))
> Explains the #include, but in the long run, I don't think this method is
> worth the effort since all you're doing is printing the format in the
> output. Is there other libvirt generated output for cpu stats that does
> a similar conversion?  If so, share code, if not drop this.
>
> No need to rearrange the range someone else entered and we've
> succesfully parsed in some manner. I think the output should look like
> the XML output unless there's some compelling reason to change it which
> I don't see.
>
>  From above the:
>
>>             cpu.cache.monitor.1.name=vcpus_4-6
>>             cpu.cache.monitor.1.vcpus=4,5,6
> would then be:
>
>>             cpu.cache.monitor.1.name=vcpus_4-6
>>             cpu.cache.monitor.1.vcpus=4-6
> right?

Yes, this heavy function is just re-formatting the output of vcpus.
I also think it not worth to do this kind of reformat. Let's remove it.


> I don't even want to think about someone who does "7,4-6"...
>
>> +            goto cleanup;
>> +
>> +        if (virStrToLong_i(cur, &tmp, 10, &start) < 0)
>> +            goto cleanup;
>> +        if (start < 0)
>> +            goto cleanup;
>> +
>> +        cur = tmp;
>> +
>> +        virSkipSpaces(&cur);
>> +
>> +        if (*cur == ',' || *cur == 0) {
>> +            if (!firstnum)
>> +                virBufferAddChar(&buf, ',');
>> +            virBufferAsprintf(&buf, "%d", start);
>> +            firstnum = false;
>> +        } else if (*cur == '-') {
>> +            cur++;
>> +            virSkipSpaces(&cur);
>> +
>> +            if (virStrToLong_i(cur, &tmp, 10, &last) < 0)
>> +                goto cleanup;
>> +
>> +            if (last < start)
>> +                goto cleanup;
>> +            cur = tmp;
>> +
>> +            for (i = start; i <= last; i++) {
>> +                if (!firstnum)
>> +
>> +                    virBufferAddChar(&buf, ',');
>> +                virBufferAsprintf(&buf, "%ld", i);
>> +                firstnum = 0;
>> +            }
>> +
>> +            virSkipSpaces(&cur);
>> +        }
>> +
>> +        if (*cur == ',') {
>> +            cur++;
>> +            virSkipSpaces(&cur);
>> +        } else if (*cur == 0) {
>> +            break;
>> +        } else {
>> +            goto cleanup;
>> +        }
>> +    }
>> +
>> +    ret = virBufferContentAndReset(&buf);
>> + cleanup:
>> +    virBufferFreeAndReset(&buf);
>> +    return ret;
>> +}
>> +
>> +
>> +static int
>> +qemuDomainGetStatsCpuResource(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
>> +                              virDomainObjPtr dom,
>> +                              virDomainStatsRecordPtr record,
>> +                              int *maxparams,
>> +                              unsigned int privflags ATTRIBUTE_UNUSED,
>> +                              virResctrlMonitorType restag)
> Why bother passing ATTRIBUTE_UNUSED ?

I just copy-pasted the function header from some other function.
Will be removed since it is an internal function.

>> +{
>> +    char param_name[VIR_TYPED_PARAM_FIELD_LENGTH];
>> +    virDomainResctrlMonDefPtr domresmon = NULL;
>> +    virResctrlMonitorStatsPtr stats = NULL;
>> +    size_t nstats = 0;
> since these are local to the:
>
> +        for (j = 0; j < resctrl->nmonitors; j++) {
>
> loop and there's local's in that for loop, maybe these two should move
> there too...

If the lines with virResctrlMonitorIsRunning could be removed, then this 
loop is
not necessary any more.

virResctrlMonitorIsRunning is validating monitor through verifying PID 
lists, but it
seems there is no need to do such kind of validation and the PIDs in 
*tasks file
will not change without control:
-. The PID in *tasks file will be removed by kernel if vcpu process is 
terminated,
but the vcpu process will not exit except performing vcpu hot-plug.
-. In process of libvirt re-connection, VM will not  make any changes in 
terms of
resctrl groups and vcpus, so the content of *tasks will not change and 
the layout
of resctrl groups will not change.
-. Any changes out of libvirt are not allowed, for example, manually 
creating or
deleting any resctrl groups by bash commands are not allowed.

I decided to remove the lines invoking virResctrlMonitorIsRunning, and 
the loop
will be removed.

Actually I will split this function into three functions:
qemuDomainGetCpuResMonitorData
qemuDomainGetStatsCpuResMonitorPerTag
and
qemuDomainGetStatsCPUResMonitor

qemuDomainGetCpuResMonitorData will fetch data such as the monitor group
ID, vcpus, and cache information for all monitors, any error happened in 
this
function will reported to user through virReportError. So the error will 
be reported
to user before dumping the final result.

qemuDomainGetStatsCpuResMonitorPerTag is responsible for showing the data
retrieved by a successful call of qemuDomainGetCpuResMonitorData. In 
this function
it does not dump any error message created by virReportError which will 
interrupt
the showing of cache monitor information.

qemuDomainGetStatsCPUResMonitor is the interface called by 
qemuDomainGetStatsCPU.
we could invoke qemuDomainGetStatsCpuResMonitorPerTag  with tag
VIR_RESCTRL_MONITOR_TYPE_CACHE for cache monitor.
memBW monitor result will be processed by invoking this function through 
specify
tag VIR_RESCTRL_MONITOR_TYPE_MEMBW.

>> +    virDomainResctrlDefPtr resctrl = NULL;
>> +    unsigned int nmonitors = 0;
>> +    unsigned int imonitor = 0;
>> +    const char *restype = NULL;
>> +    char *rawvcpus = NULL;
>> +    char *vcpus = NULL;
>> +    size_t i = 0;
>> +    size_t j = 0;
>> +    int ret = -1;
>> +
>> +    if (!virDomainObjIsActive(dom))
>> +        return 0;
>> +
>> +    if (restag == VIR_RESCTRL_MONITOR_TYPE_CACHE) {
>> +        restype = "cache";
>> +    } else {
>> +        VIR_DEBUG("Invalid CPU resource type");
> VIR_DEBUG? virReportError would seem to be more appropriate. As I've
> stated before there will be an error for some reason generated.

Originally, the purpose of using VIR_DEBUG,not virReportError, to report 
error
is to avoid showing partial monitor information with an error message on 
screen.

I will split this function into three functions,
qemuDomainGetCpuResMonitorData
qemuDomainGetStatsCpuResMonitorPerTag
and
qemuDomainGetStatsCPUResMonitor

qemuDomainGetCpuResMonitorData will get necessary data and reported
any error occurred to user promptly. 
qemuDomainGetStatsCpuResMonitorPerTag and
qemuDomainGetStatsCPUResMonitor will report the cache monitor result.
This will avoid the mix of cache monitor result and error message if 
error occurs.

Please review my new code.

>> +        return -1;
>> +    }
>> +
>> +    for (i = 0; i < dom->def->nresctrls; i++) {
>> +        resctrl = dom->def->resctrls[i];
>> +
>> +        for (j = 0; j < resctrl->nmonitors; j++) {
>> +            domresmon = resctrl->monitors[j];
>> +            if (virResctrlMonitorIsRunning(domresmon->instance) &&
>> +                domresmon->tag == restag)
> Knowing how heavy wait *IsRunning is, the order of checking should be
> reversed at the very least.

virResctrlMonitorIsRunning will not be called any more as I stated. and 
the code
will be changed, my new code will be more efficient.

>> +                nmonitors++;
>> +        }
>> +    }
>> +
>> +    if (nmonitors) {
>> +        snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
>> +                 "cpu.%s.monitor.count", restype);
>> +        if (virTypedParamsAddUInt(&record->params,
>> +                                  &record->nparams,
>> +                                  maxparams,
>> +                                  param_name,
>> +                                  nmonitors) < 0)
>> +            goto cleanup;
>> +    }
> All that above to ensure nmonitors == resctrl->nmonitors??? I think
> there's a lot of unnecessary stuff.

This part will be removed.

Here the purpose of code is to get the total 'valid' (after a successful 
check
of virResctrlMonitorIsRunning) monitor groups. It actually performing
the validation of  nmonitors == resctrl->nmonitors, just as you said.
Now I think there is no need to validate the monitor any more.

>> +
>> +    for (i = 0; i < dom->def->nresctrls; i++) {
>> +        resctrl = dom->def->resctrls[i];
>> +
>> +        for (j = 0; j < resctrl->nmonitors; j++) {
>> +            size_t l = 0;
>> +            virResctrlMonitorPtr monitor = resctrl->monitors[j]->instance;
>> +            const char *id = virResctrlMonitorGetID(monitor);
>> +
>> +            if (!id)
>> +                goto cleanup;
> I would think you have other problems in this case. Besides there's no
> error message associated with this.

Error message should be reported. And will be reported. Please review 
the new code.

>> +
>> +            domresmon = resctrl->monitors[j];
>> +
>> +            if (!virResctrlMonitorIsRunning(domresmon->instance))
>> +                continue;
> Oh my one call for each iteration, ouch - highly inefficient.

virResctrlMonitorIsRunning disappears in code and patch for this file
will be redesigned. Please renew the new code.


>> +
>> +            if (!(rawvcpus = virBitmapFormat(domresmon->vcpus)))
>> +                goto cleanup;
>> +
>> +            vcpus = qemuDomainVcpuFormatHelper(rawvcpus);
>> +            if (!vcpus)
>> +                goto cleanup;
>> +
>> +            if (virResctrlMonitorGetCacheOccupancy(monitor, &stats,
>> +                                                   &nstats) < 0)
>> +                goto cleanup;
>> +
>> +            snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
>> +                     "cpu.%s.monitor.%d.name", restype, imonitor);
>> +            if (virTypedParamsAddString(&record->params,
>> +                                        &record->nparams,
>> +                                        maxparams,
>> +                                        param_name,
>> +                                        id) < 0)
>> +                goto cleanup;
>> +
>> +            snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
>> +                     "cpu.%s.monitor.%d.vcpus", restype, imonitor);
>> +
>> +            if (virTypedParamsAddString(&record->params,
>> +                                        &record->nparams,
>> +                                        maxparams,
>> +                                        param_name,
>> +                                        vcpus) < 0)
>> +                goto cleanup;
>> +
>> +            snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
>> +                     "cpu.%s.monitor.%d.bank.count", restype, imonitor);
>> +            if (virTypedParamsAddUInt(&record->params,
>> +                                      &record->nparams,
>> +                                      maxparams,
>> +                                      param_name,
>> +                                      nstats) < 0)
>> +                goto cleanup;
>> +
>> +            for (l = 0; l < nstats; l++) {
>> +                snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
>> +                         "cpu.%s.monitor.%d.bank.%ld.id",
>> +                         restype, imonitor, l);
>> +                if (virTypedParamsAddUInt(&record->params,
>> +                                          &record->nparams,
>> +                                          maxparams,
>> +                                          param_name,
>> +                                          stats[l].id) < 0)
>> +                    goto cleanup;
>> +
>> +
>> +                snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
>> +                         "cpu.%s.monitor.%d.bank.%ld.bytes",
>> +                         restype, imonitor, l);
>> +                if (virTypedParamsAddUInt(&record->params,
>> +                                          &record->nparams,
>> +                                          maxparams,
>> +                                          param_name,
>> +                                          stats[l].val) < 0)
>> +                    goto cleanup;
>> +            }
>> +
>> +            VIR_FREE(stats);
>                 nstats = 0;
If virResctrlMonitorGetCacheOccupancy returns without error, nstats will 
be assigned with
the proper bank group number. If virResctrlMonitorGetCacheOccupancy 
returns an error,
then code will go through cleanup path and returns.
Seems no need to clear nstats to 0.

Any way in my new code, this nstats will not be used any more, please 
review the logic of
new code later.

> too!
>
>> +            VIR_FREE(vcpus);
>> +            imonitor++;
>> +        }
>> +    }
>> +
>> +    ret = 0;
>> + cleanup:
>> +    VIR_FREE(vcpus);
>> +    return ret;
>> +}
>> +
>> +
>>   static int
>>   qemuDomainGetStatsCpu(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
>>                         virDomainObjPtr dom,
>> @@ -19735,6 +19960,10 @@ qemuDomainGetStatsCpu(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
>>               return -1;
>>       }
>>   
>> +    if (qemuDomainGetStatsCpuResource(driver, dom, record, maxparams, privflags,
>> +                                      VIR_RESCTRL_MONITOR_TYPE_CACHE) < 0)
>> +        return -1;
>> +
>>       return 0;
>>   }
>>   
>> diff --git a/src/util/virresctrl.c b/src/util/virresctrl.c
>> index fa3e6e9..02e7095 100644
>> --- a/src/util/virresctrl.c
>> +++ b/src/util/virresctrl.c
>> @@ -2713,3 +2713,133 @@ virResctrlMonitorIsRunning(virResctrlMonitorPtr monitor)
>>   
>>       return ret;
>>   }
>> +
>> +
>> +static int
>> +virResctrlMonitorStatsSorter(const void *a,
>> +                             const void *b)
>> +{
>> +    return ((virResctrlMonitorStatsPtr)a)->id
>> +        - ((virResctrlMonitorStatsPtr)b)->id;
>> +}
>> +
>> +
>> +/*
>> + * virResctrlMonitorGetStats
>> + *
>> + * @monitor: The monitor that the statistic data will be retrieved from.
>> + * @resource: The name for resource name. 'llc_occupancy' for cache resource.
>> + * "mbm_total_bytes" and "mbm_local_bytes" for memory bandwidth resource.
>> + * @stats: Array of virResctrlMonitorStatsPtr for holding cache or memory
>> + * bandwidth usage data.
>> + * @nstats: A size_t pointer to hold the returned array length of @stats
>> + *
>> + * Get cache or memory bandwidth utilization information.
>> + *
>> + * Returns 0 on success, -1 on error.
>> + */
>> +static int
>> +virResctrlMonitorGetStats(virResctrlMonitorPtr monitor,
>> +                          const char *resource,
>> +                          virResctrlMonitorStatsPtr *stats,
>> +                          size_t *nstats)
>> +{
>> +    int rv = -1;
>> +    int ret = -1;
>> +    DIR *dirp = NULL;
>> +    char *datapath = NULL;
>> +    struct dirent *ent = NULL;
>> +    virResctrlMonitorStatsPtr stat = NULL;
>> +
>> +    if (!monitor) {
>> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>> +                       _("Invalid resctrl monitor"));
>> +        return -1;
>> +    }
>> +
>> +    if (virAsprintf(&datapath, "%s/mon_data", monitor->path) < 0)
>> +        return -1;
>> +
>> +    if (virDirOpen(&dirp, datapath) < 0)
>> +        goto cleanup;
>> +
>> +    *nstats = 0;
>> +    while (virDirRead(dirp, &ent, datapath) > 0) {
>> +        char *node_id = NULL;
>> +
>> +        if (VIR_ALLOC(stat) < 0)
>> +            goto cleanup;
>> +
>> +        /* Looking for directory that contains resource utilization
>> +         * information file. The directory name is arranged in format
>> +         * "mon_<node_name>_<node_id>". For example, "mon_L3_00" and
>> +         * "mon_L3_01" are two target directories for a two nodes system
>> +         * with resource utilization data file for each node respectively.
>> +         */
>> +        if (ent->d_type != DT_DIR)
>> +            continue;
>> +
>> +        /* Looking for directory has a prefix 'mon_L' */
>> +        if (!(node_id = STRSKIP(ent->d_name, "mon_L")))
>> +            continue;
>> +
>> +        /* Looking for directory has another '_' */
>> +        node_id = strchr(node_id, '_');
>> +        if (!node_id)
>> +            continue;
>> +
>> +        /* Skip the character '_' */
>> +        if (!(node_id = STRSKIP(node_id, "_")))
>> +            continue;
>> +
>> +        /* The node ID number should be here, parsing it. */
>> +        if (virStrToLong_uip(node_id, NULL, 0, &stat->id) < 0)
>> +            goto cleanup;
>> +
>> +        rv = virFileReadValueUint(&stat->val, "%s/%s/%s", datapath,
>> +                                  ent->d_name, resource);
>> +        if (rv == -2) {
>> +            virReportError(VIR_ERR_INTERNAL_ERROR,
>> +                           _("File '%s/%s/%s' does not exist."),
>> +                           datapath, ent->d_name, resource);
>> +        }
>> +        if (rv < 0)
>> +            goto cleanup;
>> +
>> +        if (VIR_APPEND_ELEMENT(*stats, *nstats, *stat) < 0)
>> +            goto cleanup;
>> +    }
>> +
>> +    /* Sort in id's ascending order */
>> +    qsort(*stats, *nstats, sizeof(*stat), virResctrlMonitorStatsSorter);
> Coverity notes that *stats could be NULL - if the above while loop gets
> nothing...

Will be changed to
if (*nstats)
     qsort(*stats, *nstats, sizeof(*stat), virResctrlMonitorStatsSorter);

>> +
>> +    ret = 0;
>> + cleanup:
>> +    VIR_FREE(datapath);
>> +    VIR_FREE(stat);
>> +    VIR_DIR_CLOSE(dirp);
>> +    return ret;
>> +}
>> +
>> +
>> +/*
>> + * virResctrlMonitorGetCacheOccupancy
>> + *
>> + * @monitor: The monitor that the statistic data will be retrieved from.
>> + * @caches: Array of virResctrlMonitorStatsPtr for receiving cache occupancy
>> + * data. Caller is responsible to free this array.
>> + * @ncaches: A size_t pointer to hold the returned array length of @caches
> They're @stats and @nstats elsewhere, be consistent.

Will use @stats and @nstats for virResctrlMonitorGetCacheOccupancy and later
API (for memBW).

>> + *
>> + * Get cache or memory bandwidth utilization information.
>> + *
>> + * Returns 0 on success, -1 on error.
>> + */
>> +
>> +int
>> +virResctrlMonitorGetCacheOccupancy(virResctrlMonitorPtr monitor,
>> +                                   virResctrlMonitorStatsPtr *caches,
>> +                                   size_t *ncaches)
> They're @stats and @nstats elsewhere, be consistent.

Will use @stats and @nstats for parameters.

>> +{
>> +    return virResctrlMonitorGetStats(monitor, "llc_occupancy",
>> +                                     caches, ncaches);
>> +}
>> diff --git a/src/util/virresctrl.h b/src/util/virresctrl.h
>> index 8d8fdc2..004c40e 100644
>> --- a/src/util/virresctrl.h
>> +++ b/src/util/virresctrl.h
>> @@ -191,6 +191,13 @@ virResctrlInfoGetMonitorPrefix(virResctrlInfoPtr resctrl,
>>   typedef struct _virResctrlMonitor virResctrlMonitor;
>>   typedef virResctrlMonitor *virResctrlMonitorPtr;
>>   
>> +typedef struct _virResctrlMonitorStats virResctrlMonitorStats;
>> +typedef virResctrlMonitorStats *virResctrlMonitorStatsPtr;
>> +struct _virResctrlMonitorStats {
>> +    unsigned int id;
>> +    unsigned int val;
>> +};
>> +
>>   virResctrlMonitorPtr
>>   virResctrlMonitorNew(void);
>>   
>> @@ -222,4 +229,9 @@ virResctrlMonitorRemove(virResctrlMonitorPtr monitor);
>>   
>>   bool
>>   virResctrlMonitorIsRunning(virResctrlMonitorPtr monitor);
>> +
>> +int
>> +virResctrlMonitorGetCacheOccupancy(virResctrlMonitorPtr monitor,
>> +                                   virResctrlMonitorStatsPtr *caches,
>> +                                   size_t *ncaches);
> They're @stats and @nstats elsewhere, be consistent.

Will use @stats and @nstats for parameters.

>>   #endif /*  __VIR_RESCTRL_H__ */
>>
> I'm sure there's more I'll pick up later, but you should have plenty for
> now. As to splitting - I think some splitting could be done, I'll leave
> it up to you... Lots of change across multiple areas - ask yourself -
> can something be separated out?

The virresctrl.* part could be separated, and how about  merging this 
part with previous patch
that adding more monitor interfaces in virresctrl.*.
I'll do this in my next update for your review.

> John
>

Thanks for review.
Huaqiang
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20181112/9c26dd6b/attachment-0001.htm>


More information about the libvir-list mailing list