summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSakib Sajal <sakib.sajal@windriver.com>2020-11-10 10:59:15 -0500
committerRichard Purdie <richard.purdie@linuxfoundation.org>2021-01-17 11:28:13 +0000
commitd068fbcde2c5dd159ab903e9696ef900514ce866 (patch)
tree8655f402c10c4ac447d3b97b1af954859e8a33ac
parent75c779b628f31f1376baedd968eafcfe3c188846 (diff)
downloadpoky-d068fbcde2c5dd159ab903e9696ef900514ce866.tar.gz
buildstats.bbclass: add functionality to collect build system stats
There are a number of timeout and hang defects where it would be useful to collect statistics about what is running on a build host when that condition occurs. This adds functionality to collect build system stats on a regular interval and/or on task failure. Both features are disabled by default. To enable logging on a regular interval, set: BB_HEARTBEAT_EVENT = "<interval>" BB_LOG_HOST_STAT_ON_INTERVAL = <boolean> Logs are stored in ${BUILDSTATS_BASE}/<build_name>/host_stats To enable logging on a task failure, set: BB_LOG_HOST_STAT_ON_FAILURE = "<boolean>" Logs are stored in ${BUILDSTATS_BASE}/<build_name>/build_stats The list of commands, along with the desired options, need to be specified in the BB_LOG_HOST_STAT_CMDS variable delimited by ; as such: BB_LOG_HOST_STAT_CMDS = "command1 ; command2 ;... ;" (From OE-Core rev: edb7098e9e0a8978568a45057c1c3ad2c6cacd67) Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--meta/classes/buildstats.bbclass40
1 files changed, 37 insertions, 3 deletions
diff --git a/meta/classes/buildstats.bbclass b/meta/classes/buildstats.bbclass
index 6f87187233..a8ee6e69a6 100644
--- a/meta/classes/buildstats.bbclass
+++ b/meta/classes/buildstats.bbclass
@@ -104,14 +104,46 @@ def write_task_data(status, logfile, e, d):
104 f.write("Status: FAILED \n") 104 f.write("Status: FAILED \n")
105 f.write("Ended: %0.2f \n" % e.time) 105 f.write("Ended: %0.2f \n" % e.time)
106 106
107def write_host_data(logfile, e, d):
108 import subprocess, os, datetime
109 cmds = d.getVar('BB_LOG_HOST_STAT_CMDS')
110 if cmds is None:
111 d.setVar("BB_LOG_HOST_STAT_ON_INTERVAL", "0")
112 d.setVar("BB_LOG_HOST_STAT_ON_FAILURE", "0")
113 bb.warn("buildstats: Collecting host data failed. Set BB_LOG_HOST_STAT_CMDS=\"command1 ; command2 ; ... \" in conf\/local.conf\n")
114 return
115 path = d.getVar("PATH")
116 opath = d.getVar("BB_ORIGENV", False).getVar("PATH")
117 ospath = os.environ['PATH']
118 os.environ['PATH'] = path + ":" + opath + ":" + ospath
119 with open(logfile, "a") as f:
120 f.write("Event Time: %f\nDate: %s\n" % (e.time, datetime.datetime.now()))
121 for cmd in cmds.split(";"):
122 if len(cmd) == 0:
123 continue
124 try:
125 output = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT, timeout=1).decode('utf-8')
126 except (subprocess.CalledProcessError, subprocess.TimeoutExpired, FileNotFoundError) as err:
127 output = "Error running command: %s\n%s\n" % (cmd, err)
128 f.write("%s\n%s\n" % (cmd, output))
129 os.environ['PATH'] = ospath
130
107python run_buildstats () { 131python run_buildstats () {
108 import bb.build 132 import bb.build
109 import bb.event 133 import bb.event
110 import time, subprocess, platform 134 import time, subprocess, platform
111 135
112 bn = d.getVar('BUILDNAME') 136 bn = d.getVar('BUILDNAME')
113 bsdir = os.path.join(d.getVar('BUILDSTATS_BASE'), bn) 137 ########################################################################
114 taskdir = os.path.join(bsdir, d.getVar('PF')) 138 # bitbake fires HeartbeatEvent even before a build has been
139 # triggered, causing BUILDNAME to be None
140 ########################################################################
141 if bn is not None:
142 bsdir = os.path.join(d.getVar('BUILDSTATS_BASE'), bn)
143 taskdir = os.path.join(bsdir, d.getVar('PF'))
144 if isinstance(e, bb.event.HeartbeatEvent) and bb.utils.to_boolean(d.getVar("BB_LOG_HOST_STAT_ON_INTERVAL")):
145 bb.utils.mkdirhier(bsdir)
146 write_host_data(os.path.join(bsdir, "host_stats"), e, d)
115 147
116 if isinstance(e, bb.event.BuildStarted): 148 if isinstance(e, bb.event.BuildStarted):
117 ######################################################################## 149 ########################################################################
@@ -186,10 +218,12 @@ python run_buildstats () {
186 build_status = os.path.join(bsdir, "build_stats") 218 build_status = os.path.join(bsdir, "build_stats")
187 with open(build_status, "a") as f: 219 with open(build_status, "a") as f:
188 f.write(d.expand("Failed at: ${PF} at task: %s \n" % e.task)) 220 f.write(d.expand("Failed at: ${PF} at task: %s \n" % e.task))
221 if bb.utils.to_boolean(d.getVar("BB_LOG_HOST_STAT_ON_FAILURE")):
222 write_host_data(build_status, e, d)
189} 223}
190 224
191addhandler run_buildstats 225addhandler run_buildstats
192run_buildstats[eventmask] = "bb.event.BuildStarted bb.event.BuildCompleted bb.build.TaskStarted bb.build.TaskSucceeded bb.build.TaskFailed" 226run_buildstats[eventmask] = "bb.event.BuildStarted bb.event.BuildCompleted bb.event.HeartbeatEvent bb.build.TaskStarted bb.build.TaskSucceeded bb.build.TaskFailed"
193 227
194python runqueue_stats () { 228python runqueue_stats () {
195 import buildstats 229 import buildstats