diff options
| -rw-r--r-- | scripts/pybootchartgui/pybootchartgui/draw.py | 62 | ||||
| -rw-r--r-- | scripts/pybootchartgui/pybootchartgui/parsing.py | 26 | ||||
| -rw-r--r-- | scripts/pybootchartgui/pybootchartgui/samples.py | 11 |
3 files changed, 99 insertions, 0 deletions
diff --git a/scripts/pybootchartgui/pybootchartgui/draw.py b/scripts/pybootchartgui/pybootchartgui/draw.py index ec5dd333a1..f0143ad0d6 100644 --- a/scripts/pybootchartgui/pybootchartgui/draw.py +++ b/scripts/pybootchartgui/pybootchartgui/draw.py | |||
| @@ -133,6 +133,16 @@ TASK_COLOR_PACKAGE = (0.0, 1.00, 1.00, 1.0) | |||
| 133 | # Package Write RPM/DEB/IPK task color | 133 | # Package Write RPM/DEB/IPK task color |
| 134 | TASK_COLOR_PACKAGE_WRITE = (0.0, 0.50, 0.50, 1.0) | 134 | TASK_COLOR_PACKAGE_WRITE = (0.0, 0.50, 0.50, 1.0) |
| 135 | 135 | ||
| 136 | # Distinct colors used for different disk volumnes. | ||
| 137 | # If we have more volumns, colors get re-used. | ||
| 138 | VOLUME_COLORS = [ | ||
| 139 | (1.0, 1.0, 0.00, 1.0), | ||
| 140 | (0.0, 1.00, 0.00, 1.0), | ||
| 141 | (1.0, 0.00, 1.00, 1.0), | ||
| 142 | (0.0, 0.00, 1.00, 1.0), | ||
| 143 | (0.0, 1.00, 1.00, 1.0), | ||
| 144 | ] | ||
| 145 | |||
| 136 | # Process states | 146 | # Process states |
| 137 | STATE_UNDEFINED = 0 | 147 | STATE_UNDEFINED = 0 |
| 138 | STATE_RUNNING = 1 | 148 | STATE_RUNNING = 1 |
| @@ -397,6 +407,58 @@ def render_charts(ctx, options, clip, trace, curr_y, w, h, sec_w): | |||
| 397 | 407 | ||
| 398 | curr_y = curr_y + 30 + bar_h | 408 | curr_y = curr_y + 30 + bar_h |
| 399 | 409 | ||
| 410 | # render disk space usage | ||
| 411 | # | ||
| 412 | # Draws the amount of disk space used on each volume relative to the | ||
| 413 | # lowest recorded amount. The graphs for each volume are stacked above | ||
| 414 | # each other so that total disk usage is visible. | ||
| 415 | if trace.monitor_disk: | ||
| 416 | ctx.set_font_size(LEGEND_FONT_SIZE) | ||
| 417 | # Determine set of volumes for which we have | ||
| 418 | # information and the minimal amount of used disk | ||
| 419 | # space for each. Currently samples are allowed to | ||
| 420 | # not have a values for all volumes; drawing could be | ||
| 421 | # made more efficient if that wasn't the case. | ||
| 422 | volumes = set() | ||
| 423 | min_used = {} | ||
| 424 | for sample in trace.monitor_disk: | ||
| 425 | for volume, used in sample.records.items(): | ||
| 426 | volumes.add(volume) | ||
| 427 | if volume not in min_used or min_used[volume] > used: | ||
| 428 | min_used[volume] = used | ||
| 429 | volumes = sorted(list(volumes)) | ||
| 430 | disk_scale = 0 | ||
| 431 | for i, volume in enumerate(volumes): | ||
| 432 | volume_scale = max([sample.records[volume] - min_used[volume] | ||
| 433 | for sample in trace.monitor_disk | ||
| 434 | if volume in sample.records]) | ||
| 435 | # Does not take length of volume name into account, but fixed offset | ||
| 436 | # works okay in practice. | ||
| 437 | draw_legend_box(ctx, '%s (max: %u MiB)' % (volume, volume_scale / 1024 / 1024), | ||
| 438 | VOLUME_COLORS[i % len(VOLUME_COLORS)], | ||
| 439 | off_x + i * 250, curr_y+20, leg_s) | ||
| 440 | disk_scale += volume_scale | ||
| 441 | |||
| 442 | # render used amount of disk space | ||
| 443 | chart_rect = (off_x, curr_y+30, w, bar_h) | ||
| 444 | if clip_visible (clip, chart_rect): | ||
| 445 | draw_box_ticks (ctx, chart_rect, sec_w) | ||
| 446 | draw_annotations (ctx, proc_tree, trace.times, chart_rect) | ||
| 447 | for i in range(len(volumes), 0, -1): | ||
| 448 | draw_chart (ctx, VOLUME_COLORS[(i - 1) % len(VOLUME_COLORS)], True, chart_rect, \ | ||
| 449 | [(sample.time, | ||
| 450 | # Sum up used space of all volumes including the current one | ||
| 451 | # so that the graphs appear as stacked on top of each other. | ||
| 452 | reduce(lambda x,y: x+y, | ||
| 453 | [sample.records[volume] - min_used[volume] | ||
| 454 | for volume in volumes[0:i] | ||
| 455 | if volume in sample.records], | ||
| 456 | 0)) | ||
| 457 | for sample in trace.monitor_disk], \ | ||
| 458 | proc_tree, [0, disk_scale]) | ||
| 459 | |||
| 460 | curr_y = curr_y + 30 + bar_h | ||
| 461 | |||
| 400 | # render mem usage | 462 | # render mem usage |
| 401 | chart_rect = (off_x, curr_y+30, w, meminfo_bar_h) | 463 | chart_rect = (off_x, curr_y+30, w, meminfo_bar_h) |
| 402 | mem_stats = trace.mem_stats | 464 | mem_stats = trace.mem_stats |
diff --git a/scripts/pybootchartgui/pybootchartgui/parsing.py b/scripts/pybootchartgui/pybootchartgui/parsing.py index 48eb048dae..301145ab67 100644 --- a/scripts/pybootchartgui/pybootchartgui/parsing.py +++ b/scripts/pybootchartgui/pybootchartgui/parsing.py | |||
| @@ -48,6 +48,7 @@ class Trace: | |||
| 48 | self.filename = None | 48 | self.filename = None |
| 49 | self.parent_map = None | 49 | self.parent_map = None |
| 50 | self.mem_stats = [] | 50 | self.mem_stats = [] |
| 51 | self.monitor_disk = None | ||
| 51 | self.times = [] # Always empty, but expected by draw.py when drawing system charts. | 52 | self.times = [] # Always empty, but expected by draw.py when drawing system charts. |
| 52 | 53 | ||
| 53 | if len(paths): | 54 | if len(paths): |
| @@ -506,6 +507,29 @@ def _parse_proc_meminfo_log(file): | |||
| 506 | 507 | ||
| 507 | return mem_stats | 508 | return mem_stats |
| 508 | 509 | ||
| 510 | def _parse_monitor_disk_log(file): | ||
| 511 | """ | ||
| 512 | Parse file with information about amount of diskspace used. | ||
| 513 | The format of relevant lines should be: ^volume path: number-of-bytes? | ||
| 514 | """ | ||
| 515 | disk_stats = [] | ||
| 516 | diskinfo_re = re.compile(r'^(.+):\s*(\d+)$') | ||
| 517 | |||
| 518 | for time, lines in _parse_timed_blocks(file): | ||
| 519 | sample = DiskSpaceSample(time) | ||
| 520 | |||
| 521 | for line in lines: | ||
| 522 | match = diskinfo_re.match(line) | ||
| 523 | if not match: | ||
| 524 | raise ParseError("Invalid monitor_disk line \"%s\"" % line) | ||
| 525 | sample.add_value(match.group(1), int(match.group(2))) | ||
| 526 | |||
| 527 | if sample.valid(): | ||
| 528 | disk_stats.append(sample) | ||
| 529 | |||
| 530 | return disk_stats | ||
| 531 | |||
| 532 | |||
| 509 | # if we boot the kernel with: initcall_debug printk.time=1 we can | 533 | # if we boot the kernel with: initcall_debug printk.time=1 we can |
| 510 | # get all manner of interesting data from the dmesg output | 534 | # get all manner of interesting data from the dmesg output |
| 511 | # We turn this into a pseudo-process tree: each event is | 535 | # We turn this into a pseudo-process tree: each event is |
| @@ -684,6 +708,8 @@ def _do_parse(writer, state, filename, file): | |||
| 684 | state.mem_stats = _parse_proc_meminfo_log(file) | 708 | state.mem_stats = _parse_proc_meminfo_log(file) |
| 685 | elif name == "cmdline2.log": | 709 | elif name == "cmdline2.log": |
| 686 | state.cmdline = _parse_cmdline_log(writer, file) | 710 | state.cmdline = _parse_cmdline_log(writer, file) |
| 711 | elif name == "monitor_disk.log": | ||
| 712 | state.monitor_disk = _parse_monitor_disk_log(file) | ||
| 687 | elif not filename.endswith('.log'): | 713 | elif not filename.endswith('.log'): |
| 688 | _parse_bitbake_buildstats(writer, state, filename, file) | 714 | _parse_bitbake_buildstats(writer, state, filename, file) |
| 689 | t2 = clock() | 715 | t2 = clock() |
diff --git a/scripts/pybootchartgui/pybootchartgui/samples.py b/scripts/pybootchartgui/pybootchartgui/samples.py index 015d743aa0..bedca4165a 100644 --- a/scripts/pybootchartgui/pybootchartgui/samples.py +++ b/scripts/pybootchartgui/pybootchartgui/samples.py | |||
| @@ -53,6 +53,17 @@ class MemSample: | |||
| 53 | # discard incomplete samples | 53 | # discard incomplete samples |
| 54 | return [v for v in MemSample.used_values if v not in keys] == [] | 54 | return [v for v in MemSample.used_values if v not in keys] == [] |
| 55 | 55 | ||
| 56 | class DiskSpaceSample: | ||
| 57 | def __init__(self, time): | ||
| 58 | self.time = time | ||
| 59 | self.records = {} | ||
| 60 | |||
| 61 | def add_value(self, name, value): | ||
| 62 | self.records[name] = value | ||
| 63 | |||
| 64 | def valid(self): | ||
| 65 | return bool(self.records) | ||
| 66 | |||
| 56 | class ProcessSample: | 67 | class ProcessSample: |
| 57 | def __init__(self, time, state, cpu_sample): | 68 | def __init__(self, time, state, cpu_sample): |
| 58 | self.time = time | 69 | self.time = time |
