summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2016-06-08 20:45:32 +0200
committerLennart Poettering <lennart@poettering.net>2016-06-14 20:01:45 +0200
commitd8cf2ac79b524d7784bccb428295ebc9c5e8548c (patch)
tree43a03ab780ccc0b130dc57322c816f99e3f09754
parent799ec13412e2f6649fd69ce4f1ca1674a40039b0 (diff)
util: introduce physical_memory_scale() to unify how we scale by physical memory
The various bits of code did the scaling all different, let's unify this, given that the code is not trivial.
-rw-r--r--src/basic/util.c27
-rw-r--r--src/basic/util.h1
-rw-r--r--src/core/load-fragment.c2
-rw-r--r--src/login/logind-user.c2
-rw-r--r--src/login/logind.c2
-rw-r--r--src/test/test-util.c38
6 files changed, 68 insertions, 4 deletions
diff --git a/src/basic/util.c b/src/basic/util.c
index 88d58cd94a..09d16697b7 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -805,6 +805,33 @@ uint64_t physical_memory(void) {
return MIN(mem, lim);
}
+uint64_t physical_memory_scale(uint64_t v, uint64_t max) {
+ uint64_t p, m, ps, r;
+
+ assert(max > 0);
+
+ /* Returns the physical memory size, multiplied by v divided by max. Returns UINT64_MAX on overflow. On success
+ * the result is a multiple of the page size (rounds down). */
+
+ ps = page_size();
+ assert(ps > 0);
+
+ p = physical_memory() / ps;
+ assert(p > 0);
+
+ m = p * v;
+ if (m / p != v)
+ return UINT64_MAX;
+
+ m /= max;
+
+ r = m * ps;
+ if (r / ps != m)
+ return UINT64_MAX;
+
+ return r;
+}
+
int update_reboot_parameter_and_warn(const char *param) {
int r;
diff --git a/src/basic/util.h b/src/basic/util.h
index 9e6df19ef1..db105197e8 100644
--- a/src/basic/util.h
+++ b/src/basic/util.h
@@ -184,6 +184,7 @@ int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *
int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd);
uint64_t physical_memory(void);
+uint64_t physical_memory_scale(uint64_t v, uint64_t max);
int update_reboot_parameter_and_warn(const char *param);
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 05852cc7e3..58d7275a96 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -2821,7 +2821,7 @@ int config_parse_memory_limit(
return 0;
}
} else
- bytes = (((physical_memory() / page_size()) * (uint64_t) r) / 100) * page_size();
+ bytes = physical_memory_scale(r, 100U);
if (bytes < 1) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Memory limit '%s' too small. Ignoring.", rvalue);
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
index 6d0904f5ca..de44d369cf 100644
--- a/src/login/logind-user.c
+++ b/src/login/logind-user.c
@@ -853,7 +853,7 @@ int config_parse_tmpfs_size(
/* First, try to parse as percentage */
r = parse_percent(rvalue);
if (r > 0 && r < 100)
- *sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) r) / 100U));
+ *sz = physical_memory_scale(r, 100U);
else {
uint64_t k;
diff --git a/src/login/logind.c b/src/login/logind.c
index caf149cfb7..d01dd110ea 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -61,7 +61,7 @@ static void manager_reset_config(Manager *m) {
m->idle_action_usec = 30 * USEC_PER_MINUTE;
m->idle_action = HANDLE_IGNORE;
- m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */
+ m->runtime_dir_size = physical_memory_scale(10U, 100U); /* 10% */
m->user_tasks_max = 12288;
m->sessions_max = 8192;
m->inhibitors_max = 8192;
diff --git a/src/test/test-util.c b/src/test/test-util.c
index 5b3fbcff53..e177612a9f 100644
--- a/src/test/test-util.c
+++ b/src/test/test-util.c
@@ -273,7 +273,42 @@ static void test_physical_memory(void) {
assert_se(p < UINT64_MAX);
assert_se(p % page_size() == 0);
- log_info("Memory: %s", format_bytes(buf, sizeof(buf), p));
+ log_info("Memory: %s (%" PRIu64 ")", format_bytes(buf, sizeof(buf), p), p);
+}
+
+static void test_physical_memory_scale(void) {
+ uint64_t p;
+
+ p = physical_memory();
+
+ assert_se(physical_memory_scale(0, 100) == 0);
+ assert_se(physical_memory_scale(100, 100) == p);
+
+ log_info("Memory original: %" PRIu64, physical_memory());
+ log_info("Memory scaled by 50%%: %" PRIu64, physical_memory_scale(50, 100));
+ log_info("Memory divided by 2: %" PRIu64, physical_memory() / 2);
+ log_info("Page size: %zu", page_size());
+
+ /* There might be an uneven number of pages, hence permit these calculations to be half a page off... */
+ assert_se(page_size()/2 + physical_memory_scale(50, 100) - p/2 <= page_size());
+ assert_se(physical_memory_scale(200, 100) == p*2);
+
+ assert_se(physical_memory_scale(0, 1) == 0);
+ assert_se(physical_memory_scale(1, 1) == p);
+ assert_se(physical_memory_scale(2, 1) == p*2);
+
+ assert_se(physical_memory_scale(0, 2) == 0);
+
+ assert_se(page_size()/2 + physical_memory_scale(1, 2) - p/2 <= page_size());
+ assert_se(physical_memory_scale(2, 2) == p);
+ assert_se(physical_memory_scale(4, 2) == p*2);
+
+ assert_se(physical_memory_scale(0, UINT32_MAX) == 0);
+ assert_se(physical_memory_scale(UINT32_MAX, UINT32_MAX) == p);
+
+ /* overflow */
+ assert_se(physical_memory_scale(UINT64_MAX/4, UINT64_MAX) == UINT64_MAX);
+
}
int main(int argc, char *argv[]) {
@@ -291,6 +326,7 @@ int main(int argc, char *argv[]) {
test_execute_directory();
test_raw_clone();
test_physical_memory();
+ test_physical_memory_scale();
return 0;
}