summaryrefslogtreecommitdiffstats
path: root/scripts/pybootchartgui/pybootchartgui/parsing.py
diff options
context:
space:
mode:
authorRobert Yang <liezhi.yang@windriver.com>2012-06-06 14:00:48 +0800
committerRichard Purdie <richard.purdie@linuxfoundation.org>2012-06-15 15:12:42 +0100
commitbc5b86f025c9c1d9f0e1a58e92fe8c1381c096a5 (patch)
tree8c7af16040e4a25fb750673194c937f626ea5166 /scripts/pybootchartgui/pybootchartgui/parsing.py
parent3d78bc19c5b63541fd45dad7580ade55ba512764 (diff)
downloadpoky-bc5b86f025c9c1d9f0e1a58e92fe8c1381c096a5.tar.gz
pybootchartgui: make the build profiling in pictures
The original patch is from Richard, I rebased it to the up-to-date upstream code, here are the original messages from him: We have just merged Beth's initial buildstats logging work. I was sitting wondering how to actually evaluate the numbers as I wanted to know "where are we spending the time?". It occurred to me that I wanted a graph very similar to that generated by bootchart. I looked around and found pyboootchartgui and then hacked it around a bit and coerced it to start producing charts like: http://tim.rpsys.net/bootchart.png which is the initial "pseudo-native" part of the build. This was simple enough to test with. I then tried graphing a poky-image-sato. To get a graph I could actually read, I stripped out any task taking less than 8 seconds and scaled the x axis from 25 units per second to one unit per second. The result was: http://tim.rpsys.net/bootchart2.png (warning this is a 2.7MB png) I also added in a little bit of colour coding for the second chart. Interestingly it looks like there is more yellow than green meaning configure is a bigger drain on the build time not that its unexpected :/. I quite enjoyed playing with this and on a serious note, the gradient of the task graph makes me a little suspicious of whether the overhead of launching tasks in bitbake itself is having some effect on build time. Certainly on the first graph there are some interesting latencies showing up. Anyhow, I think this is the first time bitbake's task execution has been visualised and there are some interesting things we can learn from it. I'm hoping this is a start of a much more detailed understanding of the build process with respect to performance. [YOCTO #2403] (From OE-Core rev: 6ea0c02d0db08f6b4570769c6811ecdb051646ad) Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org> Signed-off-by: Robert Yang <liezhi.yang@windriver.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'scripts/pybootchartgui/pybootchartgui/parsing.py')
-rw-r--r--scripts/pybootchartgui/pybootchartgui/parsing.py47
1 files changed, 26 insertions, 21 deletions
diff --git a/scripts/pybootchartgui/pybootchartgui/parsing.py b/scripts/pybootchartgui/pybootchartgui/parsing.py
index a350a3eb08..11a082941c 100644
--- a/scripts/pybootchartgui/pybootchartgui/parsing.py
+++ b/scripts/pybootchartgui/pybootchartgui/parsing.py
@@ -160,34 +160,39 @@ def get_num_cpus(headers):
160 160
161class ParserState: 161class ParserState:
162 def __init__(self): 162 def __init__(self):
163 self.headers = None 163 self.processes = {}
164 self.disk_stats = None 164 self.start = {}
165 self.ps_stats = None 165 self.end = {}
166 self.cpu_stats = None
167 166
168 def valid(self): 167 def valid(self):
169 return self.headers != None and self.disk_stats != None and self.ps_stats != None and self.cpu_stats != None 168 return len(self.processes) != 0
170 169
171 170
172_relevant_files = set(["header", "proc_diskstats.log", "proc_ps.log", "proc_stat.log"]) 171_relevant_files = set(["header", "proc_diskstats.log", "proc_ps.log", "proc_stat.log"])
173 172
174def _do_parse(state, name, file): 173def _do_parse(state, filename, file):
175 if name == "header": 174 #print filename
176 state.headers = _parse_headers(file) 175 #writer.status("parsing '%s'" % filename)
177 elif name == "proc_diskstats.log": 176 paths = filename.split("/")
178 state.disk_stats = _parse_proc_disk_stat_log(file, get_num_cpus(state.headers)) 177 task = paths[-1]
179 elif name == "proc_ps.log": 178 pn = paths[-2]
180 state.ps_stats = _parse_proc_ps_log(file) 179 start = None
181 elif name == "proc_stat.log": 180 end = None
182 state.cpu_stats = _parse_proc_stat_log(file) 181 for line in file:
182 if line.startswith("Started:"):
183 start = int(float(line.split()[-1]))
184 elif line.startswith("Ended:"):
185 end = int(float(line.split()[-1]))
186 if start and end and (end - start) > 8:
187 state.processes[pn + ":" + task] = [start, end]
188 state.start[start] = pn + ":" + task
189 state.end[end] = pn + ":" + task
183 return state 190 return state
184 191
185def parse_file(state, filename): 192def parse_file(state, filename):
186 basename = os.path.basename(filename) 193 basename = os.path.basename(filename)
187 if not(basename in _relevant_files):
188 return state
189 with open(filename, "rb") as file: 194 with open(filename, "rb") as file:
190 return _do_parse(state, basename, file) 195 return _do_parse(state, filename, file)
191 196
192def parse_paths(state, paths): 197def parse_paths(state, paths):
193 for path in paths: 198 for path in paths:
@@ -196,7 +201,7 @@ def parse_paths(state, paths):
196 print "warning: path '%s' does not exist, ignoring." % path 201 print "warning: path '%s' does not exist, ignoring." % path
197 continue 202 continue
198 if os.path.isdir(path): 203 if os.path.isdir(path):
199 files = [ f for f in [os.path.join(path, f) for f in os.listdir(path)] if os.path.isfile(f) ] 204 files = [ f for f in [os.path.join(path, f) for f in os.listdir(path)] ]
200 files.sort() 205 files.sort()
201 state = parse_paths(state, files) 206 state = parse_paths(state, files)
202 elif extension in [".tar", ".tgz", ".tar.gz"]: 207 elif extension in [".tar", ".tgz", ".tar.gz"]:
@@ -218,6 +223,6 @@ def parse(paths, prune):
218 state = parse_paths(ParserState(), paths) 223 state = parse_paths(ParserState(), paths)
219 if not state.valid(): 224 if not state.valid():
220 raise ParseError("empty state: '%s' does not contain a valid bootchart" % ", ".join(paths)) 225 raise ParseError("empty state: '%s' does not contain a valid bootchart" % ", ".join(paths))
221 monitored_app = state.headers.get("profile.process") 226 #monitored_app = state.headers.get("profile.process")
222 proc_tree = ProcessTree(state.ps_stats, monitored_app, prune) 227 #proc_tree = ProcessTree(state.ps_stats, monitored_app, prune)
223 return (state.headers, state.cpu_stats, state.disk_stats, proc_tree) 228 return state