diff options
author | Sakib Sajal <sakib.sajal@windriver.com> | 2020-11-10 10:59:15 -0500 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2021-01-17 11:28:13 +0000 |
commit | d068fbcde2c5dd159ab903e9696ef900514ce866 (patch) | |
tree | 8655f402c10c4ac447d3b97b1af954859e8a33ac /meta/classes | |
parent | 75c779b628f31f1376baedd968eafcfe3c188846 (diff) | |
download | poky-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>
Diffstat (limited to 'meta/classes')
-rw-r--r-- | meta/classes/buildstats.bbclass | 40 |
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 | ||
107 | def 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 | |||
107 | python run_buildstats () { | 131 | python 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 | ||
191 | addhandler run_buildstats | 225 | addhandler run_buildstats |
192 | run_buildstats[eventmask] = "bb.event.BuildStarted bb.event.BuildCompleted bb.build.TaskStarted bb.build.TaskSucceeded bb.build.TaskFailed" | 226 | run_buildstats[eventmask] = "bb.event.BuildStarted bb.event.BuildCompleted bb.event.HeartbeatEvent bb.build.TaskStarted bb.build.TaskSucceeded bb.build.TaskFailed" |
193 | 227 | ||
194 | python runqueue_stats () { | 228 | python runqueue_stats () { |
195 | import buildstats | 229 | import buildstats |