From 4b3b2f6ceb5ddd257b4d7d6ae14679921f2995ea Mon Sep 17 00:00:00 2001 From: Thorsten Behrens Date: Fri, 14 Feb 2014 18:49:02 +0100 Subject: [PATCH] Implement domainGetCPUStats for lxc driver. --- src/libvirt_private.syms | 1 + src/lxc/lxc_driver.c | 49 ++++++++++++++++++++++++++ src/util/vircgroup.c | 75 ++++++++++++++++++++++++++++++++++++++++ src/util/vircgroup.h | 7 ++++ 4 files changed, 132 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index c404cee621..341d2e0639 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1032,6 +1032,7 @@ virCgroupGetMemorySoftLimit; virCgroupGetMemoryUsage; virCgroupGetMemSwapHardLimit; virCgroupGetMemSwapUsage; +virCgroupGetPercpuStats; virCgroupHasController; virCgroupIsolateMount; virCgroupKill; diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index fbbd8cae70..ef74ad53b0 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -77,6 +77,7 @@ #define LXC_NB_MEM_PARAM 3 + static int lxcStateInitialize(bool privileged, virStateInhibitCallback callback, void *opaque); @@ -5420,6 +5421,53 @@ cleanup: } +static int +lxcDomainGetCPUStats(virDomainPtr dom, + virTypedParameterPtr params, + unsigned int nparams, + int start_cpu, + unsigned int ncpus, + unsigned int flags) +{ + virDomainObjPtr vm = NULL; + int ret = -1; + virLXCDomainObjPrivatePtr priv; + + virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1); + + if (!(vm = lxcDomObjFromDomain(dom))) + return ret; + + priv = vm->privateData; + + if (virDomainGetCPUStatsEnsureACL(dom->conn, vm->def) < 0) + goto cleanup; + + if (!virDomainObjIsActive(vm)) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("domain is not running")); + goto cleanup; + } + + if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUACCT)) { + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("cgroup CPUACCT controller is not mounted")); + goto cleanup; + } + + if (start_cpu == -1) + ret = virCgroupGetDomainTotalCpuStats(priv->cgroup, + params, nparams); + else + ret = virCgroupGetPercpuStats(priv->cgroup, params, + nparams, start_cpu, ncpus); +cleanup: + if (vm) + virObjectUnlock(vm); + return ret; +} + + /* Function Tables */ static virDriver lxcDriver = { .no = VIR_DRV_LXC, @@ -5499,6 +5547,7 @@ static virDriver lxcDriver = { .nodeSuspendForDuration = lxcNodeSuspendForDuration, /* 0.9.8 */ .domainSetMetadata = lxcDomainSetMetadata, /* 1.1.3 */ .domainGetMetadata = lxcDomainGetMetadata, /* 1.1.3 */ + .domainGetCPUStats = lxcDomainGetCPUStats, /* 1.2.2 */ .nodeGetMemoryParameters = lxcNodeGetMemoryParameters, /* 0.10.2 */ .nodeSetMemoryParameters = lxcNodeSetMemoryParameters, /* 0.10.2 */ .domainSendProcessSignal = lxcDomainSendProcessSignal, /* 1.0.1 */ diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c index 7427a21df8..268a4ae0eb 100644 --- a/src/util/vircgroup.c +++ b/src/util/vircgroup.c @@ -53,11 +53,14 @@ #include "virsystemd.h" #include "virtypedparam.h" +#include "nodeinfo.h" + #define CGROUP_MAX_VAL 512 #define VIR_FROM_THIS VIR_FROM_CGROUP #define CGROUP_NB_TOTAL_CPU_STAT_PARAM 3 +#define CGROUP_NB_PER_CPU_STAT_PARAM 1 #if defined(__linux__) && defined(HAVE_GETMNTENT_R) && \ defined(_DIRENT_HAVE_D_TYPE) && defined(_SC_CLK_TCK) @@ -2824,6 +2827,78 @@ virCgroupDenyDevicePath(virCgroupPtr group, const char *path, int perms) } +int +virCgroupGetPercpuStats(virCgroupPtr group, + virTypedParameterPtr params, + unsigned int nparams, + int start_cpu, + unsigned int ncpus) +{ + int rv = -1; + size_t i; + int id, max_id; + char *pos; + char *buf = NULL; + virTypedParameterPtr ent; + int param_idx; + unsigned long long cpu_time; + + /* return the number of supported params */ + if (nparams == 0 && ncpus != 0) + return CGROUP_NB_PER_CPU_STAT_PARAM; + + /* To parse account file, we need to know how many cpus are present. */ + max_id = nodeGetCPUCount(); + if (max_id < 0) + return rv; + + if (ncpus == 0) { /* returns max cpu ID */ + rv = max_id; + goto cleanup; + } + + if (start_cpu > max_id) { + virReportError(VIR_ERR_INVALID_ARG, + _("start_cpu %d larger than maximum of %d"), + start_cpu, max_id); + goto cleanup; + } + + /* we get percpu cputime accounting info. */ + if (virCgroupGetCpuacctPercpuUsage(group, &buf)) + goto cleanup; + pos = buf; + + /* return percpu cputime in index 0 */ + param_idx = 0; + + /* number of cpus to compute */ + if (start_cpu >= max_id - ncpus) + id = max_id - 1; + else + id = start_cpu + ncpus - 1; + + for (i = 0; i <= id; i++) { + if (virStrToLong_ull(pos, &pos, 10, &cpu_time) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cpuacct parse error")); + goto cleanup; + } + if (i < start_cpu) + continue; + ent = ¶ms[(i - start_cpu) * nparams + param_idx]; + if (virTypedParameterAssign(ent, VIR_DOMAIN_CPU_STATS_CPUTIME, + VIR_TYPED_PARAM_ULLONG, cpu_time) < 0) + goto cleanup; + } + + rv = nparams; + +cleanup: + VIR_FREE(buf); + return rv; +} + int virCgroupGetDomainTotalCpuStats(virCgroupPtr group, diff --git a/src/util/vircgroup.h b/src/util/vircgroup.h index fae4d927e0..67478f5e6b 100644 --- a/src/util/vircgroup.h +++ b/src/util/vircgroup.h @@ -201,6 +201,13 @@ int virCgroupDenyDevicePath(virCgroupPtr group, const char *path, int perms); +int +virCgroupGetPercpuStats(virCgroupPtr group, + virTypedParameterPtr params, + unsigned int nparams, + int start_cpu, + unsigned int ncpus); + int virCgroupGetDomainTotalCpuStats(virCgroupPtr group, virTypedParameterPtr params,