[libvirt] [PATCH] parallels: add block device statistics to driver

Nikolay Shirokovskiy nshirokovskiy at parallels.com
Thu Jun 4 09:29:41 UTC 2015



On 03.06.2015 15:16, Dmitry Guryanov wrote:
> On 05/22/2015 10:42 AM, Nikolay Shirokovskiy wrote:
>> Statistics provided through PCS SDK. As we have only async interface in SDK we
>> need to be subscribed to statistics in order to get it. Trivial solution on
>> every stat request to subscribe, wait event and then unsubscribe will lead to
>> significant delays in case of a number of successive requests, as the event
>> will be delivered on next PCS server notify cycle. On the other hand we don't
>> want to keep unnesessary subscribtion. So we take an hibrid solution to
>> subcsribe on first request and then keep a subscription while requests are
>> active. We populate cache of statistics on subscribtion events and use this
>> cache to serve libvirts requests.
>>
>> Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy at parallels.com>
>> ---
>>   src/parallels/parallels_driver.c |  106 +++++++++++++++++++++
>>   src/parallels/parallels_sdk.c    |  193 ++++++++++++++++++++++++++++++++------
>>   src/parallels/parallels_sdk.h    |    2 +
>>   src/parallels/parallels_utils.h  |   15 +++
>>   4 files changed, 285 insertions(+), 31 deletions(-)
>>

>> +parallelsDomainBlockStats(virDomainPtr domain, const char *path,
>> +                     virDomainBlockStatsPtr stats)
>> +{
>> +    virDomainObjPtr dom = NULL;
>> +    int ret = -1;
>> +    size_t i;
>> +    int idx;
>> +
>> +    if (!(dom = parallelsDomObjFromDomain(domain)))
>> +        return -1;
>> +
>> +    if (*path) {
>> +        if ((idx = virDomainDiskIndexByName(dom->def, path, false)) < 0) {
>> +            virReportError(VIR_ERR_INVALID_ARG, _("invalid path: %s"), path);
>> +            goto cleanup;
>> +        }
>> +        if (prlsdkGetBlockStats(dom, dom->def->disks[idx], stats) < 0)
>> +            goto cleanup;
>> +    } else {
>> +        virDomainBlockStatsStruct s;
>> +
>> +#define PARALLELS_ZERO_STATS(VAR, TYPE, NAME)           \
>> +        stats->VAR = 0;
>> +
>> +        PARALLELS_BLOCK_STATS_FOREACH(PARALLELS_ZERO_STATS)
>> +
>> +#undef PARALLELS_ZERO_STATS
>> +
> 
> Why don't you use memset here?
to make code uniform. I use PARALLELS_BLOCK_STATS_FOREACH macro to
iterate on all disk stats PCS supports in different places, here
i use this macro make initialization somewhat *explicit* instead of
*implicit* memset.

> 

>> +
>>   static virHypervisorDriver parallelsDriver = {
>>       .name = "Parallels",
>>       .connectOpen = parallelsConnectOpen,            /* 0.10.0 */
>> @@ -1228,6 +1332,8 @@ static virHypervisorDriver parallelsDriver = {
>>       .domainManagedSave = parallelsDomainManagedSave, /* 1.2.14 */
>>       .domainManagedSaveRemove = parallelsDomainManagedSaveRemove, /* 1.2.14 */
>>       .domainGetMaxMemory = parallelsDomainGetMaxMemory, /* 1.2.15 */
>> +    .domainBlockStats = parallelsDomainBlockStats, /* 1.2.16 */
>> +    .domainBlockStatsFlags = parallelsDomainBlockStatsFlags, /* 1.2.16 */
> 
> Could you, please, update there versions to 1.2.17?
>>   };

ok
>>     static virConnectDriver parallelsConnectDriver = {
>> diff --git a/src/parallels/parallels_sdk.c b/src/parallels/parallels_sdk.c
>> index 88ad59b..eb8d965 100644
>> --- a/src/parallels/parallels_sdk.c
>> +++ b/src/parallels/parallels_sdk.c
>> @@ -21,6 +21,7 @@
>>    */
> 
> ....
>> +        goto cleanup;
>> +
>>       switch (prlEventType) {
>>           case PET_DSP_EVT_VM_STATE_CHANGED:
>> +            prlsdkHandleVmStateEvent(privconn, prlEvent, uuid);
>> +            break;
>>           case PET_DSP_EVT_VM_CONFIG_CHANGED:
>> +            prlsdkHandleVmConfigEvent(privconn, uuid);
>> +            break;
>>           case PET_DSP_EVT_VM_CREATED:
>>           case PET_DSP_EVT_VM_ADDED:
>> +            prlsdkHandleVmAddedEvent(privconn, uuid);
>> +            break;
>>           case PET_DSP_EVT_VM_DELETED:
>>           case PET_DSP_EVT_VM_UNREGISTERED:
>> -            pret = prlsdkHandleVmEvent(privconn, prlEvent);
>> +            prlsdkHandleVmRemovedEvent(privconn, uuid);
>> +            break;
>> +        case PET_DSP_EVT_VM_PERFSTATS:
>> +            prlsdkHandlePerfEvent(privconn, prlEvent, uuid);
>> +            // above function takes own of event
>> +            prlEvent = PRL_INVALID_HANDLE;
>>               break;
>>           default:
>>               VIR_DEBUG("Skipping event of type %d", prlEventType);
>> @@ -3455,3 +3481,108 @@ prlsdkDomainManagedSaveRemove(virDomainObjPtr dom)
>>         return 0;
>>   }
>> +
> 
> Could you describe the idea with stats cache in more detail? Why do you keer up to 3 prlsdk stats, but use only one? And where do you free these handles?
> 
ok, this will go to commit message
Shortly.

1. 3 - this is implicit timeout to drop cache. Explicit is is 3 * PCS_INTERVAL_BETWEEN_STAT_EVENTS. If
nobody asks for statistics for this time interval we unsubscribe and make cache invalid, so if somebody
will want statistics again we will need to subsciribe again and wait for first event to arrive to proceed.

2. Event handle is freed when next event arrived.



>> +int
>> +prlsdkGetBlockStats(virDomainObjPtr dom, virDomainDiskDefPtr disk, virDomainBlockStatsPtr stats)
>> +{
>> +    virDomainDeviceDriveAddressPtr address;
>> +    int idx;
>> +    const char *prefix;
>> +    int ret = -1;
>> +    char *name = NULL;
>> +
>> +    address = &disk->info.addr.drive;
>> +    switch (disk->bus) {
>> +    case VIR_DOMAIN_DISK_BUS_IDE:
>> +        prefix = "ide";
>> +        idx = address->bus * 2 + address->unit;
>> +        break;
>> +    case VIR_DOMAIN_DISK_BUS_SATA:
>> +        prefix = "sata";
>> +        idx = address->unit;
>> +        break;
>> +    case VIR_DOMAIN_DISK_BUS_SCSI:
>> +        prefix = "scsi";
>> +        idx = address->unit;
>> +        break;
>> +    default:
>> +        virReportError(VIR_ERR_INTERNAL_ERROR,
>> +                   _("Unknown disk bus: %X"), disk->bus);
>> +        goto cleanup;
>> +    }
>> +
> 
> I think this won't work if the domain has disks on different buses.
> 
No, it's correct as i use prefix also.
> 

Meanwhile I discover next failures in this patch that will be fixed in next version.
1. This patch includes refactorings for eventHandle function that should be done in other way.
2. We don't keep reference to domain while waiting for event so we could get wild pointer after wait finishes.
3. We don't have a timeout on waiting for event.

All will be fixed in next version.




More information about the libvir-list mailing list