[lxc-devel] [lxcfs/master] CPU views based on quotas: several improvements
BurningXFlame on Github
lxc-bot at linuxcontainers.org
Mon Jun 10 07:29:21 UTC 2019
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 2302 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190610/4e31b3f7/attachment.bin>
-------------- next part --------------
From 63800363bb72cfc83d23523ffc673ec33e9b5aba Mon Sep 17 00:00:00 2001
From: Stephen Xiang <>
Date: Fri, 24 May 2019 14:56:13 +0800
Subject: [PATCH 1/3] fall back to cpuacct.usage_percpu if cpuacct.usage_all
not exists
---
.gitignore | 1 +
Makefile.am | 7 ++-
bindings.c | 48 ++++++++++++++--
macro.h | 6 ++
sb.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++++
sb.h | 57 +++++++++++++++++++
6 files changed, 273 insertions(+), 7 deletions(-)
create mode 100644 sb.c
create mode 100644 sb.h
diff --git a/.gitignore b/.gitignore
index 95b724c..6e2130c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,3 +35,4 @@ lxcfs-*.tar.gz
.libs
*.lo
*.la
+.vscode
\ No newline at end of file
diff --git a/Makefile.am b/Makefile.am
index 99cbb36..4a76467 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -8,18 +8,21 @@ AM_CFLAGS += $(FUSE_CFLAGS)
AM_CFLAGS += -DLIBDIR=\"$(LIBDIR)\"
AM_LDFLAGS = $(FUSE_LIBS) -pthread
#AM_CFLAGS += -DDEBUG
+AM_CFLAGS += -DVERBOSE
AM_CFLAGS += -DRUNTIME_PATH=\"$(RUNTIME_PATH)\"
liblxcfs_la_SOURCES = bindings.c bindings.h \
cpuset.c \
- sysfs_fuse.c syfs_fuse.h
+ sysfs_fuse.c syfs_fuse.h \
+ sb.c sb.h
liblxcfs_la_CFLAGS = $(AM_CFLAGS)
liblxcfs_la_LDFLAGS = $(AM_CFLAGS) -module -avoid-version -shared
liblxcfstest_la_SOURCES = bindings.c bindings.h \
cpuset.c \
- sysfs_fuse.c syfs_fuse.h
+ sysfs_fuse.c syfs_fuse.h \
+ sb.c sb.h
liblxcfstest_la_CFLAGS = $(AM_CFLAGS) -DRELOADTEST
liblxcfstest_la_LDFLAGS = $(AM_CFLAGS) -module -avoid-version -shared
diff --git a/bindings.c b/bindings.c
index a948a5d..7c68691 100644
--- a/bindings.c
+++ b/bindings.c
@@ -38,6 +38,7 @@
#include "bindings.h"
#include "config.h" // for VERSION
+#include "sb.h"
/* Define pivot_root() if missing from the C library */
#ifndef HAVE_PIVOT_ROOT
@@ -1155,6 +1156,7 @@ bool cgfs_get_value(const char *controller, const char *cgroup, const char *file
char *fnam, *tmpc;
tmpc = find_mounted_controller(controller, &cfd);
+ lxcfs_v("tmpc: %s\n", tmpc);
if (!tmpc)
return false;
@@ -1164,6 +1166,7 @@ bool cgfs_get_value(const char *controller, const char *cgroup, const char *file
len = strlen(cgroup) + strlen(file) + 3;
fnam = alloca(len);
ret = snprintf(fnam, len, "%s%s/%s", *cgroup == '/' ? "." : "", cgroup, file);
+ lxcfs_v("fnam: %s\n", fnam);
if (ret < 0 || (size_t)ret >= len)
return false;
@@ -1172,6 +1175,7 @@ bool cgfs_get_value(const char *controller, const char *cgroup, const char *file
return false;
*value = slurp_file(fnam, fd);
+ lxcfs_v("*value: %s\n", *value);
return *value != NULL;
}
@@ -3738,9 +3742,11 @@ static int proc_cpuinfo_read(char *buf, size_t size, off_t offset,
}
pid_t initpid = lookup_initpid_in_store(fc->pid);
+ lxcfs_v("initpid: %d\n", initpid);
if (initpid <= 0)
initpid = fc->pid;
cg = get_pid_cgroup(initpid, "cpuset");
+ lxcfs_v("cg: %s\n", cg);
if (!cg)
return read_file("proc/cpuinfo", buf, size, d);
prune_init_slice(cg);
@@ -3750,9 +3756,11 @@ static int proc_cpuinfo_read(char *buf, size_t size, off_t offset,
goto err;
use_view = use_cpuview(cg);
+ lxcfs_v("use_view: %d\n", use_view);
if (use_view)
max_cpus = max_cpu_count(cg);
+ lxcfs_v("max_cpus: %d\n", max_cpus);
f = fopen("/proc/cpuinfo", "r");
if (!f)
@@ -4034,7 +4042,7 @@ static int read_cpuacct_usage_all(char *cg, char *cpuset, struct cpuacct_usage *
ticks_per_sec = sysconf(_SC_CLK_TCK);
if (ticks_per_sec < 0 && errno == EINVAL) {
- lxcfs_debug(
+ lxcfs_v(
"%s\n",
"read_cpuacct_usage_all failed to determine number of clock ticks "
"in a second");
@@ -4042,12 +4050,40 @@ static int read_cpuacct_usage_all(char *cg, char *cpuset, struct cpuacct_usage *
}
cpu_usage = malloc(sizeof(struct cpuacct_usage) * cpucount);
+ bzero(cpu_usage,sizeof(struct cpuacct_usage) * cpucount);
if (!cpu_usage)
return -ENOMEM;
if (!cgfs_get_value("cpuacct", cg, "cpuacct.usage_all", &usage_str)) {
- rv = -1;
- goto err;
+ lxcfs_v("failed to read cpuacct.usage_all. usage_str: %s\n", usage_str);
+
+ // read cpuacct.usage_percpu instead
+ lxcfs_v("reading cpuacct.usage_percpu instead%s\n", "");
+ if (!cgfs_get_value("cpuacct", cg, "cpuacct.usage_percpu", &usage_str)) {
+ rv = -1;
+ goto err;
+ }
+ lxcfs_v("usage_str: %s\n", usage_str);
+
+ // convert cpuacct.usage_percpu into cpuacct.usage_all
+ lxcfs_v("converting cpuacct.usage_percpu into cpuacct.usage_all%s\n", "");
+ StringBuilder *sb = sb_create();
+ sb_append(sb, "cpu user system\n");
+ int i = 0;
+ while(sscanf(usage_str + read_pos, "%lu %n", &cg_user, &read_cnt) > 0){
+ lxcfs_v("i: %d, cg_user: %lu, read_pos: %d, read_cnt: %d\n", i, cg_user, read_pos, read_cnt);
+ sb_appendf(sb, "%d %lu %lu\n", i, cg_user, 0);
+ i++;
+ read_pos += read_cnt;
+ }
+
+ free(usage_str);
+ usage_str = sb_concat(sb);
+ sb_free(sb);
+ read_pos=0;
+ read_cnt=0;
+
+ lxcfs_v("usage_str: %s\n", usage_str);
}
if (sscanf(usage_str, "cpu user system\n%n", &read_cnt) != 0) {
@@ -4770,9 +4806,11 @@ static int proc_stat_read(char *buf, size_t size, off_t offset,
}
pid_t initpid = lookup_initpid_in_store(fc->pid);
+ lxcfs_v("initpid: %d\n", initpid);
if (initpid <= 0)
initpid = fc->pid;
cg = get_pid_cgroup(initpid, "cpuset");
+ lxcfs_v("cg: %s\n", cg);
if (!cg)
return read_file("/proc/stat", buf, size, d);
prune_init_slice(cg);
@@ -4787,7 +4825,7 @@ static int proc_stat_read(char *buf, size_t size, off_t offset,
* CPU usage. If not, values from the host's /proc/stat are used.
*/
if (read_cpuacct_usage_all(cg, cpuset, &cg_cpu_usage, &cg_cpu_usage_size) != 0) {
- lxcfs_debug("%s\n", "proc_stat_read failed to read from cpuacct, "
+ lxcfs_v("%s\n", "proc_stat_read failed to read from cpuacct, "
"falling back to the host's /proc/stat");
}
@@ -6291,4 +6329,4 @@ static void __attribute__((destructor)) free_subsystems(void)
if (cgroup_mount_ns_fd >= 0)
close(cgroup_mount_ns_fd);
-}
+}
\ No newline at end of file
diff --git a/macro.h b/macro.h
index 1763dc2..7213b8f 100644
--- a/macro.h
+++ b/macro.h
@@ -15,4 +15,10 @@
#define lxcfs_debug(format, ...)
#endif /* DEBUG */
+#ifdef VERBOSE
+#define lxcfs_v(format, ...) lxcfs_error(format, __VA_ARGS__);
+#else
+#define lxcfs_v(format, ...)
+#endif /* VERBOSE */
+
#endif /* __LXCFS_MACRO_H */
diff --git a/sb.c b/sb.c
new file mode 100644
index 0000000..5b5bf9a
--- /dev/null
+++ b/sb.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2017 Ryan Armstrong <ryan at cavaliercoder.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * C String Builder - https://github.com/cavaliercoder/c-stringbuilder
+ *
+ * sb.c is a simple, non-thread safe String Builder that makes use of a
+ * dynamically-allocated linked-list to enable linear time appending and
+ * concatenation.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include "sb.h"
+
+/*
+ * sb_create returns a pointer to a new StringBuilder or NULL if memory is not
+ * available.
+ */
+StringBuilder *sb_create()
+{
+ StringBuilder *sb = (StringBuilder*) calloc(sizeof(StringBuilder), 1);
+ return sb;
+}
+
+/*
+ * sb_empty returns non-zero if the given StringBuilder is empty.
+ */
+int sb_empty(StringBuilder *sb)
+{
+ return (sb->root == NULL);
+}
+
+/*
+ * sb_append adds a copy of the given string to a StringBuilder.
+ */
+int sb_append(StringBuilder *sb, const char *str)
+{
+ int length = 0;
+ StringFragment *frag = NULL;
+
+ if (NULL == str || '\0' == *str)
+ return sb->length;
+
+ length = strlen(str);
+ frag = (StringFragment*) malloc(sizeof(StringFragment) + (sizeof(char) * length));
+ if (NULL == frag)
+ return SB_FAILURE;
+
+ frag->next = NULL;
+ frag->length = length;
+ memcpy((void*) &frag->str, (const void*) str, sizeof(char) * (length + 1));
+
+ sb->length += length;
+ if (NULL == sb->root)
+ sb->root = frag;
+ else
+ sb->trunk->next = frag;
+
+ sb->trunk = frag;
+
+ return sb->length;
+}
+
+/*
+ * sb_appendf adds a copy of the given formatted string to a StringBuilder.
+ */
+int sb_appendf(StringBuilder *sb, const char *format, ...)
+{
+ int rc = 0;
+ char buf[SB_MAX_FRAG_LENGTH];
+ va_list args;
+
+ va_start (args, format);
+ rc = vsnprintf(&buf[0], SB_MAX_FRAG_LENGTH, format, args);
+ va_end(args);
+
+ if (0 > rc)
+ return SB_FAILURE;
+
+ return sb_append(sb, buf);
+}
+
+/*
+ * sb_concat returns a concatenation of strings that have been appended to the
+ * StringBuilder. It is the callers responsibility to free the returned
+ * reference.
+ *
+ * The StringBuilder is not modified by this function and can therefore continue
+ * to be used.
+ */
+char *sb_concat(StringBuilder *sb)
+{
+ char *buf = NULL;
+ char *c = NULL;
+ StringFragment *frag = NULL;
+
+ buf = (char *) malloc((sb->length + 1) * sizeof(char));
+ if (NULL == buf)
+ return NULL;
+
+ c = buf;
+ for (frag = sb->root; frag; frag = frag->next) {
+ memcpy(c, &frag->str, sizeof(char) * frag->length);
+ c += frag->length;
+ }
+
+ *c = '\0';
+
+ return buf;
+}
+
+/*
+ * sb_reset resets the given StringBuilder, freeing all previously appended
+ * strings.
+ */
+void sb_reset(StringBuilder *sb)
+{
+ StringFragment *frag = NULL;
+ StringFragment *next = NULL;
+
+ frag = sb->root;
+ while(frag) {
+ next = frag->next;
+ free(frag);
+ frag = next;
+ }
+
+ sb->root = NULL;
+ sb->trunk = NULL;
+ sb->length = 0;
+}
+
+/*
+ * sb_free frees the given StringBuilder and all of its appended strings.
+ */
+void sb_free(StringBuilder *sb)
+{
+ sb_reset(sb);
+ free(sb);
+}
diff --git a/sb.h b/sb.h
new file mode 100644
index 0000000..2c18d4c
--- /dev/null
+++ b/sb.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2017 Ryan Armstrong <ryan at cavaliercoder.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * C String Builder - https://github.com/cavaliercoder/c-stringbuilder
+ *
+ * sb.c is a simple, non-thread safe String Builder that makes use of a
+ * dynamically-allocated linked-list to enable linear time appending and
+ * concatenation.
+ */
+
+#ifndef SB_H
+#define SB_H
+
+#define SB_FAILURE -1
+#define SB_MAX_FRAG_LENGTH 4096
+
+typedef struct _StringFragment {
+ struct _StringFragment *next;
+ int length;
+ char *str;
+} StringFragment;
+
+typedef struct _StringBuilder {
+ struct _StringFragment *root;
+ struct _StringFragment *trunk;
+ int length;
+} StringBuilder;
+
+StringBuilder *sb_create();
+int sb_empty(StringBuilder *sb);
+int sb_append(StringBuilder *sb, const char *str);
+int sb_appendf(StringBuilder *sb, const char *format, ...);
+char *sb_concat(StringBuilder *sb);
+void sb_reset(StringBuilder *sb);
+void sb_free(StringBuilder *sb);
+
+#endif
From 4a9893e24162d740416ac6f90951c6b1f670a392 Mon Sep 17 00:00:00 2001
From: Stephen Xiang <>
Date: Mon, 27 May 2019 17:18:49 +0800
Subject: [PATCH 2/3] bugfix: cpuview_proc_stat: statistic bug of cpu usage
---
bindings.c | 36 +++++++++++++++++-------------------
1 file changed, 17 insertions(+), 19 deletions(-)
diff --git a/bindings.c b/bindings.c
index 7c68691..506f75e 100644
--- a/bindings.c
+++ b/bindings.c
@@ -1156,7 +1156,7 @@ bool cgfs_get_value(const char *controller, const char *cgroup, const char *file
char *fnam, *tmpc;
tmpc = find_mounted_controller(controller, &cfd);
- lxcfs_v("tmpc: %s\n", tmpc);
+ lxcfs_debug("tmpc: %s\n", tmpc);
if (!tmpc)
return false;
@@ -1166,7 +1166,7 @@ bool cgfs_get_value(const char *controller, const char *cgroup, const char *file
len = strlen(cgroup) + strlen(file) + 3;
fnam = alloca(len);
ret = snprintf(fnam, len, "%s%s/%s", *cgroup == '/' ? "." : "", cgroup, file);
- lxcfs_v("fnam: %s\n", fnam);
+ lxcfs_debug("fnam: %s\n", fnam);
if (ret < 0 || (size_t)ret >= len)
return false;
@@ -1175,7 +1175,7 @@ bool cgfs_get_value(const char *controller, const char *cgroup, const char *file
return false;
*value = slurp_file(fnam, fd);
- lxcfs_v("*value: %s\n", *value);
+ lxcfs_debug("*value: %s\n", *value);
return *value != NULL;
}
@@ -3742,11 +3742,9 @@ static int proc_cpuinfo_read(char *buf, size_t size, off_t offset,
}
pid_t initpid = lookup_initpid_in_store(fc->pid);
- lxcfs_v("initpid: %d\n", initpid);
if (initpid <= 0)
initpid = fc->pid;
cg = get_pid_cgroup(initpid, "cpuset");
- lxcfs_v("cg: %s\n", cg);
if (!cg)
return read_file("proc/cpuinfo", buf, size, d);
prune_init_slice(cg);
@@ -3756,11 +3754,9 @@ static int proc_cpuinfo_read(char *buf, size_t size, off_t offset,
goto err;
use_view = use_cpuview(cg);
- lxcfs_v("use_view: %d\n", use_view);
if (use_view)
max_cpus = max_cpu_count(cg);
- lxcfs_v("max_cpus: %d\n", max_cpus);
f = fopen("/proc/cpuinfo", "r");
if (!f)
@@ -4063,7 +4059,6 @@ static int read_cpuacct_usage_all(char *cg, char *cpuset, struct cpuacct_usage *
rv = -1;
goto err;
}
- lxcfs_v("usage_str: %s\n", usage_str);
// convert cpuacct.usage_percpu into cpuacct.usage_all
lxcfs_v("converting cpuacct.usage_percpu into cpuacct.usage_all%s\n", "");
@@ -4071,7 +4066,7 @@ static int read_cpuacct_usage_all(char *cg, char *cpuset, struct cpuacct_usage *
sb_append(sb, "cpu user system\n");
int i = 0;
while(sscanf(usage_str + read_pos, "%lu %n", &cg_user, &read_cnt) > 0){
- lxcfs_v("i: %d, cg_user: %lu, read_pos: %d, read_cnt: %d\n", i, cg_user, read_pos, read_cnt);
+ lxcfs_debug("i: %d, cg_user: %lu, read_pos: %d, read_cnt: %d\n", i, cg_user, read_pos, read_cnt);
sb_appendf(sb, "%d %lu %lu\n", i, cg_user, 0);
i++;
read_pos += read_cnt;
@@ -4083,7 +4078,7 @@ static int read_cpuacct_usage_all(char *cg, char *cpuset, struct cpuacct_usage *
read_pos=0;
read_cnt=0;
- lxcfs_v("usage_str: %s\n", usage_str);
+ lxcfs_debug("usage_str: %s\n", usage_str);
}
if (sscanf(usage_str, "cpu user system\n%n", &read_cnt) != 0) {
@@ -4599,14 +4594,14 @@ static int cpuview_proc_stat(const char *cg, const char *cpuset, struct cpuacct_
threshold = total_sum / cpu_cnt * max_cpus;
for (curcpu = 0, i = -1; curcpu < nprocs; curcpu++) {
- if (i == max_cpus)
- break;
-
if (!stat_node->usage[curcpu].online)
continue;
i++;
+ if (max_cpus > 0 && i == max_cpus)
+ break;
+
if (diff[curcpu].user + diff[curcpu].system >= threshold)
continue;
@@ -4634,14 +4629,14 @@ static int cpuview_proc_stat(const char *cg, const char *cpuset, struct cpuacct_
lxcfs_debug("leftover system: %lu for %s\n", system_surplus, cg);
for (curcpu = 0, i = -1; curcpu < nprocs; curcpu++) {
- if (i == max_cpus)
- break;
-
if (!stat_node->usage[curcpu].online)
continue;
i++;
+ if (max_cpus > 0 && i == max_cpus)
+ break;
+
stat_node->view[curcpu].user += diff[curcpu].user;
stat_node->view[curcpu].system += diff[curcpu].system;
stat_node->view[curcpu].idle += diff[curcpu].idle;
@@ -4649,8 +4644,10 @@ static int cpuview_proc_stat(const char *cg, const char *cpuset, struct cpuacct_
user_sum += stat_node->view[curcpu].user;
system_sum += stat_node->view[curcpu].system;
idle_sum += stat_node->view[curcpu].idle;
- }
+ lxcfs_v("user: %lu, system: %lu, idle: %lu\n", stat_node->view[curcpu].user, stat_node->view[curcpu].system, stat_node->view[curcpu].idle);
+ lxcfs_v("user_sum: %lu, system_sum: %lu, idle_sum: %lu\n", user_sum, system_sum, idle_sum);
+ }
} else {
for (curcpu = 0; curcpu < nprocs; curcpu++) {
if (!stat_node->usage[curcpu].online)
@@ -4659,7 +4656,7 @@ static int cpuview_proc_stat(const char *cg, const char *cpuset, struct cpuacct_
stat_node->view[curcpu].user = stat_node->usage[curcpu].user;
stat_node->view[curcpu].system = stat_node->usage[curcpu].system;
stat_node->view[curcpu].idle = stat_node->usage[curcpu].idle;
-
+
user_sum += stat_node->view[curcpu].user;
system_sum += stat_node->view[curcpu].system;
idle_sum += stat_node->view[curcpu].idle;
@@ -4672,12 +4669,12 @@ static int cpuview_proc_stat(const char *cg, const char *cpuset, struct cpuacct_
user_sum,
system_sum,
idle_sum);
+ lxcfs_v("cpu-all: %s\n", buf);
if (l < 0) {
perror("Error writing to cache");
rv = 0;
goto err;
-
}
if (l >= buf_size) {
lxcfs_error("%s\n", "Internal error: truncated write to cache.");
@@ -4704,6 +4701,7 @@ static int cpuview_proc_stat(const char *cg, const char *cpuset, struct cpuacct_
stat_node->view[curcpu].user,
stat_node->view[curcpu].system,
stat_node->view[curcpu].idle);
+ lxcfs_v("cpu: %s\n", buf);
if (l < 0) {
perror("Error writing to cache");
From 5ae3728e75e952c7837475315c8bfbbec346fbda Mon Sep 17 00:00:00 2001
From: Stephen Xiang <>
Date: Mon, 3 Jun 2019 18:08:42 +0800
Subject: [PATCH 3/3] Correct CPU usage in partial CPU cases when quota/period
don't yield an integer.
---
Makefile.am | 2 +-
bindings.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 48 insertions(+), 3 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 4a76467..06e9ec3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -8,7 +8,7 @@ AM_CFLAGS += $(FUSE_CFLAGS)
AM_CFLAGS += -DLIBDIR=\"$(LIBDIR)\"
AM_LDFLAGS = $(FUSE_LIBS) -pthread
#AM_CFLAGS += -DDEBUG
-AM_CFLAGS += -DVERBOSE
+#AM_CFLAGS += -DVERBOSE
AM_CFLAGS += -DRUNTIME_PATH=\"$(RUNTIME_PATH)\"
diff --git a/bindings.c b/bindings.c
index 506f75e..637c0bf 100644
--- a/bindings.c
+++ b/bindings.c
@@ -3683,6 +3683,35 @@ int max_cpu_count(const char *cg)
return rv;
}
+/*
+ * Return the exact number of visible CPUs based on CPU quotas.
+ * If there is no quota set, zero is returned.
+ */
+double exact_cpu_count(const char *cg)
+{
+ double rv;
+ int nprocs;
+ int64_t cfs_quota, cfs_period;
+
+ if (!read_cpu_cfs_param(cg, "quota", &cfs_quota))
+ return 0;
+
+ if (!read_cpu_cfs_param(cg, "period", &cfs_period))
+ return 0;
+
+ if (cfs_quota <= 0 || cfs_period <= 0)
+ return 0;
+
+ rv = (double)cfs_quota / (double)cfs_period;
+
+ nprocs = get_nprocs();
+
+ if (rv > nprocs)
+ rv = nprocs;
+
+ return rv;
+}
+
/*
* Determine whether CPU views should be used or not.
*/
@@ -4628,6 +4657,7 @@ static int cpuview_proc_stat(const char *cg, const char *cpuset, struct cpuacct_
if (system_surplus > 0)
lxcfs_debug("leftover system: %lu for %s\n", system_surplus, cg);
+ unsigned long diff_total = 0;
for (curcpu = 0, i = -1; curcpu < nprocs; curcpu++) {
if (!stat_node->usage[curcpu].online)
continue;
@@ -4645,8 +4675,23 @@ static int cpuview_proc_stat(const char *cg, const char *cpuset, struct cpuacct_
system_sum += stat_node->view[curcpu].system;
idle_sum += stat_node->view[curcpu].idle;
- lxcfs_v("user: %lu, system: %lu, idle: %lu\n", stat_node->view[curcpu].user, stat_node->view[curcpu].system, stat_node->view[curcpu].idle);
- lxcfs_v("user_sum: %lu, system_sum: %lu, idle_sum: %lu\n", user_sum, system_sum, idle_sum);
+ diff_total += diff[curcpu].user + diff[curcpu].system + diff[curcpu].idle;
+
+ lxcfs_v("curcpu: %d, user: %lu, system: %lu, idle: %lu\n", curcpu, stat_node->view[curcpu].user, stat_node->view[curcpu].system, stat_node->view[curcpu].idle);
+ lxcfs_v("user_sum: %lu, system_sum: %lu, idle_sum: %lu, diff_total: %lu\n", user_sum, system_sum, idle_sum, diff_total);
+ }
+
+ // revise cpu usage view to support partial cpu case
+ double exact_cpus = exact_cpu_count(cg);
+ if (exact_cpus < (double)max_cpus){
+ lxcfs_v("revising cpu usage view to match the exact cpu count [%f]\n", exact_cpus);
+ unsigned long delta = (unsigned long)((double)diff_total * (1 - exact_cpus / (double)max_cpus));
+ idle_sum = idle_sum > delta ? idle_sum - delta : 0;
+ lxcfs_v("user_sum: %lu, system_sum: %lu, idle_sum: %lu, delta: %lu\n", user_sum, system_sum, idle_sum, delta);
+
+ curcpu = max_cpus - 1;
+ stat_node->view[curcpu].idle = stat_node->view[curcpu].idle > delta ? stat_node->view[curcpu].idle - delta : 0;
+ lxcfs_v("curcpu: %d, user: %lu, system: %lu, idle: %lu\n", curcpu, stat_node->view[curcpu].user, stat_node->view[curcpu].system, stat_node->view[curcpu].idle);
}
} else {
for (curcpu = 0; curcpu < nprocs; curcpu++) {
More information about the lxc-devel
mailing list