From fb0ad18d3a783526a219cde7c1f7b00d6a29c7c2 Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Mon, 15 Dec 2025 16:58:35 +0100 Subject: [PATCH] initctl: add CPU throttled information alongside memory usage Signed-off-by: Joachim Wiberg --- src/cgutil.c | 35 +++++++++++++++++++++++++++++++++++ src/cgutil.h | 1 + src/initctl.c | 30 +++++++++++++++++++++++++++++- 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/cgutil.c b/src/cgutil.c index b8eed025..04901053 100644 --- a/src/cgutil.c +++ b/src/cgutil.c @@ -252,6 +252,41 @@ uint64_t cgroup_memory(char *group) return cgroup_uint64(path, "memory.current"); } +int cgroup_throttle(char *group, uint64_t *throttled_usec, uint64_t *nr_throttled) +{ + char path[256]; + char buf[256]; + FILE *fp; + int found = 0; + + paste(path, sizeof(path), FINIT_CGPATH, group); + + fp = fopenf("r", "%s/cpu.stat", path); + if (!fp) + return -1; + + *throttled_usec = 0; + *nr_throttled = 0; + + while (fgets(buf, sizeof(buf), fp)) { + chomp(buf); + + if (!strncmp(buf, "throttled_usec", 14)) { + *throttled_usec = strtoull(&buf[15], NULL, 10); + found++; + } else if (!strncmp(buf, "nr_throttled", 12)) { + *nr_throttled = strtoull(&buf[13], NULL, 10); + found++; + } + + if (found == 2) + break; + } + + fclose(fp); + return 0; +} + static float cgroup_cpuload(struct cg *cg) { char fn[256]; diff --git a/src/cgutil.h b/src/cgutil.h index c7b5e9ca..1f3d55d3 100644 --- a/src/cgutil.h +++ b/src/cgutil.h @@ -58,6 +58,7 @@ char *pid_cmdline (int pid); char *pid_cgroup (int pid); uint64_t cgroup_memory(char *group); +int cgroup_throttle(char *group, uint64_t *throttled_usec, uint64_t *nr_throttled); struct cg *cg_stats(char *path); struct cg *cg_conf (char *path); diff --git a/src/initctl.c b/src/initctl.c index 50fc4276..b20b1f10 100644 --- a/src/initctl.c +++ b/src/initctl.c @@ -1015,6 +1015,7 @@ static int json_status_one(FILE *fp, svc_t *svc, char *indent, int prev) indent, svc_typestr(svc), indent, svc->forking ? "true" : "false", indent, svc_status(svc)); + if (svc->state != SVC_RUNNING_STATE) { int rc, sig; @@ -1030,30 +1031,48 @@ static int json_status_one(FILE *fp, svc_t *svc, char *indent, int prev) "%s \"exit\": { \"%s\": %d },\n", indent, "signal", sig); } + fprintf(fp, "%s \"origin\": \"%s\",\n" "%s \"command\": \"%s\",\n", indent, svc->file[0] ? svc->file : "built-in", indent, svc_command(svc, buf, sizeof(buf), 0)); + svc_environ(svc, buf, sizeof(buf), 0); if (buf[0]) fprintf(fp, "%s \"environment\": \"%s\",\n", indent, buf); + svc_cond(svc, buf, sizeof(buf), 0); if (buf[0]) fprintf(fp, "%s \"condition\": %s,\n", indent, buf); + if (svc->manual) fprintf(fp, "%s \"starts\": %d,\n", indent, svc->once); + fprintf(fp, "%s \"restarts\": %d,\n", indent, svc->restart_tot); /* XXX: add restart_cnt and restart_max */ - /* Add memory information if cgroup support is available */ + /* Add memory and CPU information if cgroup support is available */ if (cgrp && svc->pid > 1) { char *group = pid_cgroup(svc->pid); + if (group) { + uint64_t throttled_usec = 0; + uint64_t nr_throttled = 0; + + fprintf(fp, "%s \"cgroup\": \"%s\",\n", indent, group); fprintf(fp, "%s \"memory\": %lu,\n", indent, cgroup_memory(group)); + + if (cgroup_throttle(group, &throttled_usec, &nr_throttled) == 0) { + fprintf(fp, "%s \"cpu\": {\n", indent); + fprintf(fp, "%s \"throttled_usec\": %lu,\n", indent, throttled_usec); + fprintf(fp, "%s \"nr_throttled\": %lu\n", indent, nr_throttled); + fprintf(fp, "%s },\n", indent); + } + free(group); } } @@ -1144,8 +1163,11 @@ static int show_status(char *arg) printf(" Starts : %d\n", svc->once); printf(" Restarts : %d (%d/%d)\n", svc->restart_tot, svc->restart_cnt, svc->restart_max); printf(" Runlevels : %s\n", runlevel_string(runlevel, svc->runlevels)); + if (cgrp && svc->pid > 1) { const struct cg *cg; + uint64_t throttled_usec = 0; + uint64_t nr_throttled = 0; char path[256]; char *group; @@ -1157,6 +1179,12 @@ static int show_status(char *arg) cg = cg_conf(path); printf(" Memory : %s\n", memsz(cgroup_memory(group), uptm, sizeof(uptm))); + + if (cgroup_throttle(group, &throttled_usec, &nr_throttled) == 0) { + printf("CPU Throttle : %lu usec (%lu times)\n", + throttled_usec, nr_throttled); + } + printf(" CGroup : %s cpu %s [%s, %s] mem [%s, %s]\n", group, cg->cg_cpu.set, cg->cg_cpu.weight, cg->cg_cpu.max, cg->cg_mem.min, cg->cg_mem.max);