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 |