diff options
Diffstat (limited to 'main/lxc/lxc-top-cgroupv2.patch')
-rw-r--r-- | main/lxc/lxc-top-cgroupv2.patch | 620 |
1 files changed, 533 insertions, 87 deletions
diff --git a/main/lxc/lxc-top-cgroupv2.patch b/main/lxc/lxc-top-cgroupv2.patch index a88b8546bd0..5e6098aa9c1 100644 --- a/main/lxc/lxc-top-cgroupv2.patch +++ b/main/lxc/lxc-top-cgroupv2.patch @@ -1,118 +1,564 @@ -From ba823cc3cd2ea8b7eef714c317a212a9d7b5afe0 Mon Sep 17 00:00:00 2001 -From: Anoop Rachakonda <anooprac@utexas.edu> -Date: Wed, 1 May 2024 13:56:30 -0500 -Subject: [PATCH] stats_get: Changed paths to be aligned with cgroup2 - specifications +From 40857b9de3714b3314f5c22e924d5993c458acbe Mon Sep 17 00:00:00 2001 +From: Natanael Copa <ncopa@alpinelinux.org> +Date: Wed, 24 Jul 2024 15:23:11 +0200 +Subject: [PATCH 1/5] tools: lxc-top: refactor lxc-top stat structs -Closes #4376 +Create separate structs for each controller class. This will make it +easier to add cgroupv2 support. -Signed-off-by: Devon Schwartz <devon.s.schwartz@utexas.edu> +No functional changes. + +Signed-off-by: Natanael Copa <ncopa@alpinelinux.org> +--- + src/lxc/tools/lxc_top.c | 125 +++++++++++++++++++++++----------------- + 1 file changed, 72 insertions(+), 53 deletions(-) + +diff --git a/src/lxc/tools/lxc_top.c b/src/lxc/tools/lxc_top.c +index aa6e7209e..bcc695b3e 100644 +--- a/src/lxc/tools/lxc_top.c ++++ b/src/lxc/tools/lxc_top.c +@@ -35,16 +35,24 @@ struct blkio_stats { + uint64_t total; + }; + +-struct stats { +- uint64_t mem_used; +- uint64_t mem_limit; +- uint64_t memsw_used; +- uint64_t memsw_limit; ++struct cpu_stats { ++ uint64_t use_nanos; ++ uint64_t use_user; ++ uint64_t use_sys; ++}; ++ ++struct mem_stats { ++ uint64_t used; ++ uint64_t limit; ++ uint64_t swap_used; ++ uint64_t swap_limit; + uint64_t kmem_used; + uint64_t kmem_limit; +- uint64_t cpu_use_nanos; +- uint64_t cpu_use_user; +- uint64_t cpu_use_sys; ++}; ++ ++struct stats { ++ struct mem_stats mem; ++ struct cpu_stats cpu; + struct blkio_stats io_service_bytes; + struct blkio_stats io_serviced; + }; +@@ -314,34 +322,45 @@ out: + return; + } + ++static void cg1_mem_stats(struct lxc_container *c, struct mem_stats *mem) ++{ ++ mem->used = stat_get_int(c, "memory.usage_in_bytes"); ++ mem->limit = stat_get_int(c, "memory.limit_in_bytes"); ++ mem->swap_used = stat_get_int(c, "memory.memsw.usage_in_bytes"); ++ mem->swap_limit = stat_get_int(c, "memory.memsw.limit_in_bytes"); ++ mem->kmem_used = stat_get_int(c, "memory.kmem.usage_in_bytes"); ++ mem->kmem_limit = stat_get_int(c, "memory.kmem.limit_in_bytes"); ++} ++ ++static void cg1_cpu_stats(struct lxc_container *c, struct cpu_stats *cpu) ++{ ++ cpu->use_nanos = stat_get_int(c, "cpuacct.usage"); ++ cpu->use_user = stat_match_get_int(c, "cpuacct.stat", "user", 1); ++ cpu->use_sys = stat_match_get_int(c, "cpuacct.stat", "system", 1); ++} ++ + static void stats_get(struct lxc_container *c, struct container_stats *ct, struct stats *total) + { + ct->c = c; +- ct->stats->mem_used = stat_get_int(c, "memory.usage_in_bytes"); +- ct->stats->mem_limit = stat_get_int(c, "memory.limit_in_bytes"); +- ct->stats->memsw_used = stat_get_int(c, "memory.memsw.usage_in_bytes"); +- ct->stats->memsw_limit = stat_get_int(c, "memory.memsw.limit_in_bytes"); +- ct->stats->kmem_used = stat_get_int(c, "memory.kmem.usage_in_bytes"); +- ct->stats->kmem_limit = stat_get_int(c, "memory.kmem.limit_in_bytes"); +- ct->stats->cpu_use_nanos = stat_get_int(c, "cpuacct.usage"); +- ct->stats->cpu_use_user = stat_match_get_int(c, "cpuacct.stat", "user", 1); +- ct->stats->cpu_use_sys = stat_match_get_int(c, "cpuacct.stat", "system", 1); +- ++ cg1_mem_stats(c, &ct->stats->mem); ++ cg1_cpu_stats(c, &ct->stats->cpu); + stat_get_blk_stats(c, "blkio.throttle.io_service_bytes", &ct->stats->io_service_bytes); + stat_get_blk_stats(c, "blkio.throttle.io_serviced", &ct->stats->io_serviced); + + if (total) { +- total->mem_used = total->mem_used + ct->stats->mem_used; +- total->mem_limit = total->mem_limit + ct->stats->mem_limit; +- total->memsw_used = total->memsw_used + ct->stats->memsw_used; +- total->memsw_limit = total->memsw_limit + ct->stats->memsw_limit; +- total->kmem_used = total->kmem_used + ct->stats->kmem_used; +- total->kmem_limit = total->kmem_limit + ct->stats->kmem_limit; +- total->cpu_use_nanos = total->cpu_use_nanos + ct->stats->cpu_use_nanos; +- total->cpu_use_user = total->cpu_use_user + ct->stats->cpu_use_user; +- total->cpu_use_sys = total->cpu_use_sys + ct->stats->cpu_use_sys; ++ total->mem.used += ct->stats->mem.used; ++ total->mem.limit += ct->stats->mem.limit; ++ total->mem.swap_used += ct->stats->mem.swap_used; ++ total->mem.swap_limit += ct->stats->mem.swap_limit; ++ total->mem.kmem_used += ct->stats->mem.kmem_used; ++ total->mem.kmem_limit += ct->stats->mem.kmem_limit; ++ ++ total->cpu.use_nanos += ct->stats->cpu.use_nanos; ++ total->cpu.use_user += ct->stats->cpu.use_user; ++ total->cpu.use_sys += ct->stats->cpu.use_sys; ++ + total->io_service_bytes.total += ct->stats->io_service_bytes.total; +- total->io_service_bytes.read += ct->stats->io_service_bytes.read; ++ total->io_service_bytes.read += ct->stats->io_service_bytes.read; + total->io_service_bytes.write += ct->stats->io_service_bytes.write; + } + } +@@ -351,19 +370,19 @@ static void stats_print_header(struct stats *stats) + printf(TERMRVRS TERMBOLD); + printf("%-18s %12s %12s %12s %36s %10s", "Container", "CPU", "CPU", "CPU", "BlkIO", "Mem"); + +- if (stats->memsw_used > 0) ++ if (stats->mem.swap_used > 0) + printf(" %10s", "MemSw"); + +- if (stats->kmem_used > 0) ++ if (stats->mem.kmem_used > 0) + printf(" %10s", "KMem"); + printf("\n"); + + printf("%-18s %12s %12s %12s %36s %10s", "Name", "Used", "Sys", "User", "Total(Read/Write)", "Used"); + +- if (stats->memsw_used > 0) ++ if (stats->mem.swap_used > 0) + printf(" %10s", "Used"); + +- if (stats->kmem_used > 0) ++ if (stats->mem.kmem_used > 0) + printf(" %10s", "Used"); + + printf("\n"); +@@ -388,7 +407,7 @@ static void stats_print(const char *name, const struct stats *stats, + size_humanize(stats->io_service_bytes.total, iosb_total_str, sizeof(iosb_total_str)); + size_humanize(stats->io_service_bytes.read, iosb_read_str, sizeof(iosb_read_str)); + size_humanize(stats->io_service_bytes.write, iosb_write_str, sizeof(iosb_write_str)); +- size_humanize(stats->mem_used, mem_used_str, sizeof(mem_used_str)); ++ size_humanize(stats->mem.used, mem_used_str, sizeof(mem_used_str)); + + ret = snprintf(iosb_str, sizeof(iosb_str), "%s(%s/%s)", iosb_total_str, iosb_read_str, iosb_write_str); + if (ret < 0 || (size_t)ret >= sizeof(iosb_str)) +@@ -396,18 +415,18 @@ static void stats_print(const char *name, const struct stats *stats, + + printf("%-18.18s %12.2f %12.2f %12.2f %36s %10s", + name, +- (float)stats->cpu_use_nanos / 1000000000, +- (float)stats->cpu_use_sys / USER_HZ, +- (float)stats->cpu_use_user / USER_HZ, ++ (float)stats->cpu.use_nanos / 1000000000, ++ (float)stats->cpu.use_sys / USER_HZ, ++ (float)stats->cpu.use_user / USER_HZ, + iosb_str, + mem_used_str); + +- if (total->memsw_used > 0) { +- size_humanize(stats->memsw_used, memsw_used_str, sizeof(memsw_used_str)); ++ if (total->mem.swap_used > 0) { ++ size_humanize(stats->mem.swap_used, memsw_used_str, sizeof(memsw_used_str)); + printf(" %10s", memsw_used_str); + } +- if (total->kmem_used > 0) { +- size_humanize(stats->kmem_used, kmem_used_str, sizeof(kmem_used_str)); ++ if (total->mem.kmem_used > 0) { ++ size_humanize(stats->mem.kmem_used, kmem_used_str, sizeof(kmem_used_str)); + printf(" %10s", kmem_used_str); + } + } else { +@@ -415,11 +434,11 @@ static void stats_print(const char *name, const struct stats *stats, + time_ms = (unsigned long long) (time_val.tv_sec) * 1000 + (unsigned long long) (time_val.tv_usec) / 1000; + printf("%" PRIu64 ",%s,%" PRIu64 ",%" PRIu64 ",%" PRIu64 + ",%" PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64, +- (uint64_t)time_ms, name, (uint64_t)stats->cpu_use_nanos, +- (uint64_t)stats->cpu_use_sys, +- (uint64_t)stats->cpu_use_user, (uint64_t)stats->io_service_bytes.total, +- (uint64_t)stats->io_serviced.total, (uint64_t)stats->mem_used, +- (uint64_t)stats->memsw_used, (uint64_t)stats->kmem_used); ++ (uint64_t)time_ms, name, (uint64_t)stats->cpu.use_nanos, ++ (uint64_t)stats->cpu.use_sys, ++ (uint64_t)stats->cpu.use_user, (uint64_t)stats->io_service_bytes.total, ++ (uint64_t)stats->io_serviced.total, (uint64_t)stats->mem.used, ++ (uint64_t)stats->mem.swap_used, (uint64_t)stats->mem.kmem_used); + } + + } +@@ -441,9 +460,9 @@ static int cmp_cpuuse(const void *sct1, const void *sct2) + const struct container_stats *ct2 = sct2; + + if (sort_reverse) +- return ct2->stats->cpu_use_nanos < ct1->stats->cpu_use_nanos; ++ return ct2->stats->cpu.use_nanos < ct1->stats->cpu.use_nanos; + +- return ct1->stats->cpu_use_nanos < ct2->stats->cpu_use_nanos; ++ return ct1->stats->cpu.use_nanos < ct2->stats->cpu.use_nanos; + } + + static int cmp_blkio(const void *sct1, const void *sct2) +@@ -463,9 +482,9 @@ static int cmp_memory(const void *sct1, const void *sct2) + const struct container_stats *ct2 = sct2; + + if (sort_reverse) +- return ct2->stats->mem_used < ct1->stats->mem_used; ++ return ct2->stats->mem.used < ct1->stats->mem.used; + +- return ct1->stats->mem_used < ct2->stats->mem_used; ++ return ct1->stats->mem.used < ct2->stats->mem.used; + } + + static int cmp_memorysw(const void *sct1, const void *sct2) +@@ -474,9 +493,9 @@ static int cmp_memorysw(const void *sct1, const void *sct2) + const struct container_stats *ct2 = sct2; + + if (sort_reverse) +- return ct2->stats->memsw_used < ct1->stats->memsw_used; ++ return ct2->stats->mem.swap_used < ct1->stats->mem.swap_used; + +- return ct1->stats->memsw_used < ct2->stats->memsw_used; ++ return ct1->stats->mem.swap_used < ct2->stats->mem.swap_used; + } + + static int cmp_kmemory(const void *sct1, const void *sct2) +@@ -485,9 +504,9 @@ static int cmp_kmemory(const void *sct1, const void *sct2) + const struct container_stats *ct2 = sct2; + + if (sort_reverse) +- return ct2->stats->kmem_used < ct1->stats->kmem_used; ++ return ct2->stats->mem.kmem_used < ct1->stats->mem.kmem_used; + +- return ct1->stats->kmem_used < ct2->stats->kmem_used; ++ return ct1->stats->mem.kmem_used < ct2->stats->mem.kmem_used; + } + + static void ct_sort(int active) +-- +2.45.2 + + +From ec11c2dad1ccf5fd6dd9a57e2812c4551f8a710f Mon Sep 17 00:00:00 2001 +From: Natanael Copa <ncopa@alpinelinux.org> +Date: Wed, 24 Jul 2024 15:47:55 +0200 +Subject: [PATCH 2/5] tools: lxc-top: get memory stats from cgroups2 + +Signed-off-by: Natanael Copa <ncopa@alpinelinux.org> --- - src/lxc/tools/lxc_top.c | 64 ++++++++++++++++++++++++++++++++--------- - 1 file changed, 51 insertions(+), 13 deletions(-) + src/lxc/tools/lxc_top.c | 23 ++++++++++++++++++++--- + 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/lxc/tools/lxc_top.c b/src/lxc/tools/lxc_top.c -index aa6e7209e3..f27025f730 100644 +index bcc695b3e..29d81563f 100644 --- a/src/lxc/tools/lxc_top.c +++ b/src/lxc/tools/lxc_top.c -@@ -276,27 +276,33 @@ static uint64_t stat_match_get_int(struct lxc_container *c, const char *item, +@@ -212,7 +212,6 @@ static uint64_t stat_get_int(struct lxc_container *c, const char *item) + + len = c->get_cgroup_item(c, item, buf, sizeof(buf)); + if (len <= 0) { +- fprintf(stderr, "Unable to read cgroup item %s\n", item); + return 0; + } + +@@ -322,7 +321,7 @@ out: + return; + } + +-static void cg1_mem_stats(struct lxc_container *c, struct mem_stats *mem) ++static int cg1_mem_stats(struct lxc_container *c, struct mem_stats *mem) + { + mem->used = stat_get_int(c, "memory.usage_in_bytes"); + mem->limit = stat_get_int(c, "memory.limit_in_bytes"); +@@ -330,6 +329,20 @@ static void cg1_mem_stats(struct lxc_container *c, struct mem_stats *mem) + mem->swap_limit = stat_get_int(c, "memory.memsw.limit_in_bytes"); + mem->kmem_used = stat_get_int(c, "memory.kmem.usage_in_bytes"); + mem->kmem_limit = stat_get_int(c, "memory.kmem.limit_in_bytes"); ++ return mem->used > 0 ? 0 : -1; ++} ++ ++static int cg2_mem_stats(struct lxc_container *c, struct mem_stats *mem) ++{ ++ mem->used = stat_get_int(c, "memory.current"); ++ mem->limit = stat_get_int(c, "memory.max"); ++ mem->swap_used = stat_get_int(c, "memory.swap.current"); ++ mem->swap_limit = stat_get_int(c, "memory.swap.max"); ++ /* TODO: find the kernel usage */ ++ mem->kmem_used = 0; ++ /* does not exist in cgroup v2 */ ++ mem->kmem_limit = 0; ++ return mem->used > 0 ? 0 : -1; + } + + static void cg1_cpu_stats(struct lxc_container *c, struct cpu_stats *cpu) +@@ -342,7 +355,11 @@ static void cg1_cpu_stats(struct lxc_container *c, struct cpu_stats *cpu) + static void stats_get(struct lxc_container *c, struct container_stats *ct, struct stats *total) + { + ct->c = c; +- cg1_mem_stats(c, &ct->stats->mem); ++ if (cg1_mem_stats(c, &ct->stats->mem) < 0) { ++ if (cg2_mem_stats(c, &ct->stats->mem) < 0) { ++ fprintf(stderr, "Unable to read memory stats\n"); ++ } ++ } + cg1_cpu_stats(c, &ct->stats->cpu); + stat_get_blk_stats(c, "blkio.throttle.io_service_bytes", &ct->stats->io_service_bytes); + stat_get_blk_stats(c, "blkio.throttle.io_serviced", &ct->stats->io_serviced); +-- +2.45.2 + + +From df219e84ca11294ba29ff9e85d09f4190942b30c Mon Sep 17 00:00:00 2001 +From: Natanael Copa <ncopa@alpinelinux.org> +Date: Wed, 24 Jul 2024 16:32:30 +0200 +Subject: [PATCH 3/5] lxc-top: CPU stats for cgroups2 + +Recalculate the usec to nanoseconds and USER_HZ + +Signed-off-by: Natanael Copa <ncopa@alpinelinux.org> +--- + src/lxc/tools/lxc_top.c | 21 ++++++++++++++++++--- + 1 file changed, 18 insertions(+), 3 deletions(-) + +diff --git a/src/lxc/tools/lxc_top.c b/src/lxc/tools/lxc_top.c +index 29d81563f..3a6c49e82 100644 +--- a/src/lxc/tools/lxc_top.c ++++ b/src/lxc/tools/lxc_top.c +@@ -230,7 +230,6 @@ static uint64_t stat_match_get_int(struct lxc_container *c, const char *item, + + len = c->get_cgroup_item(c, item, buf, sizeof(buf)); + if (len <= 0) { +- fprintf(stderr, "Unable to read cgroup item %s\n", item); + goto out; + } + +@@ -345,11 +344,22 @@ static int cg2_mem_stats(struct lxc_container *c, struct mem_stats *mem) + return mem->used > 0 ? 0 : -1; + } + +-static void cg1_cpu_stats(struct lxc_container *c, struct cpu_stats *cpu) ++static int cg1_cpu_stats(struct lxc_container *c, struct cpu_stats *cpu) + { + cpu->use_nanos = stat_get_int(c, "cpuacct.usage"); + cpu->use_user = stat_match_get_int(c, "cpuacct.stat", "user", 1); + cpu->use_sys = stat_match_get_int(c, "cpuacct.stat", "system", 1); ++ return cpu->use_nanos > 0 ? 0 : -1; ++} ++ ++static int cg2_cpu_stats(struct lxc_container *c, struct cpu_stats *cpu) ++{ ++ /* convert microseconds to nanoseconds */ ++ cpu->use_nanos = stat_match_get_int(c, "cpu.stat", "usage_usec", 1) * 1000; ++ ++ cpu->use_user = stat_match_get_int(c, "cpu.stat", "user_usec", 1) * USER_HZ / 1000000; ++ cpu->use_sys = stat_match_get_int(c, "cpu.stat", "system_usec", 1) * USER_HZ / 1000000; ++ return cpu->use_nanos > 0 ? 0 : -1; + } + + static void stats_get(struct lxc_container *c, struct container_stats *ct, struct stats *total) +@@ -360,7 +370,12 @@ static void stats_get(struct lxc_container *c, struct container_stats *ct, struc + fprintf(stderr, "Unable to read memory stats\n"); + } + } +- cg1_cpu_stats(c, &ct->stats->cpu); ++ if (cg1_cpu_stats(c, &ct->stats->cpu) < 0) { ++ if (cg2_cpu_stats(c, &ct->stats->cpu) < 0) { ++ fprintf(stderr, "Unable to read CPU stats\n"); ++ } ++ } ++ + stat_get_blk_stats(c, "blkio.throttle.io_service_bytes", &ct->stats->io_service_bytes); + stat_get_blk_stats(c, "blkio.throttle.io_serviced", &ct->stats->io_serviced); + +-- +2.45.2 + + +From 094f05141db5968f8e3a855e4230579b12721a65 Mon Sep 17 00:00:00 2001 +From: Natanael Copa <ncopa@alpinelinux.org> +Date: Wed, 24 Jul 2024 16:54:00 +0200 +Subject: [PATCH 4/5] tools: lxc-top: get the user HZ at runtime + +The USER_HZ depends on the kernel configuration. Get it run-time instead +of assume it is 100 HZ. + +Signed-off-by: Natanael Copa <ncopa@alpinelinux.org> +--- + src/lxc/tools/lxc_top.c | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +diff --git a/src/lxc/tools/lxc_top.c b/src/lxc/tools/lxc_top.c +index 3a6c49e82..deea1b41d 100644 +--- a/src/lxc/tools/lxc_top.c ++++ b/src/lxc/tools/lxc_top.c +@@ -22,7 +22,6 @@ + #include "mainloop.h" + #include "utils.h" + +-#define USER_HZ 100 + #define ESC "\033" + #define TERMCLEAR ESC "[H" ESC "[J" + #define TERMNORM ESC "[0m" +@@ -70,6 +69,7 @@ static int sort_reverse = 0; + static struct termios oldtios; + static struct container_stats *container_stats = NULL; + static int ct_alloc_cnt = 0; ++static long user_hz = 0; + + static int my_parser(struct lxc_arguments *args, int c, char *arg) + { +@@ -357,8 +357,8 @@ static int cg2_cpu_stats(struct lxc_container *c, struct cpu_stats *cpu) + /* convert microseconds to nanoseconds */ + cpu->use_nanos = stat_match_get_int(c, "cpu.stat", "usage_usec", 1) * 1000; + +- cpu->use_user = stat_match_get_int(c, "cpu.stat", "user_usec", 1) * USER_HZ / 1000000; +- cpu->use_sys = stat_match_get_int(c, "cpu.stat", "system_usec", 1) * USER_HZ / 1000000; ++ cpu->use_user = stat_match_get_int(c, "cpu.stat", "user_usec", 1) * user_hz / 1000000; ++ cpu->use_sys = stat_match_get_int(c, "cpu.stat", "system_usec", 1) * user_hz / 1000000; + return cpu->use_nanos > 0 ? 0 : -1; + } + +@@ -448,8 +448,8 @@ static void stats_print(const char *name, const struct stats *stats, + printf("%-18.18s %12.2f %12.2f %12.2f %36s %10s", + name, + (float)stats->cpu.use_nanos / 1000000000, +- (float)stats->cpu.use_sys / USER_HZ, +- (float)stats->cpu.use_user / USER_HZ, ++ (float)stats->cpu.use_sys / user_hz, ++ (float)stats->cpu.use_user / user_hz, + iosb_str, + mem_used_str); + +@@ -640,6 +640,11 @@ int lxc_top_main(int argc, char *argv[]) + signal(SIGINT, sig_handler); + signal(SIGQUIT, sig_handler); + ++ user_hz = sysconf(_SC_CLK_TCK); ++ if (user_hz == 0) { ++ user_hz = 100; ++ } ++ + if (lxc_mainloop_open(&descr)) { + fprintf(stderr, "Failed to create mainloop\n"); + goto out; +-- +2.45.2 + + +From cf8f1e067f9be356f9879566ddfa31333929af22 Mon Sep 17 00:00:00 2001 +From: Natanael Copa <ncopa@alpinelinux.org> +Date: Wed, 24 Jul 2024 17:29:10 +0200 +Subject: [PATCH 5/5] tools: lxc-top: add cgroups2 IO stats + +Signed-off-by: Natanael Copa <ncopa@alpinelinux.org> +--- + src/lxc/tools/lxc_top.c | 60 ++++++++++++++++++++++++++++++++++++----- + 1 file changed, 53 insertions(+), 7 deletions(-) + +diff --git a/src/lxc/tools/lxc_top.c b/src/lxc/tools/lxc_top.c +index deea1b41d..6cc54988d 100644 +--- a/src/lxc/tools/lxc_top.c ++++ b/src/lxc/tools/lxc_top.c +@@ -281,21 +281,21 @@ examples: + 8:0 Total 149327872 Total 149327872 */ - static void stat_get_blk_stats(struct lxc_container *c, const char *item, -- struct blkio_stats *stats) { -+ struct blkio_stats *stats, bool *success) { +-static void stat_get_blk_stats(struct lxc_container *c, const char *item, ++static int cg1_get_blk_stats(struct lxc_container *c, const char *item, + struct blkio_stats *stats) { char buf[4096]; int i, len; char **lines, **cols; -+ *success = true; ++ int ret = -1; len = c->get_cgroup_item(c, item, buf, sizeof(buf)); if (len <= 0 || (size_t)len >= sizeof(buf)) { - fprintf(stderr, "Unable to read cgroup item %s\n", item); -+ *success = false; - return; +- fprintf(stderr, "Unable to read cgroup item %s\n", item); +- return; ++ return ret; } lines = lxc_string_split_and_trim(buf, '\n'); -- if (!lines) -+ if (!lines) { -+ *success = false; - return; -+ } + if (!lines) +- return; ++ return ret; memset(stats, 0, sizeof(struct blkio_stats)); - for (i = 0; lines[i]; i++) { - cols = lxc_string_split_and_trim(lines[i], ' '); -- if (!cols) -+ if (!cols) { -+ *success = false; - goto out; -+ } - - if (strncmp(cols[1], "Read", strlen(cols[1])) == 0) - stats->read += strtoull(cols[2], NULL, 0); -@@ -314,21 +320,53 @@ static void stat_get_blk_stats(struct lxc_container *c, const char *item, - return; - } +@@ -314,10 +314,50 @@ static void stat_get_blk_stats(struct lxc_container *c, const char *item, -+static void try_cgroup2(struct lxc_container *c, u_int64_t *stat, const char* path_cgroup1, const char* path_cgroup2, -+ const char* match, bool call_match) { -+ -+ int ret_cgroup2; -+ -+ if (call_match) { -+ ret_cgroup2 = stat_match_get_int(c, path_cgroup2, match, 1); -+ if (ret_cgroup2 < 0) { -+ *stat = stat_match_get_int(c, path_cgroup1, match, 1); -+ } -+ -+ } else { -+ ret_cgroup2 = stat_get_int(c, path_cgroup2); -+ -+ if (ret_cgroup2 < 0) { -+ *stat = stat_get_int(c, path_cgroup1); -+ } else { -+ *stat = ret_cgroup2; -+ } -+ } + lxc_free_array((void **)cols, free); + } ++ ret = 0; ++out: ++ lxc_free_array((void **)lines, free); ++ return ret; +} + ++static int cg2_get_blk_stats(struct lxc_container *c, const char *item, ++ struct blkio_stats *stats) { ++ char buf[4096]; ++ int i, j, len; ++ char **lines, **cols; ++ int ret = -1; + - static void stats_get(struct lxc_container *c, struct container_stats *ct, struct stats *total) - { - ct->c = c; -- ct->stats->mem_used = stat_get_int(c, "memory.usage_in_bytes"); -- ct->stats->mem_limit = stat_get_int(c, "memory.limit_in_bytes"); -- ct->stats->memsw_used = stat_get_int(c, "memory.memsw.usage_in_bytes"); -- ct->stats->memsw_limit = stat_get_int(c, "memory.memsw.limit_in_bytes"); -+ -+ // handle stat_get_int cases -+ try_cgroup2(c, &(ct->stats->mem_used), "memory.usage_in_bytes", "memory.current", NULL, false); -+ try_cgroup2(c, &(ct->stats->mem_limit), "memory.limit_in_bytes", "memory.max", NULL, false); -+ try_cgroup2(c, &(ct->stats->memsw_used), "memory.memsw.usage_in_bytes", "memory.swap.current", NULL, false); -+ try_cgroup2(c, &(ct->stats->memsw_limit), "memory.memsw.limit_in_bytes", "memory.swap.max", NULL, false); -+ try_cgroup2(c, &(ct->stats->cpu_use_nanos), "cpuacct.usage", "cpu.stat", NULL, false); -+ try_cgroup2(c, &(ct->stats->cpu_use_user), "cpuacct.stat", "cpu.stat", "user", true); -+ try_cgroup2(c, &(ct->stats->cpu_use_sys), "cpuacct.stat", "cpu.stat", "system", true); -+ -+ // singular cgroup2 case for get blk stats -+ bool success; -+ stat_get_blk_stats(c, "io.stat", &ct->stats->io_service_bytes, &success); -+ if (!success) { -+ stat_get_blk_stats(c, "blkio.throttle.io_service_bytes", &ct->stats->io_service_bytes, &success); ++ len = c->get_cgroup_item(c, item, buf, sizeof(buf)); ++ if (len <= 0 || (size_t)len >= sizeof(buf)) { ++ return ret; + } + -+ // paths only exist in cgroup1 - ct->stats->kmem_used = stat_get_int(c, "memory.kmem.usage_in_bytes"); - ct->stats->kmem_limit = stat_get_int(c, "memory.kmem.limit_in_bytes"); -- ct->stats->cpu_use_nanos = stat_get_int(c, "cpuacct.usage"); -- ct->stats->cpu_use_user = stat_match_get_int(c, "cpuacct.stat", "user", 1); -- ct->stats->cpu_use_sys = stat_match_get_int(c, "cpuacct.stat", "system", 1); -- ++ lines = lxc_string_split_and_trim(buf, '\n'); ++ if (!lines) ++ return ret; ++ ++ memset(stats, 0, sizeof(struct blkio_stats)); ++ ++ for (i = 0; lines[i]; i++) { ++ cols = lxc_string_split_and_trim(lines[i], ' '); ++ if (!cols) ++ goto out; + ++ for (j = 0; cols[j]; j++) { ++ if (strncmp(cols[j], "rbytes=", 7) == 0) { ++ stats->read += strtoull(&cols[j][7], NULL, 0); ++ } else if (strncmp(cols[j], "wbytes=", 7) == 0) { ++ stats->write += strtoull(&cols[j][7], NULL, 0); ++ } ++ } ++ ++ lxc_free_array((void **)cols, free); ++ } ++ stats->total = stats->read + stats->write; ++ ret = 0; + out: + lxc_free_array((void **)lines, free); +- return; ++ return ret; + } + + static int cg1_mem_stats(struct lxc_container *c, struct mem_stats *mem) +@@ -376,8 +416,14 @@ static void stats_get(struct lxc_container *c, struct container_stats *ct, struc + } + } + - stat_get_blk_stats(c, "blkio.throttle.io_service_bytes", &ct->stats->io_service_bytes); - stat_get_blk_stats(c, "blkio.throttle.io_serviced", &ct->stats->io_serviced); -+ stat_get_blk_stats(c, "blkio.throttle.io_serviced", &ct->stats->io_serviced, &success); ++ if (cg1_get_blk_stats(c, "blkio.throttle.io_service_bytes", &ct->stats->io_service_bytes) < 0) { ++ if (cg2_get_blk_stats(c, "io.stat", &ct->stats->io_service_bytes) < 0) { ++ fprintf(stderr, "Unable to read CPU stats\n"); ++ } ++ } else { ++ /* only with cgroups v1 */ ++ cg1_get_blk_stats(c, "blkio.throttle.io_serviced", &ct->stats->io_serviced); ++ } if (total) { - total->mem_used = total->mem_used + ct->stats->mem_used; + total->mem.used += ct->stats->mem.used; +-- +2.45.2 + |