[libvirt] [PATCH v2 3/3] vz: add memory statistics

Nikolay Shirokovskiy nshirokovskiy at parallels.com
Fri Jun 26 08:22:14 UTC 2015



On 25.06.2015 20:36, Dmitry Guryanov wrote:
> On 06/18/2015 12:28 PM, Nikolay Shirokovskiy wrote:
>> From: Nikolay Shirokovskiy <nshirokovskiy at parallels.com>
>>
>> Implemented counters:
>>   VIR_DOMAIN_MEMORY_STAT_SWAP_IN
>>   VIR_DOMAIN_MEMORY_STAT_SWAP_OUT
>>   VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT
>>   VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT
>>   VIR_DOMAIN_MEMORY_STAT_AVAILABLE
>>   VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON
>>   VIR_DOMAIN_MEMORY_STAT_UNUSED
>>
>> Comments.
>>
>> 1. Use vzDomObjFromDomainRef/virDomainObjEndAPI pair to get domain
>> object as we use prlsdkGetStatsParam. See previous statistics
>> comments.
>>
>> 2. Balloon statistics is not applicable to containers. Fault
>> statistics for containers not provided in PCS6 yet.
> 
> At some reason it returns -1 for all counters on my server, need to check, why is it...
You need an recent build of PCS6 update10 and update guest tools for VMs too.
> 
>> Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy at virtuozzo.com>
>> ---
>>   src/vz/vz_driver.c |   73 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>>   1 files changed, 73 insertions(+), 0 deletions(-)
>>
>> diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c
>> index 4197569..8dae7c4 100644
>> --- a/src/vz/vz_driver.c
>> +++ b/src/vz/vz_driver.c
>> @@ -1377,6 +1377,78 @@ vzDomainInterfaceStats(virDomainPtr domain,
>>       return ret;
>>   }
>>   +static int
>> +vzDomainMemoryStats(virDomainPtr domain,
>> +                      virDomainMemoryStatPtr stats,
>> +                      unsigned int nr_stats,
>> +                      unsigned int flags)
>> +{
>> +    virDomainObjPtr dom = NULL;
>> +    int ret = -1;
>> +    long long v = 0, t = 0, u = 0;
>> +    size_t i = 0;
>> +
>> +    virCheckFlags(0, -1);
>> +    if (!(dom = vzDomObjFromDomainRef(domain)))
>> +        return -1;
>> +
>> +#define PARALLELS_GET_COUNTER(NAME, VALUE)                          \
>> +    if (prlsdkGetStatsParam(dom, NAME, &VALUE) < 0)                 \
>> +        goto cleanup;                                               \
>> +
>> +#define PARALLELS_MEMORY_STAT_SET(TAG, VALUE)                       \
>> +    if (i < nr_stats) {                                             \
>> +        stats[i].tag = (TAG);                                       \
>> +        stats[i].val = (VALUE);                                     \
>> +        i++;                                                        \
>> +    }
>> +
>> +#define PARALLELS_COUNTER_PROTECT(VALUE) VALUE == -1 : ?
>> +
>> +    i = 0;
>> +
>> +    // count to kb
>> +    PARALLELS_GET_COUNTER("guest.ram.swap_in", v)
>> +    if (v != -1)
>> +        PARALLELS_MEMORY_STAT_SET(VIR_DOMAIN_MEMORY_STAT_SWAP_IN, v << 12)
>> +
>> +    PARALLELS_GET_COUNTER("guest.ram.swap_out", v)
>> +    if (v != -1)
>> +        PARALLELS_MEMORY_STAT_SET(VIR_DOMAIN_MEMORY_STAT_SWAP_OUT, v << 12)
>> +
>> +    PARALLELS_GET_COUNTER("guest.ram.minor_fault", v)
>> +    if (v != -1)
>> +        PARALLELS_MEMORY_STAT_SET(VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT, v)
>> +
>> +    PARALLELS_GET_COUNTER("guest.ram.major_fault", v)
>> +    if (v != -1)
>> +        PARALLELS_MEMORY_STAT_SET(VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT, v)
> 
> To be honest, I don't think macros here improve code readability, look, how it would be without them:
> 
> if (prlsdkGetStatsParam(dom, "guest.ram.major_fault", &v) < 0)
>     goto cleanup;
> 
> if (v != -1 && i < nr_stats) {
>     stats[i].tag = VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT;
>     stats[i].val = v;
>     i++;
> }
> 
> 
> Only "goto cleanup" and "i++" are repeating information.
> 

But with macros it is easy to see actual structure:
1. you get some counter
2. check if it is present (!= -1) 
3. save to libvirt structure optionally converting to different units

Without conversion this could be just 1 line. May be introduce conversion macros.

Then we could get just:

PARALLELS_GET_COUNTER("guest.ram.swap_out", VIR_DOMAIN_MEMORY_STAT_SWAP_OUT, BYTES_TO_PAGES)
PARALLELS_GET_COUNTER("guest.ram.minor_fault", VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT, NO_CONVERSION)

Without macros it is entangled with counters vector capacity checks( i < nr_stats),
incrementing counters. It looks like low-level but there is no wish to
factor it out to type.

>> +
>> +    PARALLELS_GET_COUNTER("guest.ram.total", v)
>> +    if (v != -1)
>> +        PARALLELS_MEMORY_STAT_SET(VIR_DOMAIN_MEMORY_STAT_AVAILABLE, v << 10)
>> +
>> +    PARALLELS_GET_COUNTER("guest.ram.balloon_actual", v)
>> +    if (v != -1)
>> +        PARALLELS_MEMORY_STAT_SET(VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON, v << 10)
>> +
>> +    PARALLELS_GET_COUNTER("guest.ram.usage", u)
>> +    PARALLELS_GET_COUNTER("guest.ram.total", t)
>> +    if (u != -1 && t != -1)
>> +        PARALLELS_MEMORY_STAT_SET(VIR_DOMAIN_MEMORY_STAT_UNUSED, (t - u) << 10)
>> +
>> +
>> +#undef PARALLELS_GET_COUNTER
>> +#undef PARALLELS_MEMORY_STAT_SET
>> +
>> +    ret = i;
>> + cleanup:
>> +    if (dom)
>> +        virDomainObjEndAPI(&dom);
>> +
>> +    return ret;
>> +}
>> +
>>   static virHypervisorDriver vzDriver = {
>>       .name = "vz",
>>       .connectOpen = vzConnectOpen,            /* 0.10.0 */
>> @@ -1429,6 +1501,7 @@ static virHypervisorDriver vzDriver = {
>>       .domainBlockStats = vzDomainBlockStats, /* 1.3.0 */
>>       .domainBlockStatsFlags = vzDomainBlockStatsFlags, /* 1.3.0 */
>>       .domainInterfaceStats = vzDomainInterfaceStats, /* 1.3.0 */
>> +    .domainMemoryStats = vzDomainMemoryStats, /* 1.3.0 */
>>   };
>>     static virConnectDriver vzConnectDriver = {
> 
> 




More information about the libvir-list mailing list