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

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

Issue 2578503003: [foozzie] Initial correctness fuzzer harness. (Closed)
Patch Set: Presubmit 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
« no previous file with comments | « tools/foozzie/v8_commands.py ('k') | tools/foozzie/v8_foozzie_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 = dict(
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 # Return codes.
35 RETURN_PASS = 0
36 RETURN_FAILURE = 2
37
38 BASE_PATH = os.path.dirname(os.path.abspath(__file__))
39 PREAMBLE = [
40 os.path.join(BASE_PATH, 'v8_mock.js'),
41 os.path.join(BASE_PATH, 'v8_suppressions.js'),
42 ]
43
44 FLAGS = ['--abort_on_stack_overflow', '--expose-gc', '--allow-natives-syntax',
45 '--invoke-weak-callbacks', '--omit-quit', '--es-staging']
46
47 SUPPORTED_ARCHS = ['ia32', 'x64', 'arm', 'arm64']
48
49 # Output for suppressed failure case.
50 FAILURE_HEADER_TEMPLATE = """
51 #
52 # V8 correctness failure
53 # V8 correctness configs: %(configs)s
54 # V8 correctness sources: %(sources)s
55 # V8 correctness suppression: %(suppression)s""".strip()
56
57 # Extended output for failure case. The 'CHECK' is for the minimizer.
58 FAILURE_TEMPLATE = FAILURE_HEADER_TEMPLATE + """
59 #
60 # CHECK
61 #
62 # Compared %(first_config_label)s with %(second_config_label)s
63 #
64 # Flags of %(first_config_label)s:
65 %(first_config_flags)s
66 # Flags of %(second_config_label)s:
67 %(second_config_flags)s
68 #
69 # Difference:
70 %(difference)s
71 #
72 ### Start of configuration %(first_config_label)s:
73 %(first_config_output)s
74 ### End of configuration %(first_config_label)s
75 #
76 ### Start of configuration %(second_config_label)s:
77 %(second_config_output)s
78 ### End of configuration %(second_config_label)s
79 """.strip()
80
81
82 def parse_args():
83 parser = argparse.ArgumentParser()
84 parser.add_argument(
85 '--random-seed', type=int, required=True,
86 help='random seed passed to both runs')
87 parser.add_argument(
88 '--first-arch', help='first architecture', default='x64')
89 parser.add_argument(
90 '--second-arch', help='second architecture', default='x64')
91 parser.add_argument(
92 '--first-config', help='first configuration', default='fullcode')
93 parser.add_argument(
94 '--second-config', help='second configuration', default='fullcode')
95 parser.add_argument(
96 '--first-d8', default='d8',
97 help='optional path to first d8 executable, '
98 'default: bundled in the same directory as this script')
99 parser.add_argument(
100 '--second-d8',
101 help='optional path to second d8 executable, default: same as first')
102 parser.add_argument('testcase', help='path to test case')
103 options = parser.parse_args()
104
105 # Ensure we make a sane comparison.
106 assert (options.first_arch != options.second_arch or
107 options.first_config != options.second_config) , (
108 'Need either arch or config difference.')
109 assert options.first_arch in SUPPORTED_ARCHS
110 assert options.second_arch in SUPPORTED_ARCHS
111 assert options.first_config in CONFIGS
112 assert options.second_config in CONFIGS
113
114 # Ensure we have a test case.
115 assert (os.path.exists(options.testcase) and
116 os.path.isfile(options.testcase)), (
117 'Test case %s doesn\'t exist' % options.testcase)
118
119 # Use first d8 as default for second d8.
120 options.second_d8 = options.second_d8 or options.first_d8
121
122 # Ensure absolute paths.
123 options.first_d8 = os.path.abspath(options.first_d8)
124 options.second_d8 = os.path.abspath(options.second_d8)
125
126 # Ensure executables exist.
127 assert os.path.exists(options.first_d8)
128 assert os.path.exists(options.second_d8)
129
130 # Ensure we use different executables when we claim we compare
131 # different architectures.
132 # TODO(machenbach): Infer arch from gn's build output.
133 if options.first_arch != options.second_arch:
134 assert options.first_d8 != options.second_d8
135
136 return options
137
138
139 def test_pattern_bailout(testcase, ignore_fun):
140 """Print failure state and return if ignore_fun matches testcase."""
141 with open(testcase) as f:
142 bug = (ignore_fun(f.read()) or '').strip()
143 if bug:
144 print FAILURE_HEADER_TEMPLATE % dict(
145 configs='', sources='', suppression=bug)
146 return True
147 return False
148
149
150 def pass_bailout(output, step_number):
151 """Print info and return if in timeout or crash pass states."""
152 if output.HasTimedOut():
153 # Dashed output, so that no other clusterfuzz tools can match the
154 # words timeout or crash.
155 print '# V8 correctness - T-I-M-E-O-U-T %d' % step_number
156 return True
157 if output.HasCrashed():
158 print '# V8 correctness - C-R-A-S-H %d' % step_number
159 return True
160 return False
161
162
163 def fail_bailout(output, ignore_by_output_fun):
164 """Print failure state and return if ignore_by_output_fun matches output."""
165 bug = (ignore_by_output_fun(output.stdout) or '').strip()
166 if bug:
167 print FAILURE_HEADER_TEMPLATE % dict(
168 configs='', sources='', suppression=bug)
169 return True
170 return False
171
172
173 def main():
174 options = parse_args()
175
176 # Suppressions are architecture and configuration specific.
177 suppress = v8_suppressions.get_suppression(
178 options.first_arch, options.first_config,
179 options.second_arch, options.second_config,
180 )
181
182 if test_pattern_bailout(options.testcase, suppress.ignore):
183 return RETURN_FAILURE
184
185 common_flags = FLAGS + ['--random-seed', str(options.random_seed)]
186 first_config_flags = common_flags + CONFIGS[options.first_config]
187 second_config_flags = common_flags + CONFIGS[options.second_config]
188
189 def run_d8(d8, config_flags):
190 return v8_commands.Execute(
191 [d8] + config_flags + PREAMBLE + [options.testcase],
192 cwd=os.path.dirname(options.testcase),
193 timeout=TIMEOUT,
194 )
195
196 first_config_output = run_d8(options.first_d8, first_config_flags)
197
198 # Early bailout based on first run's output.
199 if pass_bailout(first_config_output, 1):
200 return RETURN_PASS
201 if fail_bailout(first_config_output, suppress.ignore_by_output1):
202 return RETURN_FAILURE
203
204 second_config_output = run_d8(options.second_d8, second_config_flags)
205
206 # Bailout based on second run's output.
207 if pass_bailout(second_config_output, 2):
208 return RETURN_PASS
209 if fail_bailout(second_config_output, suppress.ignore_by_output2):
210 return RETURN_FAILURE
211
212 difference = suppress.diff(
213 first_config_output.stdout, second_config_output.stdout)
214 if difference:
215 # The first three entries will be parsed by clusterfuzz. Format changes
216 # will require changes on the clusterfuzz side.
217 first_config_label = '%s,%s' % (options.first_arch, options.first_config)
218 second_config_label = '%s,%s' % (options.second_arch, options.second_config)
219 print FAILURE_TEMPLATE % dict(
220 configs='%s:%s' % (first_config_label, second_config_label),
221 sources='', # TODO
222 suppression='', # We can't tie bugs to differences.
223 first_config_label=first_config_label,
224 second_config_label=second_config_label,
225 first_config_flags=' '.join(first_config_flags),
226 second_config_flags=' '.join(second_config_flags),
227 first_config_output=first_config_output.stdout,
228 second_config_output=second_config_output.stdout,
229 difference=difference,
230 )
231 return RETURN_FAILURE
232
233 # TODO(machenbach): Figure out if we could also return a bug in case there's
234 # no difference, but one of the line suppressions has matched - and without
235 # the match there would be a difference.
236
237 print '# V8 correctness - pass'
238 return RETURN_PASS
239
240
241 if __name__ == "__main__":
242 try:
243 result = main()
244 except SystemExit:
245 # Make sure clusterfuzz reports internal errors and wrong usage.
246 # Use one label for all internal and usage errors.
247 print FAILURE_HEADER_TEMPLATE % dict(
248 configs='', sources='', suppression='wrong_usage')
249 result = RETURN_FAILURE
250 except Exception as e:
251 print FAILURE_HEADER_TEMPLATE % dict(
252 configs='', sources='', suppression='internal_error')
253 print '# Internal error: %s' % e
254 traceback.print_exc(file=sys.stdout)
255 result = RETURN_FAILURE
256
257 sys.exit(result)
OLDNEW
« no previous file with comments | « tools/foozzie/v8_commands.py ('k') | tools/foozzie/v8_foozzie_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698