]> git.cworth.org Git - apitrace/blob - scripts/tracediff.py
Avoid weird named fifo race condition in tracediff.
[apitrace] / scripts / tracediff.py
1 #!/usr/bin/env python
2 ##########################################################################
3 #
4 # Copyright 2011 Jose Fonseca
5 # All Rights Reserved.
6 #
7 # Permission is hereby granted, free of charge, to any person obtaining a copy
8 # of this software and associated documentation files (the "Software"), to deal
9 # in the Software without restriction, including without limitation the rights
10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 # copies of the Software, and to permit persons to whom the Software is
12 # furnished to do so, subject to the following conditions:
13 #
14 # The above copyright notice and this permission notice shall be included in
15 # all copies or substantial portions of the Software.
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 # THE SOFTWARE.
24 #
25 ##########################################################################/
26
27
28 import platform
29 import optparse
30 import os
31 import shutil
32 import subprocess
33 import sys
34 import tempfile
35 import time
36
37
38 def stripdump(trace, fifo):
39     dump = subprocess.Popen(
40         args = [
41             options.apitrace,
42             'dump',
43             '--color=never',
44             '--arg-names=no',
45             '--calls=' + options.calls,
46             trace
47         ],
48         stdout = subprocess.PIPE,
49         universal_newlines = True,
50     )
51
52     sed = subprocess.Popen(
53         args = [
54             'sed',
55             '-e', r's/\r$//g',
56             '-e', r's/^[0-9]\+ //',
57             '-e', r's/hdc = \w\+/hdc/g',
58         ],
59         stdin = dump.stdout,
60         stdout = open(fifo, 'wt'),
61         universal_newlines = True,
62     )
63
64     # XXX: Avoid a weird race condition
65     time.sleep(0.01)
66
67
68 def diff(traces):
69     fifodir = tempfile.mkdtemp()
70     try:
71         fifos = []
72         for i in range(len(traces)):
73             trace = traces[i]
74             fifo = os.path.join(fifodir, str(i))
75             stripdump(trace, fifo)
76             fifos.append(fifo)
77
78         # TODO use difflib instead
79         sdiff = subprocess.Popen(
80             args = [
81                 'sdiff',
82                 '--width=%u' % options.width,
83                 '--speed-large-files',
84             ] + fifos,
85             stdout = subprocess.PIPE,
86             universal_newlines = True,
87         )
88
89         less = subprocess.Popen(
90             args = ['less', '-FRXn'],
91             stdin = sdiff.stdout
92         )
93
94         less.wait()
95
96     finally:
97         shutil.rmtree(fifodir)
98
99
100 def columns():
101     import curses
102     curses.setupterm()
103     return curses.tigetnum('cols')
104
105
106 def main():
107     '''Main program.
108     '''
109
110     default_width = columns()
111
112     # Parse command line options
113     optparser = optparse.OptionParser(
114         usage='\n\t%prog [options] -- TRACE_FILE TRACE_FILE',
115         version='%%prog')
116     optparser.add_option(
117         '-a', '--apitrace', metavar='PROGRAM',
118         type='string', dest='apitrace', default='apitrace',
119         help='apitrace command [default: %default]')
120     optparser.add_option(
121         '-c', '--calls', metavar='CALLSET',
122         type="string", dest="calls", default='1-10000',
123         help="calls to compare [default: %default]")
124     optparser.add_option(
125         '-w', '--width', metavar='NUM',
126         type="string", dest="width", default=default_width,
127         help="columns [default: %default]")
128
129     global options
130     (options, args) = optparser.parse_args(sys.argv[1:])
131     if len(args) != 2:
132         optparser.error("incorrect number of arguments")
133
134     diff(args)
135
136
137 if __name__ == '__main__':
138     main()