On 11/18/2015 10:03 PM, Jim Fehlig wrote: > On 11/13/2015 06:14 AM, Joao Martins wrote: >> Introduce support for connectGetAllDomainStats call that >> allow us to _all_ domain(s) statistics including network, block, > > allows us to get > >> cpus and memory. Changes are rather mechanical and mostly >> take care of the format to export the data. >> >> Signed-off-by: Joao Martins <joao.m.martins@xxxxxxxxxx> >> --- >> Changes since v1: >> - Rework flags checking on libxlDomainGetStats >> for VIR_DOMAIN_STATS_{VCPU,INTERFACE,BLOCK} >> - Removed path since we are reusing <virDomainNetDef>.ifname >> - Init dominfo and dispose it on cleanup. >> - Fixed VIR_FREE issue that was reported with make syntax-check" >> - Bump version to 1.2.22 >> --- >> src/libxl/libxl_driver.c | 266 +++++++++++++++++++++++++++++++++++++++++++++++ >> 1 file changed, 266 insertions(+) >> >> diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c >> index ba1d67b..8db6536 100644 >> --- a/src/libxl/libxl_driver.c >> +++ b/src/libxl/libxl_driver.c >> @@ -5238,6 +5238,271 @@ libxlDomainMemoryStats(virDomainPtr dom, >> >> #undef LIBXL_SET_MEMSTAT >> >> +#define LIBXL_RECORD_UINT(error, key, value, ...) \ >> +do { \ >> + char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \ >> + snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, \ >> + key, ##__VA_ARGS__); \ >> + if (virTypedParamsAddUInt(&tmp->params, \ >> + &tmp->nparams, \ >> + &maxparams, \ >> + param_name, \ >> + value) < 0) \ >> + goto error; \ >> +} while (0) >> + >> +#define LIBXL_RECORD_LL(error, key, value, ...) \ >> +do { \ >> + char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \ >> + snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, \ >> + key, ##__VA_ARGS__); \ >> + if (virTypedParamsAddLLong(&tmp->params, \ >> + &tmp->nparams, \ >> + &maxparams, \ >> + param_name, \ >> + value) < 0) \ >> + goto error; \ >> +} while (0) >> + >> +#define LIBXL_RECORD_ULL(error, key, value, ...) \ >> +do { \ >> + char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \ >> + snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, \ >> + key, ##__VA_ARGS__); \ >> + if (virTypedParamsAddULLong(&tmp->params, \ >> + &tmp->nparams, \ >> + &maxparams, \ >> + param_name, \ >> + value) < 0) \ >> + goto error; \ >> +} while (0) >> + >> +#define LIBXL_RECORD_STR(error, key, value, ...) \ >> +do { \ >> + char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \ >> + snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, \ >> + key, ##__VA_ARGS__); \ >> + if (virTypedParamsAddString(&tmp->params, \ >> + &tmp->nparams, \ >> + &maxparams, \ >> + param_name, \ >> + value) < 0) \ >> + goto error; \ >> +} while (0) >> + >> +static int >> +libxlDomainGetStats(virConnectPtr conn, >> + virDomainObjPtr dom, >> + unsigned int stats, >> + virDomainStatsRecordPtr *record) >> +{ >> + libxlDriverPrivatePtr driver = conn->privateData; >> + libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver); > > cfg needs to be unref'ed when this function terminates. Sadly I noticed this > only after pushing some of the other patches with a similar flaw. > OK, will fix that. I saw and tested your fix series, and it appears both of them are Acked already. >> + virDomainStatsRecordPtr tmp; >> + libxl_dominfo d_info; >> + libxl_vcpuinfo *vcpuinfo = NULL; >> + int maxcpu, hostcpus; >> + unsigned long long mem, maxmem; >> + int maxparams = 0; >> + int ret = -1; >> + size_t i, state; >> + unsigned int domflags = stats & (VIR_DOMAIN_STATS_BALLOON | >> + VIR_DOMAIN_STATS_CPU_TOTAL); >> + >> + if (VIR_ALLOC(tmp) < 0) >> + return ret; >> + >> + libxl_dominfo_init(&d_info); >> + >> + mem = virDomainDefGetMemoryInitial(dom->def); >> + maxmem = virDomainDefGetMemoryActual(dom->def); >> + d_info.cpu_time = 0; >> + >> + if (domflags && virDomainObjIsActive(dom) && >> + !libxl_domain_info(cfg->ctx, &d_info, dom->def->id)) { >> + mem = d_info.current_memkb; >> + maxmem = d_info.max_memkb; >> + } >> + >> + if (stats & VIR_DOMAIN_STATS_STATE) { >> + LIBXL_RECORD_UINT(cleanup, "state.reason", dom->state.reason); >> + LIBXL_RECORD_UINT(cleanup, "state.state", dom->state.state); >> + } >> + >> + if (stats & VIR_DOMAIN_STATS_BALLOON) { >> + LIBXL_RECORD_ULL(cleanup, "balloon.current", mem); >> + LIBXL_RECORD_ULL(cleanup, "balloon.maximum", maxmem); >> + } >> + >> + if (stats & VIR_DOMAIN_STATS_CPU_TOTAL) >> + LIBXL_RECORD_ULL(cleanup, "cpu.time", d_info.cpu_time); >> + >> + if (stats & VIR_DOMAIN_STATS_VCPU) { >> + vcpuinfo = libxl_list_vcpu(cfg->ctx, dom->def->id, &maxcpu, &hostcpus); >> + >> + for (i = 0; i < dom->def->vcpus; i++) { >> + if (!vcpuinfo) >> + state = VIR_VCPU_OFFLINE; >> + else if (vcpuinfo[i].running) >> + state = VIR_VCPU_RUNNING; >> + else if (vcpuinfo[i].blocked) >> + state = VIR_VCPU_BLOCKED; >> + else >> + state = VIR_VCPU_OFFLINE; >> + >> + LIBXL_RECORD_UINT(cleanup_vcpu, "vcpu.%zu.state", state, i); >> + >> + /* vcputime is shown only if the VM is active */ >> + if (!virDomainObjIsActive(dom)) >> + continue; >> + >> + LIBXL_RECORD_ULL(cleanup_vcpu, "vcpu.%zu.time", vcpuinfo[i].vcpu_time, i); >> + } >> + >> + if (vcpuinfo) >> + libxl_vcpuinfo_list_free(vcpuinfo, maxcpu); >> + } >> + >> + if (stats & VIR_DOMAIN_STATS_INTERFACE) { >> + for (i = 0; i < dom->def->nnets; i++) { >> + virDomainNetDefPtr net = dom->def->nets[i]; >> + struct _virDomainInterfaceStats netstats; >> + >> + if (!virDomainObjIsActive(dom) || !net->ifname) >> + continue; >> + >> + if ((ret = virNetInterfaceStats(net->ifname, &netstats)) < 0) >> + continue; >> + >> + LIBXL_RECORD_ULL(cleanup, "net.%zu.rx.bytes", netstats.rx_bytes, i); >> + LIBXL_RECORD_ULL(cleanup, "net.%zu.rx.pkts", netstats.rx_packets, i); >> + LIBXL_RECORD_ULL(cleanup, "net.%zu.rx.drop", netstats.rx_drop, i); >> + LIBXL_RECORD_ULL(cleanup, "net.%zu.rx.errs", netstats.rx_errs, i); >> + LIBXL_RECORD_ULL(cleanup, "net.%zu.tx.bytes", netstats.tx_bytes, i); >> + LIBXL_RECORD_ULL(cleanup, "net.%zu.tx.pkts", netstats.tx_packets, i); >> + LIBXL_RECORD_ULL(cleanup, "net.%zu.tx.drop", netstats.tx_drop, i); >> + LIBXL_RECORD_ULL(cleanup, "net.%zu.tx.errs", netstats.tx_errs, i); >> + LIBXL_RECORD_STR(cleanup, "net.%zu.name", net->ifname, i); >> + } >> + >> + LIBXL_RECORD_UINT(cleanup, "net.count", dom->def->nnets); >> + } >> + >> + if (stats & VIR_DOMAIN_STATS_BLOCK) { >> + for (i = 0; i < dom->def->ndisks; i++) { >> + virDomainDiskDefPtr disk = dom->def->disks[i]; >> + struct _libxlBlockStats blkstats; >> + >> + if (!virDomainObjIsActive(dom)) >> + continue; >> + >> + memset(&blkstats, 0, sizeof(libxlBlockStats)); >> + if ((ret = libxlDomainBlockStatsGather(dom, disk->dst, &blkstats)) < 0) >> + continue; >> + >> + LIBXL_RECORD_LL(cleanup, "block.%zu.rd.reqs", blkstats.rd_req, i); >> + LIBXL_RECORD_LL(cleanup, "block.%zu.rd.bytes", blkstats.rd_bytes, i); >> + LIBXL_RECORD_LL(cleanup, "block.%zu.wr.reqs", blkstats.wr_req, i); >> + LIBXL_RECORD_LL(cleanup, "block.%zu.wr.bytes", blkstats.wr_bytes, i); >> + LIBXL_RECORD_LL(cleanup, "block.%zu.fl.reqs", blkstats.f_req, i); >> + >> + if (STREQ_NULLABLE(blkstats.backend, "vbd")) { >> + LIBXL_RECORD_LL(cleanup, "block.%zu.discard.reqs", blkstats.u.vbd.ds_req, i); >> + LIBXL_RECORD_LL(cleanup, "block.%zu.errs", blkstats.u.vbd.oo_req, i); >> + } >> + LIBXL_RECORD_STR(cleanup, "block.%zu.name", disk->dst, i); >> + LIBXL_RECORD_STR(cleanup, "block.%zu.path", disk->src->path, i); >> + } >> + >> + LIBXL_RECORD_UINT(cleanup, "block.count", dom->def->ndisks); >> + } >> + >> + if (!(tmp->dom = virGetDomain(conn, dom->def->name, dom->def->uuid))) >> + goto cleanup; >> + >> + *record = tmp; > > tmp = NULL; > ret = 0; > > then fall-though to cleanup? Otherwise looks like there are some leaks. > Ah, yes. Will need to do this too: if (tmp) virTypedParamsFree(tmp->params, tmp->nparams); And perhaps set vcpuinfo to NULL on (stats & VIR_DOMAIN_STATS_VCPU) after libxl_vcpuinfo_list_free() gets called so that I can just remove the "return 0" there. That way return path is clear and also with no leaks. Thanks! Joao > Regards, > Jim > >> + return 0; >> + >> + cleanup_vcpu: >> + if (vcpuinfo) >> + libxl_vcpuinfo_list_free(vcpuinfo, maxcpu); >> + cleanup: >> + libxl_dominfo_dispose(&d_info); >> + virTypedParamsFree(tmp->params, tmp->nparams); >> + VIR_FREE(tmp); >> + return ret; >> +} >> + >> +static int >> +libxlConnectGetAllDomainStats(virConnectPtr conn, >> + virDomainPtr *doms, >> + unsigned int ndoms, >> + unsigned int stats, >> + virDomainStatsRecordPtr **retStats, >> + unsigned int flags) >> +{ >> + libxlDriverPrivatePtr driver = conn->privateData; >> + virDomainObjPtr *vms = NULL; >> + virDomainObjPtr vm; >> + size_t nvms; >> + virDomainStatsRecordPtr *tmpstats = NULL; >> + int nstats = 0; >> + size_t i; >> + int ret = -1; >> + unsigned int lflags = flags & (VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE | >> + VIR_CONNECT_LIST_DOMAINS_FILTERS_PERSISTENT | >> + VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE); >> + >> + virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE | >> + VIR_CONNECT_LIST_DOMAINS_FILTERS_PERSISTENT | >> + VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE, -1); >> + >> + if (virConnectGetAllDomainStatsEnsureACL(conn) < 0) >> + return -1; >> + >> + if (ndoms) { >> + if (virDomainObjListConvert(driver->domains, conn, doms, ndoms, &vms, >> + &nvms, virConnectGetAllDomainStatsCheckACL, >> + lflags, true) < 0) >> + return -1; >> + } else { >> + if (virDomainObjListCollect(driver->domains, conn, &vms, &nvms, >> + virConnectGetAllDomainStatsCheckACL, >> + lflags) < 0) >> + return -1; >> + } >> + >> + if (VIR_ALLOC_N(tmpstats, nvms + 1) < 0) >> + return -1; >> + >> + for (i = 0; i < nvms; i++) { >> + virDomainStatsRecordPtr tmp = NULL; >> + vm = vms[i]; >> + >> + virObjectLock(vm); >> + >> + if (libxlDomainGetStats(conn, vm, stats, &tmp) < 0) { >> + virObjectUnlock(vm); >> + goto cleanup; >> + } >> + >> + if (tmp) >> + tmpstats[nstats++] = tmp; >> + >> + virObjectUnlock(vm); >> + } >> + >> + *retStats = tmpstats; >> + tmpstats = NULL; >> + >> + ret = nstats; >> + >> + cleanup: >> + virDomainStatsRecordListFree(tmpstats); >> + virObjectListFreeCount(vms, nvms); >> + return ret; >> +} >> + >> static int >> libxlConnectDomainEventRegisterAny(virConnectPtr conn, virDomainPtr dom, int eventID, >> virConnectDomainEventGenericCallback callback, >> @@ -5836,6 +6101,7 @@ static virHypervisorDriver libxlHypervisorDriver = { >> .domainInterfaceStats = libxlDomainInterfaceStats, /* 1.2.22 */ >> .domainMemoryStats = libxlDomainMemoryStats, /* 1.2.22 */ >> .domainGetCPUStats = libxlDomainGetCPUStats, /* 1.2.22 */ >> + .connectGetAllDomainStats = libxlConnectGetAllDomainStats, /* 1.2.22 */ >> .connectDomainEventRegister = libxlConnectDomainEventRegister, /* 0.9.0 */ >> .connectDomainEventDeregister = libxlConnectDomainEventDeregister, /* 0.9.0 */ >> .domainManagedSave = libxlDomainManagedSave, /* 0.9.2 */ > -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list