1
0
Fork 0
mirror of https://gitlab.alpinelinux.org/alpine/aports.git synced 2025-07-22 02:35:23 +03:00
aports/main/lxc/lxc-info-cgroups-v2.patch

218 lines
5.5 KiB
Diff

From ebfe4c9d5a75ce5ea9881c55facd5edbdb18ee50 Mon Sep 17 00:00:00 2001
From: Petr Malat <oss@malat.biz>
Date: Mon, 4 Dec 2023 10:19:16 +0100
Subject: [PATCH] tools: lxc-info: Print memory and cpu utilization on cgroup2
system
Emulate the cgroup1 behavior by calculating memory.kmem.usage_in_bytes
and memory.usage_in_bytes using information provided in memory.stat and
use cpu.stat/usage_usec instead of cpuacct.usage.
Signed-off-by: Petr Malat <oss@malat.biz>
---
src/lxc/tools/lxc_info.c | 172 ++++++++++++++++++++++++++++++++++-----
1 file changed, 153 insertions(+), 19 deletions(-)
diff --git a/src/lxc/tools/lxc_info.c b/src/lxc/tools/lxc_info.c
index 681b597521..b59dc576a6 100644
--- a/src/lxc/tools/lxc_info.c
+++ b/src/lxc/tools/lxc_info.c
@@ -16,6 +16,7 @@
#include "arguments.h"
#include "log.h"
#include "utils.h"
+#include "macro.h"
lxc_log_define(lxc_info, lxc);
@@ -196,14 +197,158 @@ static void print_net_stats(struct lxc_container *c)
}
}
-static void print_stats(struct lxc_container *c)
+static int cg2_stat_iter(struct lxc_container *c, const char *file, void *cookie,
+ int (*iter)(char *key, char *val, void *cookie))
{
- int i, ret;
+ char *fileptr, *lineptr, *line, *metric, *value;
char buf[4096];
+ int ret;
+
+ ret = c->get_cgroup_item(c, file, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+
+ if ((size_t)ret >= sizeof(buf)) {
+ fprintf(stderr, "Internal buffer too small to read '%s'\n", file);
+ return -EMSGSIZE;
+ }
+
+ for (line = strtok_r(buf, "\n", &fileptr); line; line = strtok_r(NULL, "\n", &fileptr)) {
+ metric = strtok_r(line, " ", &lineptr);
+ if (!metric)
+ goto err;
+
+ value = strtok_r(NULL, " ", &lineptr);
+ if (!value)
+ goto err;
+
+ ret = iter(metric, value, cookie);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+
+err: fprintf(stderr, "Unexpected syntax of memory.stat\n");
+ return -EIO;
+}
+
+static int cg1_cpu_usage(struct lxc_container *c, char *usage)
+{
+ char buf[64];
+ int ret;
ret = c->get_cgroup_item(c, "cpuacct.usage", buf, sizeof(buf));
if (ret > 0 && (size_t)ret < sizeof(buf)) {
str_chomp(buf);
+ strcpy(usage, buf);
+ return 0;
+ }
+
+ return ret;
+}
+
+static int cg2_cpu_usage_iter(char *metric, char *value, void *cookie)
+{
+ if (strcmp(metric, "usage_usec"))
+ return 0;
+
+ strcpy(cookie, value);
+ strcat(cookie, "000");
+ return 1;
+}
+
+static int cg2_cpu_usage(struct lxc_container *c, char *usage)
+{
+ int ret;
+
+ ret = cg2_stat_iter(c, "cpu.stat", usage, cg2_cpu_usage_iter);
+ return ret == 1 ? 0 : ret ?: -ESRCH;
+}
+
+static int search_array(const char *array[], const char *needle, size_t size)
+{
+ size_t i;
+
+ for (i = 0; i < size; i++)
+ if (!strcmp(array[i], needle))
+ return 1;
+ return 0;
+}
+
+struct cg2_mem_usage_s {
+ unsigned long long user, kernel;
+};
+
+static int cg2_mem_usage_iter(char *metric, char *value, void *cookie)
+{
+ const char *kernel_fields[] = { "kernel_stack", "pagetables", "sock", "slab" };
+ const char *user_fields[] = { "anon", "file" };
+ struct cg2_mem_usage_s *usage = cookie;
+ unsigned long long numvalue;
+ char *end;
+
+ numvalue = strtoull(value, &end, 10);
+ if (numvalue == ULLONG_MAX || *end) {
+ fprintf(stderr, "Unexpected syntax of memory.stat\n");
+ return -EIO;
+ }
+
+ if (search_array(kernel_fields, metric, ARRAY_SIZE(kernel_fields)))
+ usage->kernel += numvalue;
+ else if (search_array(user_fields, metric, ARRAY_SIZE(user_fields)))
+ usage->user += numvalue;
+ return 0;
+}
+
+static int cg2_mem_usage(struct lxc_container *c, char *user, char *kernel)
+{
+ struct cg2_mem_usage_s usage = { 0 };
+ int ret;
+
+ ret = cg2_stat_iter(c, "memory.stat", &usage, cg2_mem_usage_iter);
+ if (ret < 0)
+ return ret;
+
+ sprintf(kernel, "%llu", usage.kernel);
+ sprintf(user, "%llu", usage.user);
+
+ return 0;
+
+}
+
+static int cg1_mem_usage(struct lxc_container *c, char *user, char *kernel)
+{
+ struct {
+ const char *file;
+ char *target;
+ } lxstat[] = {
+ { "memory.usage_in_bytes", user },
+ { "memory.kmem.usage_in_bytes", kernel },
+ };
+ int ret, i, match = 0;
+ char buf[64];
+
+ for (i = 0; i < (int)ARRAY_SIZE(lxstat); i++) {
+ ret = c->get_cgroup_item(c, lxstat[i].file, buf, sizeof(buf));
+ if (ret > 0 && (size_t)ret < sizeof(buf)) {
+ str_chomp(buf);
+ strcpy(lxstat[i].target, buf);
+ match++;
+ }
+ }
+
+ return match == ARRAY_SIZE(lxstat) ? 0 : -ESRCH;
+}
+
+static void print_stats(struct lxc_container *c)
+{
+ int ret;
+ char buf[4096];
+ char *user = buf;
+ char *kernel = buf + sizeof(buf) / 2;
+
+ if (!cg1_cpu_usage(c, buf) || !cg2_cpu_usage(c, buf)) {
if (humanize) {
float seconds = strtof(buf, NULL) / 1000000000.0;
printf("%-15s %.2f seconds\n", "CPU use:", seconds);
@@ -233,23 +378,12 @@ static void print_stats(struct lxc_container *c)
fflush(stdout);
}
- static const struct {
- const char *name;
- const char *file;
- } lxstat[] = {
- { "Memory use:", "memory.usage_in_bytes" },
- { "KMem use:", "memory.kmem.usage_in_bytes" },
- { NULL, NULL },
- };
-
- for (i = 0; lxstat[i].name; i++) {
- ret = c->get_cgroup_item(c, lxstat[i].file, buf, sizeof(buf));
- if (ret > 0 && (size_t)ret < sizeof(buf)) {
- str_chomp(buf);
- str_size_humanize(buf, sizeof(buf));
- printf("%-15s %s\n", lxstat[i].name, buf);
- fflush(stdout);
- }
+ if (!cg1_mem_usage(c, user, kernel) || !cg2_mem_usage(c, user, kernel)) {
+ str_size_humanize(user, sizeof(buf) / 2 - 1);
+ printf("%-15s %s\n", "Memory use:", user);
+ str_size_humanize(kernel, sizeof(buf) / 2 - 1);
+ printf("%-15s %s\n", "KMem use:", kernel);
+ fflush(stdout);
}
}