@@ -31,6 +31,7 @@ import time
bblogger = logging.getLogger("BitBake")
logger = logging.getLogger("BitBake.RunQueue")
hashequiv_logger = logging.getLogger("BitBake.RunQueue.HashEquiv")
+psi_logger = logging.getLogger("BitBake.RunQueue.PSI")
__find_sha256__ = re.compile( r'(?i)(?<![a-z0-9])[a-f0-9]{64}(?![a-z0-9])' )
@@ -221,7 +222,8 @@ class RunQueueScheduler(object):
pressure_state = (exceeds_cpu_pressure, exceeds_io_pressure, exceeds_memory_pressure)
pressure_values = (round(cpu_pressure,1), self.rq.max_cpu_pressure, round(io_pressure,1), self.rq.max_io_pressure, round(memory_pressure,1), self.rq.max_memory_pressure)
if hasattr(self, "pressure_state") and pressure_state != self.pressure_state:
- bb.note("Pressure status changed to CPU: %s, IO: %s, Mem: %s (CPU: %s/%s, IO: %s/%s, Mem: %s/%s) - using %s/%s bitbake threads" % (pressure_state + pressure_values + (len(self.rq.runq_running.difference(self.rq.runq_complete)), self.rq.number_tasks)))
+ psi_logger.verbose("Pressure status changed to CPU: %s, IO: %s, Mem: %s (CPU: %s/%s, IO: %s/%s, Mem: %s/%s) - using %s/%s bitbake threads" % (pressure_state + pressure_values + (len(self.rq.runq_running.difference(self.rq.runq_complete)), self.rq.number_tasks)))
+ bb.event.fire(PSIEvent(pressure_state, pressure_values), self.rq.cfgData)
self.pressure_state = pressure_state
return (exceeds_cpu_pressure or exceeds_io_pressure or exceeds_memory_pressure)
elif self.rq.max_loadfactor:
@@ -3307,6 +3309,12 @@ class taskUniHashUpdate(bb.event.Event):
self.unihash = unihash
bb.event.Event.__init__(self)
+class PSIEvent(bb.event.Event):
+ def __init__(self, pressure_state, pressure_values):
+ super().__init__()
+ self.pressure_state = pressure_state
+ self.pressure_values = pressure_values
+
class runQueuePipe():
"""
Abstraction for a pipe between a worker thread and the server
@@ -115,6 +115,20 @@ def pluralise(singular, plural, qty):
else:
return plural % qty
+def get_pressure_message(pressure_state, pressure_values):
+ cpu_pressure, io_pressure, mem_pressure = pressure_state
+ pressure_strs = []
+ if cpu_pressure:
+ pressure_strs.append("CPU pressure (>%sus)" % pressure_values[1])
+ if io_pressure:
+ pressure_strs.append("I/O pressure (>%sus)" % pressure_values[3])
+ if mem_pressure:
+ pressure_strs.append("MEM pressure (>%sus)" % pressure_values[5])
+
+ if not pressure_strs:
+ pressure_strs.append("No pressure")
+
+ return "%s is limiting task startup" % ", ".join(pressure_strs)
class InteractConsoleLogFilter(logging.Filter):
def __init__(self, tf):
@@ -122,7 +136,7 @@ class InteractConsoleLogFilter(logging.Filter):
super().__init__()
def filter(self, record):
- if record.levelno == bb.msg.BBLogFormatter.NOTE and (record.msg.startswith("Running") or record.msg.startswith("recipe ")):
+ if record.levelno == bb.msg.BBLogFormatter.NOTE and (record.msg.startswith("Running") or record.msg.startswith("recipe ") or "limiting task startup" in record.msg):
return False
self.tf.clearFooter()
return True
@@ -320,6 +334,11 @@ class TerminalFilter(object):
content += msg + "\n"
print(msg, file=self._footer_buf)
+ if any(self.helper.pressure_state):
+ msg = get_pressure_message(self.helper.pressure_state, self.helper.pressure_values)
+ content += msg + "\n"
+ print(msg, file=self._footer_buf)
+
if self.quiet:
msg = "Running tasks (%s, %s)" % (scene_tasks, cur_tasks)
elif not len(activetasks):
@@ -433,7 +452,8 @@ _evt_list = [ "bb.runqueue.runQueueExitWait", "bb.event.LogExecTTY", "logging.Lo
"bb.event.MultipleProviders", "bb.event.NoProvider", "bb.runqueue.sceneQueueTaskStarted",
"bb.runqueue.runQueueTaskStarted", "bb.runqueue.runQueueTaskFailed", "bb.runqueue.sceneQueueTaskFailed",
"bb.event.BuildBase", "bb.build.TaskStarted", "bb.build.TaskSucceeded", "bb.build.TaskFailedSilent",
- "bb.build.TaskProgress", "bb.event.ProcessStarted", "bb.event.ProcessProgress", "bb.event.ProcessFinished"]
+ "bb.build.TaskProgress", "bb.event.ProcessStarted", "bb.event.ProcessProgress", "bb.event.ProcessFinished",
+ "bb.runqueue.PSIEvent"]
def drain_events_errorhandling(eventHandler):
# We don't have logging setup, we do need to show any events we see before exiting
@@ -587,6 +607,10 @@ def main(server, eventHandler, params, tf = TerminalFilter):
"BitBake.RunQueue.HashEquiv": {
"level": "VERBOSE",
"handlers": ["BitBake.verbconsolelog"],
+ },
+ "BitBake.RunQueue.PSI": {
+ "level": "VERBOSE",
+ "handlers": ["BitBake.verbconsolelog"],
}
}
})
@@ -904,6 +928,11 @@ def main(server, eventHandler, params, tf = TerminalFilter):
parseprogress.finish()
parseprogress = None
continue
+ if isinstance(event, bb.runqueue.PSIEvent):
+ if params.options.quiet > 1:
+ continue
+ logger.info(get_pressure_message(event.pressure_state, event.pressure_values))
+ continue
# ignore
if isinstance(event, (bb.event.BuildBase,
@@ -6,6 +6,7 @@
#
import bb.build
+import bb.runqueue
import time
class BBUIHelper:
@@ -17,6 +18,8 @@ class BBUIHelper:
self.pidmap = {}
self.tasknumber_current = 0
self.tasknumber_total = 0
+ self.pressure_state = (False, False, False)
+ self.pressure_values = None
def eventHandler(self, event):
# PIDs are a bad idea as they can be reused before we process all UI events.
@@ -57,6 +60,10 @@ class BBUIHelper:
self.running_tasks[self.pidmap[event.pid]]['progress'] = event.progress
self.running_tasks[self.pidmap[event.pid]]['rate'] = event.rate
self.needUpdate = True
+ elif isinstance(event, bb.runqueue.PSIEvent):
+ self.pressure_state = event.pressure_state
+ self.pressure_values = event.pressure_values
+ self.needUpdate = True
else:
return False
return True
Reworks the way that pressure stall information (PSI) is reported in the UI. This change does a number of things to enable PSI to still be reported, but less intrusive than a NOTE message each time it changes: 1) The primary reporting of the PSI to the UI is now done through an event. 2) The knotty UI handles the event and reports which PSI montiors are preventing tasks from starting with a line in the status footer. 3) The old logging messages for PSI is moved to it's own logging domain (BitBaker.RunQueue.PSI), at verbose level. This allows filtering out PSI related events in structured logging configurations 4) The default config for knotty will report the full PSI messages (e.g. the old logging message) to the BB_LOGCONFIG file. This should providing relevant information in the user in the UI, but also not flooding the console with PSI messages. Signed-off-by: Joshua Watt <JPEWhacker@gmail.com> --- lib/bb/runqueue.py | 10 +++++++++- lib/bb/ui/knotty.py | 33 +++++++++++++++++++++++++++++++-- lib/bb/ui/uihelper.py | 7 +++++++ 3 files changed, 47 insertions(+), 3 deletions(-)