comparison mupdf-source/thirdparty/extract/src/memento.py @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 #!/usr/bin/env python3
2
3 '''
4 Post-processor for Memento.
5
6 Usage:
7 memento.py <args> [<command> ...]
8
9 Args:
10 -q <quiet>
11 Controls how often we output 'Memory squeezing @ ...' lines. E.g. '-q
12 10' outputs for multiples of 10.
13
14 If <command> is specified we run it and look at the output. Otherwise we assume
15 that Memento output is available on our stdin.
16 '''
17
18 import os
19 import re
20 import subprocess
21 import sys
22
23
24 def main():
25 quiet = 1
26 quiet_next = 0
27 out_raw = None
28 command = None
29 args = iter(sys.argv[1:])
30 while 1:
31 try:
32 arg = next(args)
33 except StopIteration:
34 break
35 if arg == '-h':
36 print(__doc__)
37 elif arg == '-o':
38 out_raw = open(next(args), 'w')
39 elif arg == '-q':
40 quiet = int(next(args))
41 elif arg.startswith('-'):
42 raise Exception(f'unrecognised arg: {arg}')
43 else:
44 command = arg
45 for a in args:
46 command += f' {a}'
47
48 if command:
49 print(f'Running: {command}')
50 child = subprocess.Popen(
51 command,
52 stdout=subprocess.PIPE,
53 stderr=subprocess.STDOUT,
54 shell=True,
55 text=True,
56 )
57 stdin = child.stdout
58 else:
59 stdin = sys.stdin
60
61 openbsd = os.uname()[0] == 'OpenBSD'
62 n = None
63 segv = 0
64 leaks = 0
65 lines = []
66 for line in stdin:
67 if out_raw:
68 out_raw.write(line)
69 m = re.match('^Memory squeezing @ ([0-9]+)( complete)?', line)
70 if m:
71 if not m.group(2):
72 # Start of squeeze.
73
74 if 0 and not openbsd:
75 # Looks like memento's forked processes might terminate
76 # before they get to output the 'Memory squeezing @ <N>
77 # complete' line.
78 #
79 assert n is None, f'n={n} line={line!r}'
80
81 n = int(m.group(1))
82 if n >= quiet_next:
83 sys.stdout.write(f'quiet_next={quiet_next!r} n={n!r}: {line}')
84 sys.stdout.flush()
85 quiet_next = (n + quiet) // quiet * quiet
86 else:
87 # End of squeeze.
88 assert n == int(m.group(1))
89 # Output info about any failure:
90 if segv or leaks:
91 print(f'Failure at squeeze {n}: segv={segv} leaks={leaks}:')
92 for l in lines:
93 if l.endswith('\n'):
94 l = l[:-1]
95 print(f' {l}')
96 if command:
97 print(f'Examine with: MEMENTO_FAILAT={n} {command}')
98 lines = []
99 segv = 0
100 leaks = 0
101 n = None
102 else:
103 if n is not None:
104 lines.append(line)
105 if line.startswith('SEGV at:'):
106 segv = 1
107 if line.startswith('Allocated blocks'):
108 leaks = 1
109
110
111 if __name__ == '__main__':
112 main()