diff options
Diffstat (limited to 'scripts/pybootchartgui')
-rw-r--r-- | scripts/pybootchartgui/pybootchartgui/draw.py | 206 | ||||
-rw-r--r-- | scripts/pybootchartgui/pybootchartgui/parsing.py | 63 | ||||
-rw-r--r-- | scripts/pybootchartgui/pybootchartgui/samples.py | 35 |
3 files changed, 289 insertions, 15 deletions
diff --git a/scripts/pybootchartgui/pybootchartgui/draw.py b/scripts/pybootchartgui/pybootchartgui/draw.py index 53324b9f8b..16739a0fa1 100644 --- a/scripts/pybootchartgui/pybootchartgui/draw.py +++ b/scripts/pybootchartgui/pybootchartgui/draw.py | |||
@@ -69,6 +69,11 @@ CPU_COLOR = (0.40, 0.55, 0.70, 1.0) | |||
69 | IO_COLOR = (0.76, 0.48, 0.48, 0.5) | 69 | IO_COLOR = (0.76, 0.48, 0.48, 0.5) |
70 | # Disk throughput color. | 70 | # Disk throughput color. |
71 | DISK_TPUT_COLOR = (0.20, 0.71, 0.20, 1.0) | 71 | DISK_TPUT_COLOR = (0.20, 0.71, 0.20, 1.0) |
72 | |||
73 | BYTES_RECEIVED_COLOR = (0.0, 0.0, 1.0, 1.0) | ||
74 | BYTES_TRANSMITTED_COLOR = (1.0, 0.0, 0.0, 1.0) | ||
75 | BYTES_RECEIVE_DIFF_COLOR = (0.0, 0.0, 1.0, 0.3) | ||
76 | BYTES_TRANSMIT_DIFF_COLOR = (1.0, 0.0, 0.0, 0.3) | ||
72 | # CPU load chart color. | 77 | # CPU load chart color. |
73 | FILE_OPEN_COLOR = (0.20, 0.71, 0.71, 1.0) | 78 | FILE_OPEN_COLOR = (0.20, 0.71, 0.71, 1.0) |
74 | # Mem cached color | 79 | # Mem cached color |
@@ -80,6 +85,22 @@ MEM_BUFFERS_COLOR = (0.4, 0.4, 0.4, 0.3) | |||
80 | # Swap color | 85 | # Swap color |
81 | MEM_SWAP_COLOR = DISK_TPUT_COLOR | 86 | MEM_SWAP_COLOR = DISK_TPUT_COLOR |
82 | 87 | ||
88 | # avg10 CPU pressure color | ||
89 | CPU_PRESSURE_AVG10_COLOR = (0.0, 0.0, 0.0, 1.0) | ||
90 | # delta total CPU pressure color | ||
91 | CPU_PRESSURE_TOTAL_COLOR = CPU_COLOR | ||
92 | # avg10 IO pressure color | ||
93 | IO_PRESSURE_AVG10_COLOR = (0.0, 0.0, 0.0, 1.0) | ||
94 | # delta total IO pressure color | ||
95 | IO_PRESSURE_TOTAL_COLOR = IO_COLOR | ||
96 | # avg10 memory pressure color | ||
97 | MEM_PRESSURE_AVG10_COLOR = (0.0, 0.0, 0.0, 1.0) | ||
98 | # delta total memory pressure color | ||
99 | MEM_PRESSURE_TOTAL_COLOR = DISK_TPUT_COLOR | ||
100 | |||
101 | |||
102 | |||
103 | |||
83 | # Process border color. | 104 | # Process border color. |
84 | PROC_BORDER_COLOR = (0.71, 0.71, 0.71, 1.0) | 105 | PROC_BORDER_COLOR = (0.71, 0.71, 0.71, 1.0) |
85 | # Waiting process color. | 106 | # Waiting process color. |
@@ -267,11 +288,14 @@ def draw_chart(ctx, color, fill, chart_bounds, data, proc_tree, data_range): | |||
267 | # avoid divide by zero | 288 | # avoid divide by zero |
268 | if max_y == 0: | 289 | if max_y == 0: |
269 | max_y = 1.0 | 290 | max_y = 1.0 |
270 | xscale = float (chart_bounds[2]) / (max_x - x_shift) | 291 | if (max_x - x_shift): |
292 | xscale = float (chart_bounds[2]) / (max_x - x_shift) | ||
293 | else: | ||
294 | xscale = float (chart_bounds[2]) | ||
271 | # If data_range is given, scale the chart so that the value range in | 295 | # If data_range is given, scale the chart so that the value range in |
272 | # data_range matches the chart bounds exactly. | 296 | # data_range matches the chart bounds exactly. |
273 | # Otherwise, scale so that the actual data matches the chart bounds. | 297 | # Otherwise, scale so that the actual data matches the chart bounds. |
274 | if data_range: | 298 | if data_range and (data_range[1] - data_range[0]): |
275 | yscale = float(chart_bounds[3]) / (data_range[1] - data_range[0]) | 299 | yscale = float(chart_bounds[3]) / (data_range[1] - data_range[0]) |
276 | ybase = data_range[0] | 300 | ybase = data_range[0] |
277 | else: | 301 | else: |
@@ -337,6 +361,12 @@ def extents(options, xscale, trace): | |||
337 | h += 30 + bar_h | 361 | h += 30 + bar_h |
338 | if trace.disk_stats: | 362 | if trace.disk_stats: |
339 | h += 30 + bar_h | 363 | h += 30 + bar_h |
364 | if trace.cpu_pressure: | ||
365 | h += 30 + bar_h | ||
366 | if trace.io_pressure: | ||
367 | h += 30 + bar_h | ||
368 | if trace.mem_pressure: | ||
369 | h += 30 + bar_h | ||
340 | if trace.monitor_disk: | 370 | if trace.monitor_disk: |
341 | h += 30 + bar_h | 371 | h += 30 + bar_h |
342 | if trace.mem_stats: | 372 | if trace.mem_stats: |
@@ -412,6 +442,151 @@ def render_charts(ctx, options, clip, trace, curr_y, w, h, sec_w): | |||
412 | 442 | ||
413 | curr_y = curr_y + 30 + bar_h | 443 | curr_y = curr_y + 30 + bar_h |
414 | 444 | ||
445 | if trace.net_stats: | ||
446 | for iface, samples in trace.net_stats.items(): | ||
447 | max_received_sample = max(samples, key=lambda s: s.received_bytes) | ||
448 | max_transmitted_sample = max(samples, key=lambda s: s.transmitted_bytes) | ||
449 | max_receive_diff_sample = max(samples, key=lambda s: s.receive_diff) | ||
450 | max_transmit_diff_sample = max(samples, key=lambda s: s.transmit_diff) | ||
451 | |||
452 | draw_text(ctx, "Iface: %s" % (iface), TEXT_COLOR, off_x, curr_y+20) | ||
453 | draw_legend_line(ctx, "Bytes received (max %d)" % (max_received_sample.received_bytes), | ||
454 | BYTES_RECEIVED_COLOR, off_x+150, curr_y+20, leg_s) | ||
455 | draw_legend_line(ctx, "Bytes transmitted (max %d)" % (max_transmitted_sample.transmitted_bytes), | ||
456 | BYTES_TRANSMITTED_COLOR, off_x+400, curr_y+20, leg_s) | ||
457 | draw_legend_box(ctx, "Bytes receive diff (max %d)" % (max_receive_diff_sample.receive_diff), | ||
458 | BYTES_RECEIVE_DIFF_COLOR, off_x+650, curr_y+20, leg_s) | ||
459 | draw_legend_box(ctx, "Bytes transmit diff (max %d)" % (max_transmit_diff_sample.transmit_diff), | ||
460 | BYTES_TRANSMIT_DIFF_COLOR, off_x+900, curr_y+20, leg_s) | ||
461 | |||
462 | |||
463 | chart_rect = (off_x, curr_y + 30, w, bar_h) | ||
464 | if clip_visible(clip, chart_rect): | ||
465 | draw_box_ticks(ctx, chart_rect, sec_w) | ||
466 | draw_annotations(ctx, proc_tree, trace.times, chart_rect) | ||
467 | |||
468 | if clip_visible (clip, chart_rect): | ||
469 | draw_chart (ctx, BYTES_RECEIVED_COLOR, False, chart_rect, \ | ||
470 | [(sample.time, sample.received_bytes) for sample in samples], \ | ||
471 | proc_tree, None) | ||
472 | |||
473 | draw_chart (ctx, BYTES_TRANSMITTED_COLOR, False, chart_rect, \ | ||
474 | [(sample.time, sample.transmitted_bytes) for sample in samples], \ | ||
475 | proc_tree, None) | ||
476 | |||
477 | if clip_visible (clip, chart_rect): | ||
478 | draw_chart (ctx, BYTES_RECEIVE_DIFF_COLOR, True, chart_rect, \ | ||
479 | [(sample.time, sample.receive_diff) for sample in samples], \ | ||
480 | proc_tree, None) | ||
481 | |||
482 | draw_chart (ctx, BYTES_TRANSMIT_DIFF_COLOR, True, chart_rect, \ | ||
483 | [(sample.time, sample.transmit_diff) for sample in samples], \ | ||
484 | proc_tree, None) | ||
485 | |||
486 | curr_y = curr_y + 30 + bar_h | ||
487 | |||
488 | # render CPU pressure chart | ||
489 | if trace.cpu_pressure: | ||
490 | max_sample_avg = max (trace.cpu_pressure, key = lambda s: s.avg10) | ||
491 | max_sample_total = max (trace.cpu_pressure, key = lambda s: s.deltaTotal) | ||
492 | draw_legend_line(ctx, "avg10 CPU Pressure (max %d%%)" % (max_sample_avg.avg10), CPU_PRESSURE_AVG10_COLOR, off_x, curr_y+20, leg_s) | ||
493 | draw_legend_box(ctx, "delta total CPU Pressure (max %d)" % (max_sample_total.deltaTotal), CPU_PRESSURE_TOTAL_COLOR, off_x + 240, curr_y+20, leg_s) | ||
494 | |||
495 | # render delta total cpu | ||
496 | chart_rect = (off_x, curr_y+30, w, bar_h) | ||
497 | if clip_visible (clip, chart_rect): | ||
498 | draw_box_ticks (ctx, chart_rect, sec_w) | ||
499 | draw_annotations (ctx, proc_tree, trace.times, chart_rect) | ||
500 | draw_chart (ctx, CPU_PRESSURE_TOTAL_COLOR, True, chart_rect, \ | ||
501 | [(sample.time, sample.deltaTotal) for sample in trace.cpu_pressure], \ | ||
502 | proc_tree, None) | ||
503 | |||
504 | # render avg10 cpu | ||
505 | if clip_visible (clip, chart_rect): | ||
506 | draw_chart (ctx, CPU_PRESSURE_AVG10_COLOR, False, chart_rect, \ | ||
507 | [(sample.time, sample.avg10) for sample in trace.cpu_pressure], \ | ||
508 | proc_tree, None) | ||
509 | |||
510 | pos_x = off_x + ((max_sample_avg.time - proc_tree.start_time) * w / proc_tree.duration) | ||
511 | |||
512 | shift_x, shift_y = -20, 20 | ||
513 | if (pos_x < off_x + 245): | ||
514 | shift_x, shift_y = 5, 40 | ||
515 | |||
516 | |||
517 | label = "%d%%" % (max_sample_avg.avg10) | ||
518 | draw_text (ctx, label, CPU_PRESSURE_AVG10_COLOR, pos_x + shift_x, curr_y + shift_y) | ||
519 | |||
520 | curr_y = curr_y + 30 + bar_h | ||
521 | |||
522 | # render I/O pressure chart | ||
523 | if trace.io_pressure: | ||
524 | max_sample_avg = max (trace.io_pressure, key = lambda s: s.avg10) | ||
525 | max_sample_total = max (trace.io_pressure, key = lambda s: s.deltaTotal) | ||
526 | draw_legend_line(ctx, "avg10 I/O Pressure (max %d%%)" % (max_sample_avg.avg10), IO_PRESSURE_AVG10_COLOR, off_x, curr_y+20, leg_s) | ||
527 | draw_legend_box(ctx, "delta total I/O Pressure (max %d)" % (max_sample_total.deltaTotal), IO_PRESSURE_TOTAL_COLOR, off_x + 240, curr_y+20, leg_s) | ||
528 | |||
529 | # render delta total io | ||
530 | chart_rect = (off_x, curr_y+30, w, bar_h) | ||
531 | if clip_visible (clip, chart_rect): | ||
532 | draw_box_ticks (ctx, chart_rect, sec_w) | ||
533 | draw_annotations (ctx, proc_tree, trace.times, chart_rect) | ||
534 | draw_chart (ctx, IO_PRESSURE_TOTAL_COLOR, True, chart_rect, \ | ||
535 | [(sample.time, sample.deltaTotal) for sample in trace.io_pressure], \ | ||
536 | proc_tree, None) | ||
537 | |||
538 | # render avg10 io | ||
539 | if clip_visible (clip, chart_rect): | ||
540 | draw_chart (ctx, IO_PRESSURE_AVG10_COLOR, False, chart_rect, \ | ||
541 | [(sample.time, sample.avg10) for sample in trace.io_pressure], \ | ||
542 | proc_tree, None) | ||
543 | |||
544 | pos_x = off_x + ((max_sample_avg.time - proc_tree.start_time) * w / proc_tree.duration) | ||
545 | |||
546 | shift_x, shift_y = -20, 20 | ||
547 | if (pos_x < off_x + 245): | ||
548 | shift_x, shift_y = 5, 40 | ||
549 | |||
550 | |||
551 | label = "%d%%" % (max_sample_avg.avg10) | ||
552 | draw_text (ctx, label, IO_PRESSURE_AVG10_COLOR, pos_x + shift_x, curr_y + shift_y) | ||
553 | |||
554 | curr_y = curr_y + 30 + bar_h | ||
555 | |||
556 | # render MEM pressure chart | ||
557 | if trace.mem_pressure: | ||
558 | max_sample_avg = max (trace.mem_pressure, key = lambda s: s.avg10) | ||
559 | max_sample_total = max (trace.mem_pressure, key = lambda s: s.deltaTotal) | ||
560 | draw_legend_line(ctx, "avg10 MEM Pressure (max %d%%)" % (max_sample_avg.avg10), MEM_PRESSURE_AVG10_COLOR, off_x, curr_y+20, leg_s) | ||
561 | draw_legend_box(ctx, "delta total MEM Pressure (max %d)" % (max_sample_total.deltaTotal), MEM_PRESSURE_TOTAL_COLOR, off_x + 240, curr_y+20, leg_s) | ||
562 | |||
563 | # render delta total mem | ||
564 | chart_rect = (off_x, curr_y+30, w, bar_h) | ||
565 | if clip_visible (clip, chart_rect): | ||
566 | draw_box_ticks (ctx, chart_rect, sec_w) | ||
567 | draw_annotations (ctx, proc_tree, trace.times, chart_rect) | ||
568 | draw_chart (ctx, MEM_PRESSURE_TOTAL_COLOR, True, chart_rect, \ | ||
569 | [(sample.time, sample.deltaTotal) for sample in trace.mem_pressure], \ | ||
570 | proc_tree, None) | ||
571 | |||
572 | # render avg10 mem | ||
573 | if clip_visible (clip, chart_rect): | ||
574 | draw_chart (ctx, MEM_PRESSURE_AVG10_COLOR, False, chart_rect, \ | ||
575 | [(sample.time, sample.avg10) for sample in trace.mem_pressure], \ | ||
576 | proc_tree, None) | ||
577 | |||
578 | pos_x = off_x + ((max_sample_avg.time - proc_tree.start_time) * w / proc_tree.duration) | ||
579 | |||
580 | shift_x, shift_y = -20, 20 | ||
581 | if (pos_x < off_x + 245): | ||
582 | shift_x, shift_y = 5, 40 | ||
583 | |||
584 | |||
585 | label = "%d%%" % (max_sample_avg.avg10) | ||
586 | draw_text (ctx, label, MEM_PRESSURE_AVG10_COLOR, pos_x + shift_x, curr_y + shift_y) | ||
587 | |||
588 | curr_y = curr_y + 30 + bar_h | ||
589 | |||
415 | # render disk space usage | 590 | # render disk space usage |
416 | # | 591 | # |
417 | # Draws the amount of disk space used on each volume relative to the | 592 | # Draws the amount of disk space used on each volume relative to the |
@@ -493,8 +668,8 @@ def render_charts(ctx, options, clip, trace, curr_y, w, h, sec_w): | |||
493 | 668 | ||
494 | return curr_y | 669 | return curr_y |
495 | 670 | ||
496 | def render_processes_chart(ctx, options, trace, curr_y, w, h, sec_w): | 671 | def render_processes_chart(ctx, options, trace, curr_y, width, h, sec_w): |
497 | chart_rect = [off_x, curr_y+header_h, w, h - curr_y - 1 * off_y - header_h ] | 672 | chart_rect = [off_x, curr_y+header_h, width, h - curr_y - 1 * off_y - header_h ] |
498 | 673 | ||
499 | draw_legend_box (ctx, "Configure", \ | 674 | draw_legend_box (ctx, "Configure", \ |
500 | TASK_COLOR_CONFIGURE, off_x , curr_y + 45, leg_s) | 675 | TASK_COLOR_CONFIGURE, off_x , curr_y + 45, leg_s) |
@@ -519,8 +694,9 @@ def render_processes_chart(ctx, options, trace, curr_y, w, h, sec_w): | |||
519 | offset = trace.min or min(trace.start.keys()) | 694 | offset = trace.min or min(trace.start.keys()) |
520 | for start in sorted(trace.start.keys()): | 695 | for start in sorted(trace.start.keys()): |
521 | for process in sorted(trace.start[start]): | 696 | for process in sorted(trace.start[start]): |
697 | elapsed_time = trace.processes[process][1] - start | ||
522 | if not options.app_options.show_all and \ | 698 | if not options.app_options.show_all and \ |
523 | trace.processes[process][1] - start < options.app_options.mintime: | 699 | elapsed_time < options.app_options.mintime: |
524 | continue | 700 | continue |
525 | task = process.split(":")[1] | 701 | task = process.split(":")[1] |
526 | 702 | ||
@@ -529,14 +705,23 @@ def render_processes_chart(ctx, options, trace, curr_y, w, h, sec_w): | |||
529 | #print(s) | 705 | #print(s) |
530 | 706 | ||
531 | x = chart_rect[0] + (start - offset) * sec_w | 707 | x = chart_rect[0] + (start - offset) * sec_w |
532 | w = ((trace.processes[process][1] - start) * sec_w) | 708 | w = elapsed_time * sec_w |
709 | |||
710 | def set_alfa(color, alfa): | ||
711 | clist = list(color) | ||
712 | clist[-1] = alfa | ||
713 | return tuple(clist) | ||
533 | 714 | ||
534 | #print("proc at %s %s %s %s" % (x, y, w, proc_h)) | 715 | #print("proc at %s %s %s %s" % (x, y, w, proc_h)) |
535 | col = None | 716 | col = None |
536 | if task == "do_compile": | 717 | if task == "do_compile": |
537 | col = TASK_COLOR_COMPILE | 718 | col = TASK_COLOR_COMPILE |
719 | elif "do_compile" in task: | ||
720 | col = set_alfa(TASK_COLOR_COMPILE, 0.25) | ||
538 | elif task == "do_configure": | 721 | elif task == "do_configure": |
539 | col = TASK_COLOR_CONFIGURE | 722 | col = TASK_COLOR_CONFIGURE |
723 | elif "do_configure" in task: | ||
724 | col = set_alfa(TASK_COLOR_CONFIGURE, 0.25) | ||
540 | elif task == "do_install": | 725 | elif task == "do_install": |
541 | col = TASK_COLOR_INSTALL | 726 | col = TASK_COLOR_INSTALL |
542 | elif task == "do_populate_sysroot": | 727 | elif task == "do_populate_sysroot": |
@@ -554,7 +739,10 @@ def render_processes_chart(ctx, options, trace, curr_y, w, h, sec_w): | |||
554 | draw_fill_rect(ctx, col, (x, y, w, proc_h)) | 739 | draw_fill_rect(ctx, col, (x, y, w, proc_h)) |
555 | draw_rect(ctx, PROC_BORDER_COLOR, (x, y, w, proc_h)) | 740 | draw_rect(ctx, PROC_BORDER_COLOR, (x, y, w, proc_h)) |
556 | 741 | ||
557 | draw_label_in_box(ctx, PROC_TEXT_COLOR, process, x, y + proc_h - 4, w, proc_h) | 742 | # Show elapsed time for each task |
743 | process = "%ds %s" % (elapsed_time, process) | ||
744 | draw_label_in_box(ctx, PROC_TEXT_COLOR, process, x, y + proc_h - 4, w, width) | ||
745 | |||
558 | y = y + proc_h | 746 | y = y + proc_h |
559 | 747 | ||
560 | return curr_y | 748 | return curr_y |
@@ -695,7 +883,7 @@ def draw_processes_recursively(ctx, proc, proc_tree, y, proc_h, rect, clip) : | |||
695 | cmdString = proc.cmd | 883 | cmdString = proc.cmd |
696 | else: | 884 | else: |
697 | cmdString = '' | 885 | cmdString = '' |
698 | if (OPTIONS.show_pid or OPTIONS.show_all) and ipid is not 0: | 886 | if (OPTIONS.show_pid or OPTIONS.show_all) and ipid != 0: |
699 | cmdString = cmdString + " [" + str(ipid // 1000) + "]" | 887 | cmdString = cmdString + " [" + str(ipid // 1000) + "]" |
700 | if OPTIONS.show_all: | 888 | if OPTIONS.show_all: |
701 | if proc.args: | 889 | if proc.args: |
@@ -793,7 +981,7 @@ class CumlSample: | |||
793 | if self.color is None: | 981 | if self.color is None: |
794 | i = self.next() % HSV_MAX_MOD | 982 | i = self.next() % HSV_MAX_MOD |
795 | h = 0.0 | 983 | h = 0.0 |
796 | if i is not 0: | 984 | if i != 0: |
797 | h = (1.0 * i) / HSV_MAX_MOD | 985 | h = (1.0 * i) / HSV_MAX_MOD |
798 | s = 0.5 | 986 | s = 0.5 |
799 | v = 1.0 | 987 | v = 1.0 |
diff --git a/scripts/pybootchartgui/pybootchartgui/parsing.py b/scripts/pybootchartgui/pybootchartgui/parsing.py index b42dac6b88..72a54c6ba5 100644 --- a/scripts/pybootchartgui/pybootchartgui/parsing.py +++ b/scripts/pybootchartgui/pybootchartgui/parsing.py | |||
@@ -48,7 +48,11 @@ 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.net_stats = [] | ||
51 | self.monitor_disk = None | 52 | self.monitor_disk = None |
53 | self.cpu_pressure = [] | ||
54 | self.io_pressure = [] | ||
55 | self.mem_pressure = [] | ||
52 | self.times = [] # Always empty, but expected by draw.py when drawing system charts. | 56 | self.times = [] # Always empty, but expected by draw.py when drawing system charts. |
53 | 57 | ||
54 | if len(paths): | 58 | if len(paths): |
@@ -128,7 +132,7 @@ class Trace: | |||
128 | def compile(self, writer): | 132 | def compile(self, writer): |
129 | 133 | ||
130 | def find_parent_id_for(pid): | 134 | def find_parent_id_for(pid): |
131 | if pid is 0: | 135 | if pid == 0: |
132 | return 0 | 136 | return 0 |
133 | ppid = self.parent_map.get(pid) | 137 | ppid = self.parent_map.get(pid) |
134 | if ppid: | 138 | if ppid: |
@@ -454,7 +458,7 @@ def _parse_proc_disk_stat_log(file): | |||
454 | not sda1, sda2 etc. The format of relevant lines should be: | 458 | not sda1, sda2 etc. The format of relevant lines should be: |
455 | {major minor name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq} | 459 | {major minor name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq} |
456 | """ | 460 | """ |
457 | disk_regex_re = re.compile ('^([hsv]d.|mtdblock\d|mmcblk\d|cciss/c\d+d\d+.*)$') | 461 | disk_regex_re = re.compile (r'^([hsv]d.|mtdblock\d|mmcblk\d|cciss/c\d+d\d+.*)$') |
458 | 462 | ||
459 | # this gets called an awful lot. | 463 | # this gets called an awful lot. |
460 | def is_relevant_line(linetokens): | 464 | def is_relevant_line(linetokens): |
@@ -555,6 +559,44 @@ def _parse_monitor_disk_log(file): | |||
555 | return disk_stats | 559 | return disk_stats |
556 | 560 | ||
557 | 561 | ||
562 | def _parse_reduced_net_log(file): | ||
563 | net_stats = {} | ||
564 | for time, lines in _parse_timed_blocks(file): | ||
565 | |||
566 | for line in lines: | ||
567 | parts = line.split() | ||
568 | iface = parts[0][:-1] | ||
569 | if iface not in net_stats: | ||
570 | net_stats[iface] = [NetSample(time, iface, int(parts[1]), int(parts[2]), int(parts[3]), int(parts[4]))] | ||
571 | else: | ||
572 | net_stats[iface].append(NetSample(time, iface, int(parts[1]), int(parts[2]), int(parts[3]), int(parts[4]))) | ||
573 | return net_stats | ||
574 | |||
575 | |||
576 | def _parse_pressure_logs(file, filename): | ||
577 | """ | ||
578 | Parse file for "some" pressure with 'avg10', 'avg60' 'avg300' and delta total values | ||
579 | (in that order) directly stored on one line for both CPU and IO, based on filename. | ||
580 | """ | ||
581 | pressure_stats = [] | ||
582 | if filename == "cpu.log": | ||
583 | SamplingClass = CPUPressureSample | ||
584 | elif filename == "memory.log": | ||
585 | SamplingClass = MemPressureSample | ||
586 | else: | ||
587 | SamplingClass = IOPressureSample | ||
588 | for time, lines in _parse_timed_blocks(file): | ||
589 | for line in lines: | ||
590 | if not line: continue | ||
591 | tokens = line.split() | ||
592 | avg10 = float(tokens[0]) | ||
593 | avg60 = float(tokens[1]) | ||
594 | avg300 = float(tokens[2]) | ||
595 | delta = float(tokens[3]) | ||
596 | pressure_stats.append(SamplingClass(time, avg10, avg60, avg300, delta)) | ||
597 | |||
598 | return pressure_stats | ||
599 | |||
558 | # if we boot the kernel with: initcall_debug printk.time=1 we can | 600 | # if we boot the kernel with: initcall_debug printk.time=1 we can |
559 | # get all manner of interesting data from the dmesg output | 601 | # get all manner of interesting data from the dmesg output |
560 | # We turn this into a pseudo-process tree: each event is | 602 | # We turn this into a pseudo-process tree: each event is |
@@ -568,8 +610,8 @@ def _parse_monitor_disk_log(file): | |||
568 | # [ 0.039993] calling migration_init+0x0/0x6b @ 1 | 610 | # [ 0.039993] calling migration_init+0x0/0x6b @ 1 |
569 | # [ 0.039993] initcall migration_init+0x0/0x6b returned 1 after 0 usecs | 611 | # [ 0.039993] initcall migration_init+0x0/0x6b returned 1 after 0 usecs |
570 | def _parse_dmesg(writer, file): | 612 | def _parse_dmesg(writer, file): |
571 | timestamp_re = re.compile ("^\[\s*(\d+\.\d+)\s*]\s+(.*)$") | 613 | timestamp_re = re.compile (r"^\[\s*(\d+\.\d+)\s*]\s+(.*)$") |
572 | split_re = re.compile ("^(\S+)\s+([\S\+_-]+) (.*)$") | 614 | split_re = re.compile (r"^(\S+)\s+([\S\+_-]+) (.*)$") |
573 | processMap = {} | 615 | processMap = {} |
574 | idx = 0 | 616 | idx = 0 |
575 | inc = 1.0 / 1000000 | 617 | inc = 1.0 / 1000000 |
@@ -614,7 +656,7 @@ def _parse_dmesg(writer, file): | |||
614 | # print "foo: '%s' '%s' '%s'" % (type, func, rest) | 656 | # print "foo: '%s' '%s' '%s'" % (type, func, rest) |
615 | if type == "calling": | 657 | if type == "calling": |
616 | ppid = kernel.pid | 658 | ppid = kernel.pid |
617 | p = re.match ("\@ (\d+)", rest) | 659 | p = re.match (r"\@ (\d+)", rest) |
618 | if p is not None: | 660 | if p is not None: |
619 | ppid = float (p.group(1)) // 1000 | 661 | ppid = float (p.group(1)) // 1000 |
620 | # print "match: '%s' ('%g') at '%s'" % (func, ppid, time_ms) | 662 | # print "match: '%s' ('%g') at '%s'" % (func, ppid, time_ms) |
@@ -716,7 +758,7 @@ def get_num_cpus(headers): | |||
716 | cpu_model = headers.get("system.cpu") | 758 | cpu_model = headers.get("system.cpu") |
717 | if cpu_model is None: | 759 | if cpu_model is None: |
718 | return 1 | 760 | return 1 |
719 | mat = re.match(".*\\((\\d+)\\)", cpu_model) | 761 | mat = re.match(r".*\\((\\d+)\\)", cpu_model) |
720 | if mat is None: | 762 | if mat is None: |
721 | return 1 | 763 | return 1 |
722 | return max (int(mat.group(1)), 1) | 764 | return max (int(mat.group(1)), 1) |
@@ -741,6 +783,15 @@ def _do_parse(writer, state, filename, file): | |||
741 | state.cmdline = _parse_cmdline_log(writer, file) | 783 | state.cmdline = _parse_cmdline_log(writer, file) |
742 | elif name == "monitor_disk.log": | 784 | elif name == "monitor_disk.log": |
743 | state.monitor_disk = _parse_monitor_disk_log(file) | 785 | state.monitor_disk = _parse_monitor_disk_log(file) |
786 | elif name == "reduced_proc_net.log": | ||
787 | state.net_stats = _parse_reduced_net_log(file) | ||
788 | #pressure logs are in a subdirectory | ||
789 | elif name == "cpu.log": | ||
790 | state.cpu_pressure = _parse_pressure_logs(file, name) | ||
791 | elif name == "io.log": | ||
792 | state.io_pressure = _parse_pressure_logs(file, name) | ||
793 | elif name == "memory.log": | ||
794 | state.mem_pressure = _parse_pressure_logs(file, name) | ||
744 | elif not filename.endswith('.log'): | 795 | elif not filename.endswith('.log'): |
745 | _parse_bitbake_buildstats(writer, state, filename, file) | 796 | _parse_bitbake_buildstats(writer, state, filename, file) |
746 | t2 = time.process_time() | 797 | t2 = time.process_time() |
diff --git a/scripts/pybootchartgui/pybootchartgui/samples.py b/scripts/pybootchartgui/pybootchartgui/samples.py index 9fc309b3ab..7c92d2ce6a 100644 --- a/scripts/pybootchartgui/pybootchartgui/samples.py +++ b/scripts/pybootchartgui/pybootchartgui/samples.py | |||
@@ -37,6 +37,41 @@ class CPUSample: | |||
37 | return str(self.time) + "\t" + str(self.user) + "\t" + \ | 37 | return str(self.time) + "\t" + str(self.user) + "\t" + \ |
38 | str(self.sys) + "\t" + str(self.io) + "\t" + str (self.swap) | 38 | str(self.sys) + "\t" + str(self.io) + "\t" + str (self.swap) |
39 | 39 | ||
40 | |||
41 | class NetSample: | ||
42 | def __init__(self, time, iface, received_bytes, transmitted_bytes, receive_diff, transmit_diff): | ||
43 | self.time = time | ||
44 | self.iface = iface | ||
45 | self.received_bytes = received_bytes | ||
46 | self.transmitted_bytes = transmitted_bytes | ||
47 | self.receive_diff = receive_diff | ||
48 | self.transmit_diff = transmit_diff | ||
49 | |||
50 | class CPUPressureSample: | ||
51 | def __init__(self, time, avg10, avg60, avg300, deltaTotal): | ||
52 | self.time = time | ||
53 | self.avg10 = avg10 | ||
54 | self.avg60 = avg60 | ||
55 | self.avg300 = avg300 | ||
56 | self.deltaTotal = deltaTotal | ||
57 | |||
58 | class IOPressureSample: | ||
59 | def __init__(self, time, avg10, avg60, avg300, deltaTotal): | ||
60 | self.time = time | ||
61 | self.avg10 = avg10 | ||
62 | self.avg60 = avg60 | ||
63 | self.avg300 = avg300 | ||
64 | self.deltaTotal = deltaTotal | ||
65 | |||
66 | class MemPressureSample: | ||
67 | def __init__(self, time, avg10, avg60, avg300, deltaTotal): | ||
68 | self.time = time | ||
69 | self.avg10 = avg10 | ||
70 | self.avg60 = avg60 | ||
71 | self.avg300 = avg300 | ||
72 | self.deltaTotal = deltaTotal | ||
73 | |||
74 | |||
40 | class MemSample: | 75 | class MemSample: |
41 | used_values = ('MemTotal', 'MemFree', 'Buffers', 'Cached', 'SwapTotal', 'SwapFree',) | 76 | used_values = ('MemTotal', 'MemFree', 'Buffers', 'Cached', 'SwapTotal', 'SwapFree',) |
42 | 77 | ||