---
src/lxc/lxc_driver.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 132 insertions(+)
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 9f586af..1e9c77a 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -75,6 +75,8 @@
#define LXC_NB_MEM_PARAM 3
+#define LXC_NB_PER_CPU_STAT_PARAM 1
+
static int lxcStateInitialize(bool privileged,
virStateInhibitCallback callback,
@@ -4775,6 +4777,135 @@ cleanup:
}
+static int
+lxcDomainGetPercpuStats(virDomainObjPtr vm,
+ 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;
+ unsigned int n = 0;
+ virLXCDomainObjPrivatePtr priv = vm->privateData;
+ virTypedParameterPtr ent;
+ int param_idx;
+ unsigned long long cpu_time;
+
+ /* TODO: share api contract code with other drivers here */
+
+ /* return the number of supported params */
+ if (nparams == 0 && ncpus != 0)
+ return LXC_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(priv->cgroup, &buf))
+ goto cleanup;
+ pos = buf;
+ memset(params, 0, nparams * ncpus);
+
+ /* 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;
+ } else {
+ n++;
+ }
+ 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;
+}
+
+
+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 = lxcDomainGetPercpuStats(vm, params, nparams,
+ start_cpu, ncpus);
+cleanup:
+ if (vm)
+ virObjectUnlock(vm);
+ return ret;
+}
+
+
/* Function Tables */
static virDriver lxcDriver = {
.no = VIR_DRV_LXC,
@@ -4852,6 +4983,7 @@ static virDriver lxcDriver = {
.nodeSuspendForDuration = lxcNodeSuspendForDuration, /* 0.9.8 */
.domainSetMetadata = lxcDomainSetMetadata, /* 1.1.3 */
.domainGetMetadata = lxcDomainGetMetadata, /* 1.1.3 */
+ .domainGetCPUStats = lxcDomainGetCPUStats, /* 0.9.11 */
.nodeGetMemoryParameters = lxcNodeGetMemoryParameters, /* 0.10.2 */
.nodeSetMemoryParameters = lxcNodeSetMemoryParameters, /* 0.10.2 */
.domainSendProcessSignal = lxcDomainSendProcessSignal, /* 1.0.1 */
--
1.8.4