pybootchartgui: show system utilization
This enables rendering of the original bootchart charts for CPU, disk and memory usage. It depends on the /proc samples recorded by the updated buildstats.bbclass. Currently, empty charts CPU and disk usage charts are drawn if that data is not present; the memory chart already gets skipped when there's no data, which will also have to be added for the other two. (From OE-Core rev: 233d3e50b361feea07803a9c0f2a691e687c6cd5) Signed-off-by: Patrick Ohly <patrick.ohly@intel.com> Signed-off-by: Ross Burton <ross.burton@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
parent
a2c2092195
commit
521887ea61
|
@ -321,6 +321,16 @@ def extents(options, xscale, trace):
|
|||
w = int ((end - start) * sec_w_base * xscale) + 2 * off_x
|
||||
h = proc_h * processes + header_h + 2 * off_y
|
||||
|
||||
if options.charts:
|
||||
if trace.cpu_stats:
|
||||
h += 30 + bar_h
|
||||
if trace.disk_stats:
|
||||
h += 30 + bar_h
|
||||
if trace.monitor_disk:
|
||||
h += 30 + bar_h
|
||||
if trace.mem_stats:
|
||||
h += meminfo_bar_h
|
||||
|
||||
return (w, h)
|
||||
|
||||
def clip_visible(clip, rect):
|
||||
|
@ -496,6 +506,9 @@ def render(ctx, options, xscale, trace):
|
|||
w -= 2*off_x
|
||||
curr_y = off_y;
|
||||
|
||||
if options.charts:
|
||||
curr_y = render_charts (ctx, options, clip, trace, curr_y, w, h, sec_w)
|
||||
|
||||
curr_y = render_processes_chart (ctx, options, trace, curr_y, w, h, sec_w)
|
||||
|
||||
return
|
||||
|
@ -513,9 +526,6 @@ def render(ctx, options, xscale, trace):
|
|||
else:
|
||||
curr_y = off_y;
|
||||
|
||||
if options.charts:
|
||||
curr_y = render_charts (ctx, options, clip, trace, curr_y, w, h, sec_w)
|
||||
|
||||
# draw process boxes
|
||||
proc_height = h
|
||||
if proc_tree.taskstats and options.cumulative:
|
||||
|
|
|
@ -38,16 +38,17 @@ class Trace:
|
|||
self.min = None
|
||||
self.max = None
|
||||
self.headers = None
|
||||
self.disk_stats = None
|
||||
self.disk_stats = []
|
||||
self.ps_stats = None
|
||||
self.taskstats = None
|
||||
self.cpu_stats = None
|
||||
self.cpu_stats = []
|
||||
self.cmdline = None
|
||||
self.kernel = None
|
||||
self.kernel_tree = None
|
||||
self.filename = None
|
||||
self.parent_map = None
|
||||
self.mem_stats = None
|
||||
self.mem_stats = []
|
||||
self.times = [] # Always empty, but expected by draw.py when drawing system charts.
|
||||
|
||||
if len(paths):
|
||||
parse_paths (writer, self, paths)
|
||||
|
@ -58,6 +59,19 @@ class Trace:
|
|||
self.min = min(self.start.keys())
|
||||
self.max = max(self.end.keys())
|
||||
|
||||
|
||||
# Rendering system charts depends on start and end
|
||||
# time. Provide them where the original drawing code expects
|
||||
# them, i.e. in proc_tree.
|
||||
class BitbakeProcessTree:
|
||||
def __init__(self, start_time, end_time):
|
||||
self.start_time = start_time
|
||||
self.end_time = end_time
|
||||
self.duration = self.end_time - self.start_time
|
||||
self.proc_tree = BitbakeProcessTree(min(self.start.keys()),
|
||||
max(self.end.keys()))
|
||||
|
||||
|
||||
return
|
||||
|
||||
# Turn that parsed information into something more useful
|
||||
|
@ -427,7 +441,7 @@ def _parse_proc_stat_log(file):
|
|||
# skip the rest of statistics lines
|
||||
return samples
|
||||
|
||||
def _parse_proc_disk_stat_log(file, numCpu):
|
||||
def _parse_proc_disk_stat_log(file):
|
||||
"""
|
||||
Parse file for disk stats, but only look at the whole device, eg. sda,
|
||||
not sda1, sda2 etc. The format of relevant lines should be:
|
||||
|
@ -462,7 +476,7 @@ def _parse_proc_disk_stat_log(file, numCpu):
|
|||
sums = [ a - b for a, b in zip(sample1.diskdata, sample2.diskdata) ]
|
||||
readTput = sums[0] / 2.0 * 100.0 / interval
|
||||
writeTput = sums[1] / 2.0 * 100.0 / interval
|
||||
util = float( sums[2] ) / 10 / interval / numCpu
|
||||
util = float( sums[2] ) / 10 / interval
|
||||
util = max(0.0, min(1.0, util))
|
||||
disk_stats.append(DiskSample(sample2.time, readTput, writeTput, util))
|
||||
|
||||
|
@ -628,6 +642,20 @@ def _parse_cmdline_log(writer, file):
|
|||
cmdLines[pid] = values
|
||||
return cmdLines
|
||||
|
||||
def _parse_bitbake_buildstats(writer, state, filename, file):
|
||||
paths = filename.split("/")
|
||||
task = paths[-1]
|
||||
pn = paths[-2]
|
||||
start = None
|
||||
end = None
|
||||
for line in file:
|
||||
if line.startswith("Started:"):
|
||||
start = int(float(line.split()[-1]))
|
||||
elif line.startswith("Ended:"):
|
||||
end = int(float(line.split()[-1]))
|
||||
if start and end:
|
||||
state.add_process(pn + ":" + task, start, end)
|
||||
|
||||
def get_num_cpus(headers):
|
||||
"""Get the number of CPUs from the system.cpu header property. As the
|
||||
CPU utilization graphs are relative, the number of CPUs currently makes
|
||||
|
@ -647,18 +675,17 @@ def get_num_cpus(headers):
|
|||
def _do_parse(writer, state, filename, file):
|
||||
writer.info("parsing '%s'" % filename)
|
||||
t1 = clock()
|
||||
paths = filename.split("/")
|
||||
task = paths[-1]
|
||||
pn = paths[-2]
|
||||
start = None
|
||||
end = None
|
||||
for line in file:
|
||||
if line.startswith("Started:"):
|
||||
start = int(float(line.split()[-1]))
|
||||
elif line.startswith("Ended:"):
|
||||
end = int(float(line.split()[-1]))
|
||||
if start and end:
|
||||
state.add_process(pn + ":" + task, start, end)
|
||||
name = os.path.basename(filename)
|
||||
if name == "proc_diskstats.log":
|
||||
state.disk_stats = _parse_proc_disk_stat_log(file)
|
||||
elif name == "proc_stat.log":
|
||||
state.cpu_stats = _parse_proc_stat_log(file)
|
||||
elif name == "proc_meminfo.log":
|
||||
state.mem_stats = _parse_proc_meminfo_log(file)
|
||||
elif name == "cmdline2.log":
|
||||
state.cmdline = _parse_cmdline_log(writer, file)
|
||||
elif not filename.endswith('.log'):
|
||||
_parse_bitbake_buildstats(writer, state, filename, file)
|
||||
t2 = clock()
|
||||
writer.info(" %s seconds" % str(t2-t1))
|
||||
return state
|
||||
|
|
Loading…
Reference in New Issue