1#!/usr/bin/python 2# SPDX-License-Identifier: LGPL-2.1-or-later 3 4""" 5A helper to compare 'systemd-analyze dump' outputs. 6 7systemd-analyze dump >/var/tmp/dump1 8(reboot) 9tools/analyze-dump-sort.py /var/tmp/dump1 → this does a diff from dump1 to current 10 11systemd-analyze dump >/var/tmp/dump2 12tools/analyze-dump-sort.py /var/tmp/{dump1,dump2} → this does a diff from dump1 to dump2 13""" 14 15import argparse 16import tempfile 17import subprocess 18 19def sort_dump(sourcefile, destfile=None): 20 if destfile is None: 21 destfile = tempfile.NamedTemporaryFile('wt') 22 23 units = {} 24 unit = [] 25 26 same = [] 27 28 for line in sourcefile: 29 line = line.rstrip() 30 31 header = line.split(':')[0] 32 if 'Timestamp' in header or 'Invocation ID' in header or 'PID' in header: 33 line = header + ': …' 34 35 if line.startswith('->'): 36 if unit: 37 units[unit[0]] = unit 38 unit = [line] 39 elif line.startswith('\t'): 40 assert unit 41 42 if same and same[0].startswith(header): 43 same.append(line) 44 else: 45 unit.extend(sorted(same, key=str.lower)) 46 same = [line] 47 else: 48 print(line, file=destfile) 49 50 if unit: 51 units[unit[0]] = unit 52 53 for unit in sorted(units.values()): 54 print('\n'.join(unit), file=destfile) 55 56 destfile.flush() 57 return destfile 58 59def parse_args(): 60 p = argparse.ArgumentParser(description=__doc__) 61 p.add_argument('one') 62 p.add_argument('two', nargs='?') 63 p.add_argument('--user', action='store_true') 64 return p.parse_args() 65 66if __name__ == '__main__': 67 opts = parse_args() 68 69 one = sort_dump(open(opts.one)) 70 if opts.two: 71 two = sort_dump(open(opts.two)) 72 else: 73 user = ['--user'] if opts.user else [] 74 two = subprocess.run(['systemd-analyze', 'dump', *user], 75 capture_output=True, text=True, check=True) 76 two = sort_dump(two.stdout.splitlines()) 77 with subprocess.Popen(['diff', '-U10', one.name, two.name], stdout=subprocess.PIPE) as diff: 78 subprocess.Popen(['less'], stdin=diff.stdout) 79