The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxcfs/pull/260
This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.
=== Description (from pull-request) ===
Currently, containers can see all CPUs in `/proc/stat` except those excluded using cpuset. cpuset isn't very practical when you have a lot of containers with unpredictable load, so we're using CPU quotas to limit CPU usage, which let the containers utilize all CPUs within the quota as the scheduler sees fit. This patchset reduces the number of CPUs visible in `/proc/cpuinfo` and `/proc/stat` based on CPU quotas configured e.g. using `lxc.cgroup.cpu.cfs_{quota,period}_us`. If qoutas aren't set, it falls back to the current behaviour.
Since containers can utilize more CPUs then should be visible, LXCFS generates per-container CPU usage view. It has to remember what values were reported to containers, so that the usage counters are continuously increasing and to ensure that no CPU will be utilized for more than 100% between two consecutive reads of `/proc/stat`. This is done by introducing state. CPU usage of all containers is tracked in a hash table with linked lists, similar to the loadavg code. CPU usage counters from hidden CPUs are spread over the visible CPUs that are not already fully utilized within the time frame since the last read of `/proc/stat`, starting from the first CPU to the last. This means that the CPU usage as seen within containers does not reflect the real usage on the host system.
Like with `/proc/loadavg`, the CPU usage accounting for containers starts to work on the first read of `/proc/stat`. CPU views are used only if there is cpuacct cgroup, cpu cgroup and `cpu.cfs_{quota,period}_us` are set.
Discussed also in #239.
From 67dedf76ca8b3f8792d5ddca2b4f25a33a2c17f3 Mon Sep 17 00:00:00 2001
From: Jakub Skokan
Date: Mon, 25 Jun 2018 08:54:15 +0200
Subject: [PATCH 1/7] cpuinfo: use cpu view based on cpu quotas
Signed-off-by: Jakub Skokan
---
bindings.c | 91 +-
1 file changed, 90 insertions(+), 1 deletion(-)
diff --git a/bindings.c b/bindings.c
index 70386fc..40ba094 100644
--- a/bindings.c
+++ b/bindings.c
@@ -3509,6 +3509,85 @@ static bool cpuline_in_cpuset(const char *line, const
char *cpuset)
return cpu_in_cpuset(cpu, cpuset);
}
+/*
+ * Read cgroup CPU quota parameters from `cpu.cfs_quota_us` or
`cpu.cfs_period_us`,
+ * depending on `param`. Parameter value is returned throuh `value`.
+ */
+static bool read_cpu_cfs_param(const char *cg, const char *param, int64_t
*value)
+{
+ bool rv = false;
+ char file[11 + 6 + 1]; // cpu.cfs__us + quota/period + \0
+ char *str = NULL;
+
+ sprintf(file, "cpu.cfs_%s_us", param);
+
+ if (!cgfs_get_value("cpu", cg, file, ))
+ goto err;
+
+ if (sscanf(str, "%ld", value) != 1)
+ goto err;
+
+ rv = true;
+
+err:
+ if (str)
+ free(str);
+ return rv;
+}
+
+/*
+ * Return the maximum number of visible CPUs based on CPU quotas.
+ * If there is no quota set, zero is returned.
+ */
+int max_cpu_count(const char *cg)
+{
+ int rv, nprocs;
+ int64_t cfs_quota, cfs_period;
+
+ if (!read_cpu_cfs_param(cg, "quota", _quota))
+ return 0;
+
+ if (!read_cpu_cfs_param(cg, "period", _period))
+ return 0;
+
+ if (cfs_quota <= 0 || cfs_period <= 0)
+ return 0;
+
+ rv = cfs_quota / cfs_period;
+
+ /* In case quota/period does not yield a whole number, add one CPU for
+* the remainder.
+*/
+ if ((cfs_quota % cfs_period) > 0)
+ rv += 1;
+
+ nprocs = get_nprocs();
+
+ if (rv > nprocs)
+ rv = nprocs;
+
+ return rv;
+}
+
+/*
+ * Determine whether CPU views should be used or not.
+ */
+bool use_cpu_view(const char *cg)
+{
+ int cfd;
+ char *tmpc;
+
+ tmpc = find_mounted_controller("cpu", );
+ if (!tmpc)
+ return false;
+
+ tmpc = find_mounted_controller("cpuacct", );
+ if (!tmpc)
+ return false;
+
+ return true;
+}
+
/*
* check whether this is a '^processor" line in /proc/cpuinfo
*/
@@ -3531,7 +3610,8 @@ static int proc_cpuinfo_read(char *buf, size_t size,
off_t offset,
char *line = NULL;
size_t linelen = 0, total_len = 0, rv = 0;
bool am_printing = false, firstline = true, is_s390x = false;
- int curcpu = -1, cpu;
+ int curcpu = -1, cpu, max_cpus = 0;
+ bool use_view;
char *cache = d->buf;
size_t cache_size = d->buflen;
FILE *f = NULL;
@@ -3559,6 +3639,11 @@ static int proc_cpuinfo_read(char *buf, size_t size,
off_t offset,
if (!cpuset)
goto err;
+ use_view = use_cpu_view(cg);
+
+ if