diff options
author | Aryaman Gupta <aryaman.gupta@windriver.com> | 2022-08-04 14:52:32 -0400 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2022-08-12 11:49:29 +0100 |
commit | f5c616d5aff31814c0fe2a4b16e3e89bebf1c10a (patch) | |
tree | fef5ac866d634f706bb4dd039d8a99123c31bd14 /bitbake/lib/bb/runqueue.py | |
parent | 0f6817f2a4552c82f2eb58602b28959a1792c0d4 (diff) | |
download | poky-f5c616d5aff31814c0fe2a4b16e3e89bebf1c10a.tar.gz |
bitbake: runqueue: add memory pressure regulation
Prevent new tasks from being scheduled if the memory pressure is above
a certain threshold, specified through the "BB_MAX_PRESSURE_MEMORY"
variable in the conf/local.conf file. This is an extension to the
following commit and hence regulates pressure in the same way:
48a6d84de1 bitbake: runqueue: add cpu/io pressure regulation
Memory pressure is experienced when time is spent swapping, refaulting
pages from the page cache or performing direct reclaim. This is why
memory pressure is rarely seen but might be useful as a last resort to
prevent OOM errors.
(Bitbake rev: 44c395434c7be8dab968630a610c8807f512920c)
Signed-off-by: Aryaman Gupta <aryaman.gupta@windriver.com>
Signed-off-by: Randy Macleod <Randy.Macleod@windriver.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/bb/runqueue.py')
-rw-r--r-- | bitbake/lib/bb/runqueue.py | 27 |
1 files changed, 22 insertions, 5 deletions
diff --git a/bitbake/lib/bb/runqueue.py b/bitbake/lib/bb/runqueue.py index bc1cbb360f..d0ffe3932c 100644 --- a/bitbake/lib/bb/runqueue.py +++ b/bitbake/lib/bb/runqueue.py | |||
@@ -168,11 +168,15 @@ class RunQueueScheduler(object): | |||
168 | openSUSE /proc/pressure/* files have readable file permissions but when read the error EOPNOTSUPP (Operation not supported) | 168 | openSUSE /proc/pressure/* files have readable file permissions but when read the error EOPNOTSUPP (Operation not supported) |
169 | is returned. | 169 | is returned. |
170 | """ | 170 | """ |
171 | if self.rq.max_cpu_pressure or self.rq.max_io_pressure: | 171 | if self.rq.max_cpu_pressure or self.rq.max_io_pressure or self.rq.max_memory_pressure: |
172 | try: | 172 | try: |
173 | with open("/proc/pressure/cpu") as cpu_pressure_fds, open("/proc/pressure/io") as io_pressure_fds: | 173 | with open("/proc/pressure/cpu") as cpu_pressure_fds, \ |
174 | open("/proc/pressure/io") as io_pressure_fds, \ | ||
175 | open("/proc/pressure/memory") as memory_pressure_fds: | ||
176 | |||
174 | self.prev_cpu_pressure = cpu_pressure_fds.readline().split()[4].split("=")[1] | 177 | self.prev_cpu_pressure = cpu_pressure_fds.readline().split()[4].split("=")[1] |
175 | self.prev_io_pressure = io_pressure_fds.readline().split()[4].split("=")[1] | 178 | self.prev_io_pressure = io_pressure_fds.readline().split()[4].split("=")[1] |
179 | self.prev_memory_pressure = memory_pressure_fds.readline().split()[4].split("=")[1] | ||
176 | self.prev_pressure_time = time.time() | 180 | self.prev_pressure_time = time.time() |
177 | self.check_pressure = True | 181 | self.check_pressure = True |
178 | except: | 182 | except: |
@@ -184,21 +188,26 @@ class RunQueueScheduler(object): | |||
184 | def exceeds_max_pressure(self): | 188 | def exceeds_max_pressure(self): |
185 | """ | 189 | """ |
186 | Monitor the difference in total pressure at least once per second, if | 190 | Monitor the difference in total pressure at least once per second, if |
187 | BB_PRESSURE_MAX_{CPU|IO} are set, return True if above threshold. | 191 | BB_PRESSURE_MAX_{CPU|IO|MEMORY} are set, return True if above threshold. |
188 | """ | 192 | """ |
189 | if self.check_pressure: | 193 | if self.check_pressure: |
190 | with open("/proc/pressure/cpu") as cpu_pressure_fds, open("/proc/pressure/io") as io_pressure_fds: | 194 | with open("/proc/pressure/cpu") as cpu_pressure_fds, \ |
195 | open("/proc/pressure/io") as io_pressure_fds, \ | ||
196 | open("/proc/pressure/memory") as memory_pressure_fds: | ||
191 | # extract "total" from /proc/pressure/{cpu|io} | 197 | # extract "total" from /proc/pressure/{cpu|io} |
192 | curr_cpu_pressure = cpu_pressure_fds.readline().split()[4].split("=")[1] | 198 | curr_cpu_pressure = cpu_pressure_fds.readline().split()[4].split("=")[1] |
193 | curr_io_pressure = io_pressure_fds.readline().split()[4].split("=")[1] | 199 | curr_io_pressure = io_pressure_fds.readline().split()[4].split("=")[1] |
200 | curr_memory_pressure = memory_pressure_fds.readline().split()[4].split("=")[1] | ||
194 | exceeds_cpu_pressure = self.rq.max_cpu_pressure and (float(curr_cpu_pressure) - float(self.prev_cpu_pressure)) > self.rq.max_cpu_pressure | 201 | exceeds_cpu_pressure = self.rq.max_cpu_pressure and (float(curr_cpu_pressure) - float(self.prev_cpu_pressure)) > self.rq.max_cpu_pressure |
195 | exceeds_io_pressure = self.rq.max_io_pressure and (float(curr_io_pressure) - float(self.prev_io_pressure)) > self.rq.max_io_pressure | 202 | exceeds_io_pressure = self.rq.max_io_pressure and (float(curr_io_pressure) - float(self.prev_io_pressure)) > self.rq.max_io_pressure |
203 | exceeds_memory_pressure = self.rq.max_memory_pressure and (float(curr_memory_pressure) - float(self.prev_memory_pressure)) > self.rq.max_memory_pressure | ||
196 | now = time.time() | 204 | now = time.time() |
197 | if now - self.prev_pressure_time > 1.0: | 205 | if now - self.prev_pressure_time > 1.0: |
198 | self.prev_cpu_pressure = curr_cpu_pressure | 206 | self.prev_cpu_pressure = curr_cpu_pressure |
199 | self.prev_io_pressure = curr_io_pressure | 207 | self.prev_io_pressure = curr_io_pressure |
208 | self.prev_memory_pressure = curr_memory_pressure | ||
200 | self.prev_pressure_time = now | 209 | self.prev_pressure_time = now |
201 | return (exceeds_cpu_pressure or exceeds_io_pressure) | 210 | return (exceeds_cpu_pressure or exceeds_io_pressure or exceeds_memory_pressure) |
202 | return False | 211 | return False |
203 | 212 | ||
204 | def next_buildable_task(self): | 213 | def next_buildable_task(self): |
@@ -1748,6 +1757,7 @@ class RunQueueExecute: | |||
1748 | self.scheduler = self.cfgData.getVar("BB_SCHEDULER") or "speed" | 1757 | self.scheduler = self.cfgData.getVar("BB_SCHEDULER") or "speed" |
1749 | self.max_cpu_pressure = self.cfgData.getVar("BB_PRESSURE_MAX_CPU") | 1758 | self.max_cpu_pressure = self.cfgData.getVar("BB_PRESSURE_MAX_CPU") |
1750 | self.max_io_pressure = self.cfgData.getVar("BB_PRESSURE_MAX_IO") | 1759 | self.max_io_pressure = self.cfgData.getVar("BB_PRESSURE_MAX_IO") |
1760 | self.max_memory_pressure = self.cfgData.getVar("BB_PRESSURE_MAX_MEMORY") | ||
1751 | 1761 | ||
1752 | self.sq_buildable = set() | 1762 | self.sq_buildable = set() |
1753 | self.sq_running = set() | 1763 | self.sq_running = set() |
@@ -1798,6 +1808,13 @@ class RunQueueExecute: | |||
1798 | if self.max_io_pressure > upper_limit: | 1808 | if self.max_io_pressure > upper_limit: |
1799 | bb.warn("Your build will be largely unregulated since BB_PRESSURE_MAX_IO is set to %s. It is very unlikely that such high pressure will be experienced." % (self.max_io_pressure)) | 1809 | bb.warn("Your build will be largely unregulated since BB_PRESSURE_MAX_IO is set to %s. It is very unlikely that such high pressure will be experienced." % (self.max_io_pressure)) |
1800 | 1810 | ||
1811 | if self.max_memory_pressure: | ||
1812 | self.max_memory_pressure = float(self.max_memory_pressure) | ||
1813 | if self.max_memory_pressure < lower_limit: | ||
1814 | bb.fatal("Invalid BB_PRESSURE_MAX_MEMORY %s, minimum value is %s." % (self.max_memory_pressure, lower_limit)) | ||
1815 | if self.max_memory_pressure > upper_limit: | ||
1816 | bb.warn("Your build will be largely unregulated since BB_PRESSURE_MAX_MEMORY is set to %s. It is very unlikely that such high pressure will be experienced." % (self.max_io_pressure)) | ||
1817 | |||
1801 | # List of setscene tasks which we've covered | 1818 | # List of setscene tasks which we've covered |
1802 | self.scenequeue_covered = set() | 1819 | self.scenequeue_covered = set() |
1803 | # List of tasks which are covered (including setscene ones) | 1820 | # List of tasks which are covered (including setscene ones) |