Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(96)

Side by Side Diff: tools/foozzie/v8_foozzie.py

Issue 2578503003: [foozzie] Initial correctness fuzzer harness. (Closed)
Patch Set: updates Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright 2016 the V8 project authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """
7 V8 correctness fuzzer launcher script.
8 """
9
10 import argparse
11 import itertools
12 import os
13 import re
14 import sys
15 import traceback
16
17 import v8_commands
18 import v8_suppressions
19
20 CONFIGS = {
21 'default': [],
22 'validate_asm': ['--validate-asm'], # Maybe add , '--disable-asm-warnings'
23 'fullcode': ['--nocrankshaft', '--turbo-filter=~'],
24 'noturbo': ['--turbo-filter=~', '--noturbo-asm'],
25 'noturbo_opt': ['--always-opt', '--turbo-filter=~', '--noturbo-asm'],
26 'ignition_staging': ['--ignition-staging'],
27 'ignition_turbo': ['--ignition-staging', '--turbo'],
28 'ignition_turbo_opt': ['--ignition-staging', '--turbo', '--always-opt'],
29 }
30
31 # Timeout in seconds for one d8 run.
32 TIMEOUT = 3
33
34 BASE_PATH = os.path.dirname(os.path.abspath(__file__))
35 PREAMBLE = [
36 os.path.join(BASE_PATH, 'v8_mock.js'),
37 os.path.join(BASE_PATH, 'v8_suppressions.js'),
38 ]
39
40 FLAGS = ['--abort_on_stack_overflow', '--expose-gc', '--allow-natives-syntax',
41 '--invoke-weak-callbacks', '--omit-quit', '--es-staging']
42
43 SUPPORTED_ARCHS = ['ia32', 'x64', 'arm', 'arm64']
44
45 # Output for suppressed failure case.
46 FAILURE_HEADER_TEMPLATE = """#
tandrii(chromium) 2016/12/16 16:46:26 Nit: instead of """# i'd do: """ # .... """.strip
Michael Achenbach 2016/12/19 08:42:45 Done.
47 # V8 correctness failure
48 # V8 correctness configs: %(configs)s
49 # V8 correctness sources: %(sources)s
50 # V8 correctness suppression: %(suppression)s"""
51
52 # Extended output for failure case. The 'CHECK' is for the minimizer.
53 FAILURE_TEMPLATE = FAILURE_HEADER_TEMPLATE + """#
54 # CHECK
55 #
56 # Compared %(first_config_label)s with %(second_config_label)s
57 #
58 # Flags of %(first_config_label)s:
59 %(first_config_flags)s
60 # Flags of %(second_config_label)s:
61 %(second_config_flags)s
62 #
63 # Difference:
64 %(difference)s
65 #
66 ### Start of configuration %(first_config_label)s:
67 %(first_config_output)s
68 ### End of configuration %(first_config_label)s
69 #
70 ### Start of configuration %(second_config_label)s:
71 %(second_config_output)s
72 ### End of configuration %(second_config_label)s
73 """
74
75
76 def parse_args():
77 parser = argparse.ArgumentParser()
78 parser.add_argument(
79 '--random-seed', type=int, required=True,
80 help='random seed passed to both runs')
81 parser.add_argument(
82 '--first-arch', help='first architecture', default='x64')
83 parser.add_argument(
84 '--second-arch', help='second architecture', default='x64')
85 parser.add_argument(
86 '--first-config', help='first configuration', default='fullcode')
87 parser.add_argument(
88 '--second-config', help='second configuration', default='fullcode')
89 parser.add_argument(
90 '--first-d8', default='d8',
91 help='optional path to first d8 executable, default: side-by-side')
tandrii(chromium) 2016/12/16 16:46:26 what does "side-by-side" mean?
Michael Achenbach 2016/12/19 08:42:45 Clarified.
92 parser.add_argument(
93 '--second-d8',
94 help='optional path to second d8 executable, default: same as first')
95 parser.add_argument('testcase', help='path to test case')
96 options = parser.parse_args()
97
98 # Ensure we make a sane comparison.
99 assert (options.first_arch != options.second_arch or
100 options.first_config != options.second_config) , (
101 'Need either arch or config difference.')
102 assert options.first_arch in SUPPORTED_ARCHS
103 assert options.second_arch in SUPPORTED_ARCHS
104 assert options.first_config in CONFIGS
105 assert options.second_config in CONFIGS
106
107 # Ensure we have a test case.
108 assert (os.path.exists(options.testcase) and
tandrii(chromium) 2016/12/16 16:46:26 if x: parser.error() is nicer, but assert is cer
Michael Achenbach 2016/12/19 08:42:45 The script is designed to be called from automated
109 os.path.isfile(options.testcase)), (
110 'Test case %s doesn\'t exist' % options.testcase)
111
112 # Use first d8 as default for second d8.
113 options.second_d8 = options.second_d8 or options.first_d8
114
115 # Ensure absolute paths.
116 options.first_d8 = os.path.abspath(options.first_d8)
117 options.second_d8 = os.path.abspath(options.second_d8)
118
119 # Ensure executables exist.
120 assert os.path.exists(options.first_d8)
121 assert os.path.exists(options.second_d8)
122
123 # Ensure we use different executables when we claim we compare
124 # different architectures.
125 # TODO(machenbach): Infer arch from gn's build output.
126 if options.first_arch != options.second_arch:
127 assert options.first_d8 != options.second_d8
128
129 return options
130
131
132 def test_pattern_bailout(testcase, ignore_fun):
133 """Print failure state and return if ignore_fun matches testcase."""
134 with open(testcase) as f:
135 bug = (ignore_fun(f.read()) or '').strip()
136 if bug:
137 print FAILURE_HEADER_TEMPLATE % {
138 'configs': '',
139 'sources': '',
140 'suppression': bug,
141 }
142 return True
143 return False
144
145
146 def pass_bailout(output, step_number):
147 """Print info and return if in timeout or crash pass states."""
148 if output.HasTimedOut():
149 # Dashed output, so that no other clusterfuzz tools can match the
150 # words timeout or crash.
151 print '# V8 correctness - T-I-M-E-O-U-T %d' % step_number
152 return True
153 if output.HasCrashed():
154 print '# V8 correctness - C-R-A-S-H %d' % step_number
155 return True
156 return False
157
158
159 def fail_bailout(output, ignore_by_output_fun):
160 """Print failure state and return if ignore_by_output_fun matches output."""
161 bug = (ignore_by_output_fun(output.stdout) or '').strip()
162 if bug:
163 print FAILURE_HEADER_TEMPLATE % {
164 'configs': '',
165 'sources': '',
166 'suppression': bug,
167 }
168 return True
169 return False
170
171
172 def main():
173 options = parse_args()
174
175 # Suppressions are architecture and configuration specific.
176 suppress = v8_suppressions.get_suppression(
177 options.first_arch, options.first_config,
178 options.second_arch, options.second_config,
179 )
180
181 if test_pattern_bailout(options.testcase, suppress.ignore):
182 return 2
tandrii(chromium) 2016/12/16 16:46:26 i'd make 2 a meaningful constant, perhaps 0 too.
Michael Achenbach 2016/12/19 08:42:45 Done.
183
184 common_flags = FLAGS + ['--random-seed', str(options.random_seed)]
185 first_config_flags = common_flags + CONFIGS[options.first_config]
186 second_config_flags = common_flags + CONFIGS[options.second_config]
187
188 def run_d8(d8, config_flags):
189 return v8_commands.Execute(
190 [d8] + config_flags + PREAMBLE + [options.testcase],
191 cwd=os.path.dirname(options.testcase),
192 timeout=TIMEOUT,
193 )
194
195 first_config_output = run_d8(options.first_d8, first_config_flags)
196
197 # Early bailout based on first run's output.
198 if pass_bailout(first_config_output, 1):
199 return 0
200 if fail_bailout(first_config_output, suppress.ignore_by_output1):
201 return 2
202
203 second_config_output = run_d8(options.second_d8, second_config_flags)
204
205 # Bailout based on second run's output.
206 if pass_bailout(second_config_output, 2):
207 return 0
208 if fail_bailout(second_config_output, suppress.ignore_by_output2):
209 return 2
210
211 difference = suppress.diff(
212 first_config_output.stdout, second_config_output.stdout)
213 if difference:
214 # The first three entries will be parsed by clusterfuzz. Format changes
215 # will require changes on the clusterfuzz side.
216 first_config_label = '%s,%s' % (options.first_arch, options.first_config)
217 second_config_label = '%s,%s' % (options.second_arch, options.second_config)
218 print FAILURE_TEMPLATE % {
219 'configs': '%s:%s' % (first_config_label, second_config_label),
220 'sources': '', # TODO
221 'suppression': '', # We can't tie bugs to differences.
222 'first_config_label': first_config_label,
223 'second_config_label': second_config_label,
224 'first_config_flags': ' '.join(first_config_flags),
225 'second_config_flags': ' '.join(second_config_flags),
226 'first_config_output': first_config_output.stdout,
227 'second_config_output': second_config_output.stdout,
228 'difference': difference,
229 }
230 return 2
231
232 # TODO(machenbach): Figure out if we could also return a bug in case there's
233 # no difference, but one of the line suppressions has matched - and without
234 # the match there would be a difference.
235
236 print '# V8 correctness - pass'
237 return 0
238
239
240 if __name__ == "__main__":
241 try:
242 result = main()
243 except SystemExit:
244 # Make sure clusterfuzz reports internal errors and wrong usage.
245 # Use one label for all internal and usage errors.
246 print FAILURE_HEADER_TEMPLATE % {
247 'configs': '',
tandrii(chromium) 2016/12/19 08:43:32 nitty IMO: % dict(configs='', sources='', suppress
Michael Achenbach 2016/12/19 09:42:19 Done. Also for the other dicts here.
248 'sources': '',
249 'suppression': 'wrong_usage',
250 }
251 result = 2
252 except Exception as e:
253 print FAILURE_HEADER_TEMPLATE % {
254 'configs': '',
255 'sources': '',
256 'suppression': 'internal_error',
257 }
258 print '# Internal error: %s' % e
259 traceback.print_exc(file=sys.stdout)
260 result = 2
261
262 sys.exit(result)
263
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698