---
Notes v3:
- moved most of the code out to virCgroupGetPercpuStats, for better
testability.
- addressed comments from v2 review
src/libvirt_private.syms | 1 +
src/lxc/lxc_driver.c | 51 ++++++++++++++++++++++++++++++++
src/util/vircgroup.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++
src/util/vircgroup.h | 7 +++++
4 files changed, 134 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 890d6c7..4a7201e 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1023,6 +1023,7 @@ virCgroupGetMemorySoftLimit;
virCgroupGetMemoryUsage;
virCgroupGetMemSwapHardLimit;
virCgroupGetMemSwapUsage;
+virCgroupGetPercpuStats;
virCgroupHasController;
virCgroupIsolateMount;
virCgroupKill;
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 02b5cc3..39cd981 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -76,6 +76,7 @@
#define LXC_NB_MEM_PARAM 3
+
static int lxcStateInitialize(bool privileged,
virStateInhibitCallback callback,
void *opaque);
@@ -5388,6 +5389,55 @@ 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;
+ bool isActive;
+ 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;
+
+ isActive = virDomainObjIsActive(vm);
+ if (!isActive) {
+ 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,
@@ -5466,6 +5516,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 7427a21..268a4ae 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 fae4d92..67478f5 100644
--- a/src/util/vircgroup.h
+++ b/src/util/vircgroup.h
@@ -202,6 +202,13 @@ int virCgroupDenyDevicePath(virCgroupPtr group,
int perms);
int
+virCgroupGetPercpuStats(virCgroupPtr group,
+ virTypedParameterPtr params,
+ unsigned int nparams,
+ int start_cpu,
+ unsigned int ncpus);
+
+int
virCgroupGetDomainTotalCpuStats(virCgroupPtr group,
virTypedParameterPtr params,
int nparams);
--
1.8.4