LCOV - code coverage report
Current view: top level - basic - limits-util.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 52 74 70.3 %
Date: 2019-08-22 15:41:25 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include "alloc-util.h"
       4             : #include "cgroup-util.h"
       5             : #include "limits-util.h"
       6             : #include "memory-util.h"
       7             : #include "parse-util.h"
       8             : #include "process-util.h"
       9             : #include "procfs-util.h"
      10             : #include "string-util.h"
      11             : 
      12          38 : uint64_t physical_memory(void) {
      13          38 :         _cleanup_free_ char *root = NULL, *value = NULL;
      14             :         uint64_t mem, lim;
      15             :         size_t ps;
      16             :         long sc;
      17             :         int r;
      18             : 
      19             :         /* We return this as uint64_t in case we are running as 32bit process on a 64bit kernel with huge amounts of
      20             :          * memory.
      21             :          *
      22             :          * In order to support containers nicely that have a configured memory limit we'll take the minimum of the
      23             :          * physically reported amount of memory and the limit configured for the root cgroup, if there is any. */
      24             : 
      25          38 :         sc = sysconf(_SC_PHYS_PAGES);
      26          38 :         assert(sc > 0);
      27             : 
      28          38 :         ps = page_size();
      29          38 :         mem = (uint64_t) sc * (uint64_t) ps;
      30             : 
      31          38 :         r = cg_get_root_path(&root);
      32          38 :         if (r < 0) {
      33           0 :                 log_debug_errno(r, "Failed to determine root cgroup, ignoring cgroup memory limit: %m");
      34           0 :                 return mem;
      35             :         }
      36             : 
      37          38 :         r = cg_all_unified();
      38          38 :         if (r < 0) {
      39           0 :                 log_debug_errno(r, "Failed to determine root unified mode, ignoring cgroup memory limit: %m");
      40           0 :                 return mem;
      41             :         }
      42          38 :         if (r > 0) {
      43           0 :                 r = cg_get_attribute("memory", root, "memory.max", &value);
      44           0 :                 if (r < 0) {
      45           0 :                         log_debug_errno(r, "Failed to read memory.max cgroup attribute, ignoring cgroup memory limit: %m");
      46           0 :                         return mem;
      47             :                 }
      48             : 
      49           0 :                 if (streq(value, "max"))
      50           0 :                         return mem;
      51             :         } else {
      52          38 :                 r = cg_get_attribute("memory", root, "memory.limit_in_bytes", &value);
      53          38 :                 if (r < 0) {
      54           0 :                         log_debug_errno(r, "Failed to read memory.limit_in_bytes cgroup attribute, ignoring cgroup memory limit: %m");
      55           0 :                         return mem;
      56             :                 }
      57             :         }
      58             : 
      59          38 :         r = safe_atou64(value, &lim);
      60          38 :         if (r < 0) {
      61           0 :                 log_debug_errno(r, "Failed to parse cgroup memory limit '%s', ignoring: %m", value);
      62           0 :                 return mem;
      63             :         }
      64          38 :         if (lim == UINT64_MAX)
      65           0 :                 return mem;
      66             : 
      67             :         /* Make sure the limit is a multiple of our own page size */
      68          38 :         lim /= ps;
      69          38 :         lim *= ps;
      70             : 
      71          38 :         return MIN(mem, lim);
      72             : }
      73             : 
      74          15 : uint64_t physical_memory_scale(uint64_t v, uint64_t max) {
      75             :         uint64_t p, m, ps, r;
      76             : 
      77          15 :         assert(max > 0);
      78             : 
      79             :         /* Returns the physical memory size, multiplied by v divided by max. Returns UINT64_MAX on overflow. On success
      80             :          * the result is a multiple of the page size (rounds down). */
      81             : 
      82          15 :         ps = page_size();
      83          15 :         assert(ps > 0);
      84             : 
      85          15 :         p = physical_memory() / ps;
      86          15 :         assert(p > 0);
      87             : 
      88          15 :         m = p * v;
      89          15 :         if (m / p != v)
      90           1 :                 return UINT64_MAX;
      91             : 
      92          14 :         m /= max;
      93             : 
      94          14 :         r = m * ps;
      95          14 :         if (r / ps != m)
      96           0 :                 return UINT64_MAX;
      97             : 
      98          14 :         return r;
      99             : }
     100             : 
     101          16 : uint64_t system_tasks_max(void) {
     102             : 
     103          16 :         uint64_t a = TASKS_MAX, b = TASKS_MAX;
     104          32 :         _cleanup_free_ char *root = NULL;
     105             :         int r;
     106             : 
     107             :         /* Determine the maximum number of tasks that may run on this system. We check three sources to determine this
     108             :          * limit:
     109             :          *
     110             :          * a) the maximum tasks value the kernel allows on this architecture
     111             :          * b) the cgroups pids_max attribute for the system
     112             :          * c) the kernel's configured maximum PID value
     113             :          *
     114             :          * And then pick the smallest of the three */
     115             : 
     116          16 :         r = procfs_tasks_get_limit(&a);
     117          16 :         if (r < 0)
     118           0 :                 log_debug_errno(r, "Failed to read maximum number of tasks from /proc, ignoring: %m");
     119             : 
     120          16 :         r = cg_get_root_path(&root);
     121          16 :         if (r < 0)
     122           0 :                 log_debug_errno(r, "Failed to determine cgroup root path, ignoring: %m");
     123             :         else {
     124          16 :                 _cleanup_free_ char *value = NULL;
     125             : 
     126          16 :                 r = cg_get_attribute("pids", root, "pids.max", &value);
     127          16 :                 if (r < 0)
     128          16 :                         log_debug_errno(r, "Failed to read pids.max attribute of cgroup root, ignoring: %m");
     129           0 :                 else if (!streq(value, "max")) {
     130           0 :                         r = safe_atou64(value, &b);
     131           0 :                         if (r < 0)
     132           0 :                                 log_debug_errno(r, "Failed to parse pids.max attribute of cgroup root, ignoring: %m");
     133             :                 }
     134             :         }
     135             : 
     136          16 :         return MIN3(TASKS_MAX,
     137             :                     a <= 0 ? TASKS_MAX : a,
     138             :                     b <= 0 ? TASKS_MAX : b);
     139             : }
     140             : 
     141          14 : uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) {
     142             :         uint64_t t, m;
     143             : 
     144          14 :         assert(max > 0);
     145             : 
     146             :         /* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages
     147             :          * relative to the system's maximum number of tasks. Returns UINT64_MAX on overflow. */
     148             : 
     149          14 :         t = system_tasks_max();
     150          14 :         assert(t > 0);
     151             : 
     152          14 :         m = t * v;
     153          14 :         if (m / t != v) /* overflow? */
     154           1 :                 return UINT64_MAX;
     155             : 
     156          13 :         return m / max;
     157             : }

Generated by: LCOV version 1.14