summaryrefslogtreecommitdiffstats
path: root/scripts/pybootchartgui
diff options
context:
space:
mode:
authorPatrick Ohly <patrick.ohly@intel.com>2016-11-30 10:50:04 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2016-12-07 10:37:59 +0000
commit521887ea61b27b33023d6aac9df352d1fdef3ec0 (patch)
tree596664ce65044549cf11bf4ea0eef4cd90b69c13 /scripts/pybootchartgui
parenta2c20921956bac82ba8df5e36243e9706639a4b2 (diff)
downloadpoky-521887ea61b27b33023d6aac9df352d1fdef3ec0.tar.gz
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>
Diffstat (limited to 'scripts/pybootchartgui')
-rw-r--r--scripts/pybootchartgui/pybootchartgui/draw.py16
-rw-r--r--scripts/pybootchartgui/pybootchartgui/parsing.py61
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):
321 w = int ((end - start) * sec_w_base * xscale) + 2 * off_x 321 w = int ((end - start) * sec_w_base * xscale) + 2 * off_x
322 h = proc_h * processes + header_h + 2 * off_y 322 h = proc_h * processes + header_h + 2 * off_y
323 323
324 if options.charts:
325 if trace.cpu_stats:
326 h += 30 + bar_h
327 if trace.disk_stats:
328 h += 30 + bar_h
329 if trace.monitor_disk:
330 h += 30 + bar_h
331 if trace.mem_stats:
332 h += meminfo_bar_h
333
324 return (w, h) 334 return (w, h)
325 335
326def clip_visible(clip, rect): 336def clip_visible(clip, rect):
@@ -496,6 +506,9 @@ def render(ctx, options, xscale, trace):
496 w -= 2*off_x 506 w -= 2*off_x
497 curr_y = off_y; 507 curr_y = off_y;
498 508
509 if options.charts:
510 curr_y = render_charts (ctx, options, clip, trace, curr_y, w, h, sec_w)
511
499 curr_y = render_processes_chart (ctx, options, trace, curr_y, w, h, sec_w) 512 curr_y = render_processes_chart (ctx, options, trace, curr_y, w, h, sec_w)
500 513
501 return 514 return
@@ -513,9 +526,6 @@ def render(ctx, options, xscale, trace):
513 else: 526 else:
514 curr_y = off_y; 527 curr_y = off_y;
515 528
516 if options.charts:
517 curr_y = render_charts (ctx, options, clip, trace, curr_y, w, h, sec_w)
518
519 # draw process boxes 529 # draw process boxes
520 proc_height = h 530 proc_height = h
521 if proc_tree.taskstats and options.cumulative: 531 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:
38 self.min = None 38 self.min = None
39 self.max = None 39 self.max = None
40 self.headers = None 40 self.headers = None
41 self.disk_stats = None 41 self.disk_stats = []
42 self.ps_stats = None 42 self.ps_stats = None
43 self.taskstats = None 43 self.taskstats = None
44 self.cpu_stats = None 44 self.cpu_stats = []
45 self.cmdline = None 45 self.cmdline = None
46 self.kernel = None 46 self.kernel = None
47 self.kernel_tree = None 47 self.kernel_tree = None
48 self.filename = None 48 self.filename = None
49 self.parent_map = None 49 self.parent_map = None
50 self.mem_stats = None 50 self.mem_stats = []
51 self.times = [] # Always empty, but expected by draw.py when drawing system charts.
51 52
52 if len(paths): 53 if len(paths):
53 parse_paths (writer, self, paths) 54 parse_paths (writer, self, paths)
@@ -58,6 +59,19 @@ class Trace:
58 self.min = min(self.start.keys()) 59 self.min = min(self.start.keys())
59 self.max = max(self.end.keys()) 60 self.max = max(self.end.keys())
60 61
62
63 # Rendering system charts depends on start and end
64 # time. Provide them where the original drawing code expects
65 # them, i.e. in proc_tree.
66 class BitbakeProcessTree:
67 def __init__(self, start_time, end_time):
68 self.start_time = start_time
69 self.end_time = end_time
70 self.duration = self.end_time - self.start_time
71 self.proc_tree = BitbakeProcessTree(min(self.start.keys()),
72 max(self.end.keys()))
73
74
61 return 75 return
62 76
63 # Turn that parsed information into something more useful 77 # Turn that parsed information into something more useful
@@ -427,7 +441,7 @@ def _parse_proc_stat_log(file):
427 # skip the rest of statistics lines 441 # skip the rest of statistics lines
428 return samples 442 return samples
429 443
430def _parse_proc_disk_stat_log(file, numCpu): 444def _parse_proc_disk_stat_log(file):
431 """ 445 """
432 Parse file for disk stats, but only look at the whole device, eg. sda, 446 Parse file for disk stats, but only look at the whole device, eg. sda,
433 not sda1, sda2 etc. The format of relevant lines should be: 447 not sda1, sda2 etc. The format of relevant lines should be:
@@ -462,7 +476,7 @@ def _parse_proc_disk_stat_log(file, numCpu):
462 sums = [ a - b for a, b in zip(sample1.diskdata, sample2.diskdata) ] 476 sums = [ a - b for a, b in zip(sample1.diskdata, sample2.diskdata) ]
463 readTput = sums[0] / 2.0 * 100.0 / interval 477 readTput = sums[0] / 2.0 * 100.0 / interval
464 writeTput = sums[1] / 2.0 * 100.0 / interval 478 writeTput = sums[1] / 2.0 * 100.0 / interval
465 util = float( sums[2] ) / 10 / interval / numCpu 479 util = float( sums[2] ) / 10 / interval
466 util = max(0.0, min(1.0, util)) 480 util = max(0.0, min(1.0, util))
467 disk_stats.append(DiskSample(sample2.time, readTput, writeTput, util)) 481 disk_stats.append(DiskSample(sample2.time, readTput, writeTput, util))
468 482
@@ -628,6 +642,20 @@ def _parse_cmdline_log(writer, file):
628 cmdLines[pid] = values 642 cmdLines[pid] = values
629 return cmdLines 643 return cmdLines
630 644
645def _parse_bitbake_buildstats(writer, state, filename, file):
646 paths = filename.split("/")
647 task = paths[-1]
648 pn = paths[-2]
649 start = None
650 end = None
651 for line in file:
652 if line.startswith("Started:"):
653 start = int(float(line.split()[-1]))
654 elif line.startswith("Ended:"):
655 end = int(float(line.split()[-1]))
656 if start and end:
657 state.add_process(pn + ":" + task, start, end)
658
631def get_num_cpus(headers): 659def get_num_cpus(headers):
632 """Get the number of CPUs from the system.cpu header property. As the 660 """Get the number of CPUs from the system.cpu header property. As the
633 CPU utilization graphs are relative, the number of CPUs currently makes 661 CPU utilization graphs are relative, the number of CPUs currently makes
@@ -647,18 +675,17 @@ def get_num_cpus(headers):
647def _do_parse(writer, state, filename, file): 675def _do_parse(writer, state, filename, file):
648 writer.info("parsing '%s'" % filename) 676 writer.info("parsing '%s'" % filename)
649 t1 = clock() 677 t1 = clock()
650 paths = filename.split("/") 678 name = os.path.basename(filename)
651 task = paths[-1] 679 if name == "proc_diskstats.log":
652 pn = paths[-2] 680 state.disk_stats = _parse_proc_disk_stat_log(file)
653 start = None 681 elif name == "proc_stat.log":
654 end = None 682 state.cpu_stats = _parse_proc_stat_log(file)
655 for line in file: 683 elif name == "proc_meminfo.log":
656 if line.startswith("Started:"): 684 state.mem_stats = _parse_proc_meminfo_log(file)
657 start = int(float(line.split()[-1])) 685 elif name == "cmdline2.log":
658 elif line.startswith("Ended:"): 686 state.cmdline = _parse_cmdline_log(writer, file)
659 end = int(float(line.split()[-1])) 687 elif not filename.endswith('.log'):
660 if start and end: 688 _parse_bitbake_buildstats(writer, state, filename, file)
661 state.add_process(pn + ":" + task, start, end)
662 t2 = clock() 689 t2 = clock()
663 writer.info(" %s seconds" % str(t2-t1)) 690 writer.info(" %s seconds" % str(t2-t1))
664 return state 691 return state