On 01/20/2014 08:15 PM, Thorsten Behrens wrote:
This reads blkio stats from blkio.throttle.io_service_bytes and
blkio.throttle.io_serviced.
---
Note on v3:
- rebased to current master, sadly the
virCgroupSetBlkioDeviceReadBps etc conflicted
src/libvirt_private.syms | 2 +
src/util/vircgroup.c | 242 +++++++++++++++++++++++++++++++++++++++++++++++
src/util/vircgroup.h | 12 +++
3 files changed, 256 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 3ede3d5..1e44ed8 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1002,6 +1002,8 @@ virCgroupDenyDevice;
virCgroupDenyDeviceMajor;
virCgroupDenyDevicePath;
virCgroupFree;
+virCgroupGetBlkioIoDeviceServiced;
+virCgroupGetBlkioIoServiced;
virCgroupGetBlkioWeight;
virCgroupGetCpuacctPercpuUsage;
virCgroupGetCpuacctStat;
diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c
index a6d60c5..2b70bcb 100644
--- a/src/util/vircgroup.c
+++ b/src/util/vircgroup.c
@@ -1786,6 +1786,221 @@ virCgroupPathOfController(virCgroupPtr group,
/**
+ * virCgroupGetBlkioIoServiced:
+ *
+ * @group: The cgroup to get throughput for
+ * @bytes_read: Pointer to returned bytes read
+ * @bytes_write: Pointer to returned bytes written
+ * @requests_read: Pointer to returned read io ops
+ * @requests_write: Pointer to returned write io ops
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int
+virCgroupGetBlkioIoServiced(virCgroupPtr group,
+ long long *bytes_read,
+ long long *bytes_write,
+ long long *requests_read,
+ long long *requests_write)
+{
+ long long stats_val;
+ char *str1 = NULL, *str2 = NULL, *p1, *p2;
+ size_t i;
+ int ret = -1;
+
+ const char *value_names[] = {
+ "Read ",
+ "Write "
+ };
+ long long *bytes_ptrs[] = {
+ bytes_read,
+ bytes_write
+ };
+ long long *requests_ptrs[] = {
+ requests_read,
+ requests_write
+ };
+
+ *bytes_read = 0;
+ *bytes_write = 0;
+ *requests_read = 0;
+ *requests_write = 0;
+
+ if (virCgroupGetValueStr(group,
+ VIR_CGROUP_CONTROLLER_BLKIO,
+ "blkio.throttle.io_service_bytes", &str1)
< 0)
+ goto cleanup;
+
+ if (virCgroupGetValueStr(group,
+ VIR_CGROUP_CONTROLLER_BLKIO,
+ "blkio.throttle.io_serviced", &str2) < 0)
+ goto cleanup;
+
+ /* sum up all entries of the same kind, from all devices */
+ for (i = 0; i < ARRAY_CARDINALITY(value_names); i++) {
+ p1 = str1;
+ p2 = str2;
+
+ while ((p1 = strstr(p1, value_names[i]))) {
+ p1 += strlen(value_names[i]);
+ if (virStrToLong_ll(p1, &p1, 10, &stats_val) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Cannot parse byte %sstat '%s'"),
+ value_names[i],
+ p1);
+ goto cleanup;
+ }
+
+ if (stats_val < 0 ||
+ (stats_val > 0 && *bytes_ptrs[i] > (LLONG_MAX -
stats_val)))
+ {
+ virReportError(VIR_ERR_OVERFLOW,
+ _("Sum of byte %sstat overflows"),
+ value_names[i]);
+ goto cleanup;
+ }
+ *bytes_ptrs[i] += stats_val;
+ }
+
+ while ((p2 = strstr(p2, value_names[i]))) {
+ p2 += strlen(value_names[i]);
+ if (virStrToLong_ll(p2, &p2, 10, &stats_val) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Cannot parse %srequest stat '%s'"),
+ value_names[i],
+ p2);
+ goto cleanup;
+ }
+
+ if (stats_val < 0 ||
+ (stats_val > 0 && *requests_ptrs[i] > (LLONG_MAX -
stats_val)))
+ {
+ virReportError(VIR_ERR_OVERFLOW,
+ _("Sum of %srequest stat overflows"),
+ value_names[i]);
+ goto cleanup;
+ }
+ *requests_ptrs[i] += stats_val;
+ }
+ }
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(str2);
+ VIR_FREE(str1);
+ return ret;
+}
+
+
+/**
+ * virCgroupGetBlkioIoDeviceServiced:
+ *
+ * @group: The cgroup to get throughput for
+ * @path: The device to get throughput for
+ * @bytes_read: Pointer to returned bytes read
+ * @bytes_write: Pointer to returned bytes written
+ * @requests_read: Pointer to returned read io ops
+ * @requests_write: Pointer to returned write io ops
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int
+virCgroupGetBlkioIoDeviceServiced(virCgroupPtr group,
+ const char *path,
+ long long *bytes_read,
+ long long *bytes_write,
+ long long *requests_read,
+ long long *requests_write)
+{
+ char *str1 = NULL, *str2 = NULL, *str3 = NULL, *p;
+ struct stat sb;
+ size_t i;
+ int ret = -1;
+
+ const char *value_names[] = {
+ "Read ",
+ "Write "
+ };
+ long long *bytes_ptrs[] = {
+ bytes_read,
+ bytes_write
+ };
+ long long *requests_ptrs[] = {
+ requests_read,
+ requests_write
+ };
+
+ if (stat(path, &sb) < 0) {
+ virReportSystemError(errno,
+ _("Path '%s' is not accessible"),
+ path);
+ return -1;
+ }
+
+ if (!S_ISBLK(sb.st_mode)) {
+ virReportSystemError(EINVAL,
+ _("Path '%s' must be a block device"),
+ path);
+ return -1;
+ }
+
+ if (virCgroupGetValueStr(group,
+ VIR_CGROUP_CONTROLLER_BLKIO,
+ "blkio.throttle.io_service_bytes", &str1)
< 0)
+ goto cleanup;
+
+ if (virCgroupGetValueStr(group,
+ VIR_CGROUP_CONTROLLER_BLKIO,
+ "blkio.throttle.io_serviced", &str2) < 0)
+ goto cleanup;
+
+ if (virAsprintf(&str3, "%d:%d ", major(sb.st_rdev), minor(sb.st_rdev))
< 0)
+ goto cleanup;
+
+ if (!(p = strstr(str1, str3))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Cannot find byte stats for block device
'%s'"),
+ p);
path?
+ goto cleanup;
+ }
+
+ if (!(p = strstr(str2, str3))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Cannot find request stats for block device
'%s'"),
+ p);
here too;
+ goto cleanup;
+ }
+
+ for (i = 0; i < ARRAY_CARDINALITY(value_names); i++) {
+ if (!(p = strstr(p, value_names[i])) ||
+ virStrToLong_ll(p + strlen(value_names[i]), &p, 10, bytes_ptrs[i]) <
0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Cannot parse stat '%s'"),
+ p + strlen(value_names[i]));
p may null here.
+ goto cleanup;
+ }
+
+ if (!(p = strstr(p, value_names[i])) ||
+ virStrToLong_ll(p + strlen(value_names[i]), &p, 10, requests_ptrs[i])
< 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Cannot parse stat '%s'"),
+ p + strlen(value_names[i]));
here too;
ACK with these changed.