2 ##########################################################################
4 # Copyright 2011 Jose Fonseca
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:
14 # The above copyright notice and this permission notice shall be included in
15 # all copies or substantial portions of the Software.
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
25 ##########################################################################/
33 from trace import Parser
41 ignored_function_names = set([
44 'glXGetCurrentDisplay',
46 'glXGetProcAddressARB',
55 call = parser.parse_call()
56 while call and len(calls) < 1000:
58 if call.sig.name not in ignored_function_names:
60 call = parser.parse_call()
66 def __init__(self, a, b):
71 matcher = difflib.SequenceMatcher(None, self.a, self.b)
72 for tag, alo, ahi, blo, bhi in matcher.get_opcodes():
74 self.replace(alo, ahi, blo, bhi)
82 raise ValueError, 'unknown tag %s' % (tag,)
84 def replace(self, alo, ahi, blo, bhi):
85 assert alo < ahi and blo < bhi
87 a_names = [call.name for call in self.a[alo:ahi]]
88 b_names = [call.name for call in self.b[blo:bhi]]
90 matcher = difflib.SequenceMatcher(None, a_names, b_names)
91 for tag, _alo, _ahi, _blo, _bhi in matcher.get_opcodes():
97 self.replace_dissimilar(_alo, _ahi, _blo, _bhi)
99 self.delete(_alo, _ahi)
100 elif tag == 'insert':
101 self.insert(_blo, _bhi)
103 self.replace_similar(_alo, _ahi, _blo, _bhi)
105 raise ValueError, 'unknown tag %s' % (tag,)
107 def replace_similar(self, alo, ahi, blo, bhi):
108 assert alo < ahi and blo < bhi
109 assert ahi - alo == bhi - blo
110 for i in xrange(0, bhi - blo):
111 a_call = self.a[alo + i]
112 b_call = self.b[blo + i]
113 assert a_call.name == b_call.name
114 assert len(a_call.args) == len(b_call.args)
115 sys.stdout.write(b_call.name + '(')
117 for j in xrange(len(b_call.args)):
118 sys.stdout.write(sep)
119 self.replace_value(a_call.args[j], b_call.args[j])
121 sys.stdout.write(')')
122 if a_call.ret is not None or b_call.ret is not None:
123 sys.stdout.write(' = ')
124 self.replace_value(a_call.ret, b_call.ret)
125 sys.stdout.write('\n')
127 def replace_dissimilar(self, alo, ahi, blo, bhi):
128 assert alo < ahi and blo < bhi
129 if bhi - blo < ahi - alo:
130 first = self.insert(blo, bhi)
131 second = self.delete(alo, ahi)
133 first = self.delete(alo, ahi)
134 second = self.insert(blo, bhi)
136 for g in first, second:
140 def replace_value(self, a, b):
142 sys.stdout.write(str(b))
144 sys.stdout.write('%s -> %s' % (a, b))
148 def delete(self, alo, ahi):
149 self.dump('- ' + self.escape + '9m', self.a, alo, ahi, self.escape + '0m')
151 def insert(self, blo, bhi):
152 self.dump('+ ', self.b, blo, bhi)
154 def equal(self, alo, ahi):
155 self.dump(' ' + self.escape + '2m', self.a, alo, ahi, self.escape + '0m')
157 def dump(self, prefix, x, lo, hi, suffix=""):
158 for i in xrange(lo, hi):
159 sys.stdout.write(prefix + str(x[i]) + suffix + '\n')
165 optparser = optparse.OptionParser(
166 usage='\n\t%prog <trace> <trace>',
168 optparser.add_option(
169 '-d', '--tracedump', metavar='PROGRAM',
170 type='string', dest='tracedump', default='tracedump',
171 help='tracedump command [default: %default]')
173 (options, args) = optparser.parse_args(sys.argv[1:])
175 optparser.error("incorrect number of arguments")
177 ref_calls = readtrace(args[0])
178 src_calls = readtrace(args[1])
180 differ = SDiffer(ref_calls, src_calls)
184 if __name__ == '__main__':