diff options
| author | Patrick Ohly <patrick.ohly@intel.com> | 2016-11-30 10:50:04 +0100 | 
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-12-07 10:36:10 +0000 | 
| commit | 233d3e50b361feea07803a9c0f2a691e687c6cd5 (patch) | |
| tree | d1f122f8c29f8f30e08a4f1eb5d0fe3fc3f5ed19 /scripts/pybootchartgui | |
| parent | 166f8f9aaa1f01fc6d6a5451f8f06b815c51ffae (diff) | |
| download | openembedded-core-233d3e50b361feea07803a9c0f2a691e687c6cd5.tar.gz openembedded-core-233d3e50b361feea07803a9c0f2a691e687c6cd5.tar.bz2 openembedded-core-233d3e50b361feea07803a9c0f2a691e687c6cd5.zip | |
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.
Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
Signed-off-by: Ross Burton <ross.burton@intel.com>
Diffstat (limited to 'scripts/pybootchartgui')
| -rw-r--r-- | scripts/pybootchartgui/pybootchartgui/draw.py | 16 | ||||
| -rw-r--r-- | scripts/pybootchartgui/pybootchartgui/parsing.py | 61 | 
2 files changed, 57 insertions, 20 deletions
| diff --git a/scripts/pybootchartgui/pybootchartgui/draw.py b/scripts/pybootchartgui/pybootchartgui/draw.py index 925002d6e8..bddd8048c9 100644 --- a/scripts/pybootchartgui/pybootchartgui/draw.py +++ b/scripts/pybootchartgui/pybootchartgui/draw.py @@ -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: diff --git a/scripts/pybootchartgui/pybootchartgui/parsing.py b/scripts/pybootchartgui/pybootchartgui/parsing.py index a3a0b0b339..af684353fd 100644 --- a/scripts/pybootchartgui/pybootchartgui/parsing.py +++ b/scripts/pybootchartgui/pybootchartgui/parsing.py @@ -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 | 
