As documented in linux.git/Documentation/cgroups/cpuacct.txt,
cpuacct.stat returns user and system time in ticks (the same
unit used in times(2)). It would be a bit nicer if it were like
getrusage(2) and reported timeval contents, or like cpuacct.usage
and in nanoseconds, but we can't be picky.
* src/util/cgroup.h (virCgroupGetCpuacctStat): New function.
* src/util/cgroup.c (virCgroupGetCpuacctStat): Implement it.
(virCgroupGetValueStr): Allow for multi-line files.
* src/libvirt_private.syms (cgroup.h): Export it.
---
src/libvirt_private.syms | 1 +
src/util/cgroup.c | 51 ++++++++++++++++++++++++++++++++++++++++++++-
src/util/cgroup.h | 4 ++-
3 files changed, 53 insertions(+), 3 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index d7ec221..1f55f5d 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -78,6 +78,7 @@ virCgroupGetCpuCfsPeriod;
virCgroupGetCpuCfsQuota;
virCgroupGetCpuShares;
virCgroupGetCpuacctPercpuUsage;
+virCgroupGetCpuacctStat;
virCgroupGetCpuacctUsage;
virCgroupGetCpusetMems;
virCgroupGetFreezerState;
diff --git a/src/util/cgroup.c b/src/util/cgroup.c
index c150fbb..ad49bc2 100644
--- a/src/util/cgroup.c
+++ b/src/util/cgroup.c
@@ -355,8 +355,8 @@ static int virCgroupGetValueStr(virCgroupPtr group,
VIR_DEBUG("Failed to read %s: %m\n", keypath);
} else {
/* Terminated with '\n' has sometimes harmful effects to the caller */
- char *p = strchr(*value, '\n');
- if (p) *p = '\0';
+ if ((*value)[rc - 1] == '\n')
+ (*value)[rc - 1] = '\0';
rc = 0;
}
@@ -1561,6 +1561,53 @@ int virCgroupGetCpuacctPercpuUsage(virCgroupPtr group, char
**usage)
"cpuacct.usage_percpu", usage);
}
+#ifdef _SC_CLK_TCK
+int virCgroupGetCpuacctStat(virCgroupPtr group, unsigned long long *user,
+ unsigned long long *sys)
+{
+ char *str;
+ char *p;
+ int ret;
+ static double scale = -1.0;
+
+ if ((ret = virCgroupGetValueStr(group, VIR_CGROUP_CONTROLLER_CPUACCT,
+ "cpuacct.stat", &str)) < 0)
+ return ret;
+ if (!(p = STRSKIP(str, "user ")) ||
+ virStrToLong_ull(p, &p, 10, user) < 0 ||
+ !(p = STRSKIP(p, "\nsystem ")) ||
+ virStrToLong_ull(p, NULL, 10, sys) < 0) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ /* times reported are in system ticks (generally 100 Hz), but that
+ * rate can theoretically vary between machines. Scale things
+ * into approximate nanoseconds. */
+ if (scale < 0) {
+ long ticks_per_sec = sysconf(_SC_CLK_TCK);
+ if (ticks_per_sec == -1) {
+ ret = -errno;
+ goto cleanup;
+ }
+ scale = 1000000000.0 / ticks_per_sec;
+ }
+ *user *= scale;
+ *sys *= scale;
+
+ ret = 0;
+cleanup:
+ VIR_FREE(str);
+ return ret;
+}
+#else
+int virCgroupGetCpuacctStat(virCgroupPtr group ATTRIBUTE_UNUSED,
+ unsigned long long *user ATTRIBUTE_UNUSED,
+ unsigned long long *sys ATTRIBUTE_UNUSED)
+{
+ return -ENOSYS;
+}
+#endif
+
int virCgroupSetFreezerState(virCgroupPtr group, const char *state)
{
return virCgroupSetValueStr(group,
diff --git a/src/util/cgroup.h b/src/util/cgroup.h
index b4e0f37..8486c42 100644
--- a/src/util/cgroup.h
+++ b/src/util/cgroup.h
@@ -1,7 +1,7 @@
/*
* cgroup.h: Interface to tools for managing cgroups
*
- * Copyright (C) 2011 Red Hat, Inc.
+ * Copyright (C) 2011-2012 Red Hat, Inc.
* Copyright IBM Corp. 2008
*
* See COPYING.LIB for the License of this software
@@ -116,6 +116,8 @@ int virCgroupGetCpuCfsQuota(virCgroupPtr group, long long
*cfs_quota);
int virCgroupGetCpuacctUsage(virCgroupPtr group, unsigned long long *usage);
int virCgroupGetCpuacctPercpuUsage(virCgroupPtr group, char **usage);
+int virCgroupGetCpuacctStat(virCgroupPtr group, unsigned long long *user,
+ unsigned long long *sys);
int virCgroupSetFreezerState(virCgroupPtr group, const char *state);
int virCgroupGetFreezerState(virCgroupPtr group, char **state);
--
1.7.7.6