summaryrefslogtreecommitdiffstats
path: root/meta/classes/buildstats.bbclass
diff options
context:
space:
mode:
authorBeth Flanagan <elizabeth.flanagan@intel.com>2011-02-12 16:25:09 -0800
committerRichard Purdie <richard.purdie@linuxfoundation.org>2011-02-15 09:59:51 +0000
commit411056041b23631548ad2fa467152eb52c32a0ea (patch)
treeea5ba9a9475b8c8191a579a965c23d5f4504c90e /meta/classes/buildstats.bbclass
parent6cb8fd6def4912e4aa76330649ba42a9ed2694fd (diff)
downloadpoky-411056041b23631548ad2fa467152eb52c32a0ea.tar.gz
Buildstats commit: buildstats.bbclass
Used to track some basic build metrics by build and task/event level. Signed-off-by: Beth Flanagan <elizabeth.flanagan@intel.com>
Diffstat (limited to 'meta/classes/buildstats.bbclass')
-rw-r--r--meta/classes/buildstats.bbclass194
1 files changed, 194 insertions, 0 deletions
diff --git a/meta/classes/buildstats.bbclass b/meta/classes/buildstats.bbclass
new file mode 100644
index 0000000000..f57d018060
--- /dev/null
+++ b/meta/classes/buildstats.bbclass
@@ -0,0 +1,194 @@
1BUILDSTATS_BASE = ${TMPDIR}/buildstats/
2BNFILE = ${BUILDSTATS_BASE}/.buildname
3
4################################################################################
5# Build statistics gathering.
6#
7# The CPU and Time gathering/tracking functions and bbevent inspiration
8# were written by Christopher Larson and can be seen here:
9# http://kergoth.pastey.net/142813
10#
11################################################################################
12
13def get_process_cputime(pid):
14 fields = open("/proc/%d/stat" % pid, "r").readline().rstrip().split()
15 # 13: utime, 14: stime, 15: cutime, 16: cstime
16 return sum(int(field) for field in fields[13:16])
17
18def get_cputime():
19 fields = open("/proc/stat", "r").readline().rstrip().split()[1:]
20 return sum(int(field) for field in fields)
21
22def set_timedata(var, data):
23 import time
24
25 time = time.time()
26 cputime = get_cputime()
27 proctime = get_process_cputime(os.getpid())
28 data.setVar(var, (time, cputime, proctime))
29
30def get_timedata(var, data):
31 import time
32 timedata = data.getVar(var, False)
33 if timedata is None:
34 return
35 oldtime, oldcpu, oldproc = timedata
36 procdiff = get_process_cputime(os.getpid()) - oldproc
37 cpudiff = get_cputime() - oldcpu
38 timediff = time.time() - oldtime
39 if cpudiff > 0:
40 cpuperc = float(procdiff) * 100 / cpudiff
41 else:
42 cpuperc = None
43 return timediff, cpuperc
44
45##############################################
46# We need to set the buildname to a file since
47# BUILDNAME changes throughout a build
48##############################################
49
50def set_bn(e):
51 bn = e.getPkgs()[0] + "-" + bb.data.getVar('MACHINE',e.data, True)
52 try:
53 os.remove(bb.data.getVar('BNFILE',e.data, True))
54 except:
55 pass
56 file = open(bb.data.getVar('BNFILE',e.data, True), "w")
57 file.write(os.path.join(bn, bb.data.getVar('BUILDNAME', e.data, True)))
58 file.close()
59
60def get_bn(e):
61 file = open(bb.data.getVar('BNFILE',e.data, True))
62 bn = file.readline()
63 file.close()
64 return bn
65
66python run_buildstats () {
67 import bb.build
68 import bb.event
69 import bb.data
70 import time, subprocess
71
72 if isinstance(e, bb.event.BuildStarted):
73 ##############################################
74 # at first pass make the buildstats heriarchy and then
75 # set the buildname
76 ##############################################
77 try:
78 bb.mkdirhier(bb.data.getVar('BUILDSTATS_BASE', e.data, True))
79 except:
80 pass
81 set_bn(e)
82 bn = get_bn(e)
83 bb.warn(bn)
84 bsdir = os.path.join(bb.data.getVar('BUILDSTATS_BASE', e.data, True), bn)
85 try:
86 bb.mkdirhier(bsdir)
87 except:
88 pass
89 set_timedata("__timedata_build", e.data)
90 build_time = os.path.join(bsdir, "build_stats")
91 # write start of build into build_time
92 file = open(build_time,"a")
93 # We do this here because subprocess within BuildStarted is messy
94 host_info = subprocess.Popen(["uname", "-a"], stdout=subprocess.PIPE).stdout.read()
95 file.write("Host Info: %s" % host_info)
96 file.write("Build Started: %0.2f \n" % time.time())
97 file.close()
98
99 elif isinstance(e, bb.event.BuildCompleted):
100 bn=get_bn(e)
101 timedata = get_timedata("__timedata_build", e.data)
102 if not timedata:
103 return
104 time, cpu = timedata
105 bsdir = os.path.join(bb.data.getVar('BUILDSTATS_BASE', e.data, True), bn)
106 build_time = os.path.join(bsdir, "build_stats")
107 # write end of build and cpu used into build_time
108 file = open(build_time, "a")
109 file.write("Elapsed time: %0.2f seconds \n" % (time))
110 if cpu:
111 file.write("CPU usage: %0.1f%% \n" % cpu)
112 file.close()
113
114
115 if isinstance(e, bb.build.TaskStarted):
116 bn=get_bn(e)
117 set_timedata("__timedata_task", e.data)
118
119 bsdir = os.path.join(bb.data.getVar('BUILDSTATS_BASE', e.data, True), bn)
120 taskdir = os.path.join(bsdir, bb.data.expand("${PF}", e.data))
121 try:
122 bb.mkdirhier(taskdir)
123 except:
124 pass
125 # write into the task event file the name and start time
126 file = open(os.path.join(taskdir, e.task), "a")
127 file.write("Event: %s \n" % bb.event.getName(e))
128 file.write("Started: %0.2f \n" % time.time())
129 file.close()
130
131 elif isinstance(e, bb.build.TaskSucceeded):
132 bn=get_bn(e)
133 timedata = get_timedata("__timedata_task", e.data)
134 if not timedata:
135 return
136 time, cpu = timedata
137 bsdir = os.path.join(bb.data.getVar('BUILDSTATS_BASE', e.data, True), bn)
138 taskdir = os.path.join(bsdir, bb.data.expand("${PF}", e.data))
139 file = open(os.path.join(taskdir, e.task), "a")
140 file.write(bb.data.expand("${PF}: %s: Elapsed time: %0.2f seconds \n" %
141 (e.task, time), e.data))
142 if cpu:
143 file.write("CPU usage: %0.1f%% \n" % cpu)
144
145 file.write("Status: PASSED")
146 file.close()
147
148 ##############################################
149 # Alot of metric gathering occurs here.
150 # Reminder: I stripped out some in process stuff here
151 ##############################################
152
153 if e.task == "do_rootfs":
154 bs=os.path.join(bsdir, "build_stats")
155 file = open(bs,"a")
156 rootfs = bb.data.getVar('IMAGE_ROOTFS', e.data, True)
157 rootfs_size = subprocess.Popen(["du", "-sh", rootfs], stdout=subprocess.PIPE).stdout.read()
158 file.write("Uncompressed Rootfs size: %s" % rootfs_size)
159 file.close()
160
161 elif isinstance(e, bb.build.TaskFailed):
162 bn=get_bn(e)
163 timedata = get_timedata("__timedata_task", e.data)
164 if not timedata:
165 return
166 time, cpu = timedata
167 bsdir = os.path.join(bb.data.getVar('BUILDSTATS_BASE', e.data, True), bn)
168 taskdir = os.path.join(bsdir, bb.data.expand("${PF}", e.data))
169 ##############################################
170 # If the task fails dump the regular data.
171 # fgrep -R "FAILED" <bsdir>
172 # will grep all the events that failed.
173 ##############################################
174 file = open(os.path.join(taskdir, e.task), "a")
175 file.write(bb.data.expand("${PF}: %s: Elapsed time: %0.2f seconds \n" %
176 (e.task, time), e.data))
177 if cpu:
178 file.write("CPU usage: %0.1f%% \n" % cpu)
179 file.write("Status: FAILED")
180 file.close()
181 ##############################################
182 # Lets make things easier and tell people where the build failed in build_status
183 # We do this here because BuildCompleted triggers no matter what the status of the
184 # build actually is
185 ##############################################
186 build_status = os.path.join(bsdir, "build_stats")
187 file = open(build_status,"a")
188 file.write(bb.data.expand("Failed at: ${PF} at task: %s \n", e.task))
189 file.close()
190
191}
192
193addhandler run_buildstats
194