mirror of
https://gitlab.alpinelinux.org/alpine/aports.git
synced 2025-07-22 02:35:23 +03:00
218 lines
5.5 KiB
Diff
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);
|
|
}
|
|
}
|
|
|