diff options
Diffstat (limited to 'scripts/pybootchartgui/pybootchartgui/parsing.py')
-rw-r--r-- | scripts/pybootchartgui/pybootchartgui/parsing.py | 63 |
1 files changed, 57 insertions, 6 deletions
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() |