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

Side by Side Diff: tools/findit/crash_utils.py

Issue 430943003: [Findit] Plain objects to represent and parse stack trace. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: addressed codereview. Created 6 years, 4 months 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 # Copyright (c) 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 import cgi
6 import json
7 import os
8 import time
9 import urllib
10
stgao 2014/08/07 21:03:37 One more empty line above.
jeun 2014/08/07 22:03:20 Done.
11 INFINITY = float('inf')
12
13
14 def NormalizePathLinux(path):
15 """Normalizes linux path.
16
17 Args:
18 path: A string representing a path.
19
20 Returns:
21 A tuple containing a component this path is in (e.g blink, skia, etc)
22 and a path in that component's repository.
23 """
24 normalized_path = os.path.abspath(path)
25
26 if 'src/v8/' in normalized_path:
27 component = 'v8'
28 normalized_path = normalized_path.split('src/v8/')[1]
29
30 # TODO(jeun): Integrate with parsing DEPS file.
31 if 'WebKit/' in normalized_path:
32 component = 'blink'
33 normalized_path = ''.join(path.split('WebKit/')[1:])
34 else:
35 component = 'chromium'
36
37 if '/build/' in normalized_path:
38 normalized_path = normalized_path.split('/build/')[-1]
39
40 if not (normalized_path.startswith('src/') or
41 normalized_path.startswith('Source/')):
42 normalized_path = 'src/' + normalized_path
43
44 return (component, normalized_path)
45
46
47 def SplitRange(regression):
48 """Splits a range as retrieved from clusterfuzz.
49
50 Args:
51 regression: A string in format 'r1234:r5678'.
52
53 Returns:
54 A list containing two numbers represented in string, for example
55 ['1234','5678'].
56 """
57 revisions = regression.split(':')
58
59 # If regression information is not available, return none.
60 if len(revisions) != 2:
61 return None
62
63 # Strip 'r' from both start and end range.
64 start_range = revisions[0].lstrip('r')
65 end_range = revisions[1].lstrip('r')
66
67 return [start_range, end_range]
68
69
70 def LoadJSON(json_string):
71 """Loads json object from string, or None.
72
73 Args:
74 json_string: A string to get object from.
75
76 Returns:
77 JSON object if the string represents a JSON object, None otherwise.
78 """
79 try:
80 data = json.loads(json_string)
81 except ValueError:
82 data = None
83
84 return data
85
86
87 def GetDataFromURL(url, retries=10, sleep_time=0.1):
88 """Retrieves raw data from URL, tries 10 times.
89
90 Args:
91 url: URL to get data from.
92 retries: Number of times to retry connection.
93 sleep_time: Time in seconds to wait before retrying connection.
94
95 Returns:
96 None if the data retrieval fails, or the raw data.
97 """
98 data = None
99 for i in range(retries):
100 # Retrieves data from URL.
101 try:
102 data = urllib.urlopen(url)
103
104 # If retrieval is successful, return the data.
105 if data:
106 return data.read()
107
108 # If retrieval fails, try after sleep_time second.
109 except IOError:
110 time.sleep(sleep_time)
111 continue
112
113 # Return None if it fails to read data from URL 'retries' times.
114 return None
115
116
117 def FindMinLineDistance(crashed_line_list, changed_line_numbers):
118 """Calculates how far the changed line is from one of the crashes.
119
120 Finds the minimum distance between the lines that the file crashed on
121 and the lines that the file changed. For example, if the file crashed on
122 line 200 and the CL changes line 203,204 and 205, the function returns 3.
123
124 Args:
125 crashed_line_list: A list of lines that the file crashed on.
126 changed_line_numbers: A list of lines that the file changed.
127
128 Returns:
129 The minimum distance. If either of the input lists is empty,
130 it returns inf.
131
132 """
133 min_distance = INFINITY
134
135 for line in crashed_line_list:
136 for distance in changed_line_numbers:
137 # Find the current distance and update the min if current distance is
138 # less than current min.
139 current_distance = abs(line - distance)
140 if current_distance < min_distance:
141 min_distance = current_distance
142
143 return min_distance
144
145
146 def GuessIfSameSubPath(path1, path2):
147 """Guesses if two paths represent same path.
148
149 Compares the name of the folders in the path (by split('/')), and checks
150 if they match either more than 3 or min of path lengths.
151
152 Args:
153 path1: First path.
154 path2: Second path to compare.
155
156 Returns:
157 True if it they are thought to be a same path, False otherwise.
158 """
159 path1 = path1.split('/')
160 path2 = path2.split('/')
161
162 intersection = set(path1).intersection(set(path2))
163 return len(intersection) >= (min(3, min(len(path1), len(path2))))
164
165
166 def FindMinStackFrameNumber(stack_frame_indices, priorities):
167 """Finds the minimum stack number, from the list of stack numbers.
168
169 Args:
170 stack_frame_indices: A list of lists containing stack position.
171 priorities: A list of of priority for each file.
172
173 Returns:
174 Inf if stack_frame_indices is empty, minimum stack number otherwise.
175 """
176 # Get the indexes of the highest priority (or low priority number).
177 highest_priority = min(priorities)
178 highest_priority_indices = []
179 for i in range(len(priorities)):
180 if priorities[i] == highest_priority:
181 highest_priority_indices.append(i)
182
183 # Gather the list of stack frame numbers for the files that change the
184 # crash lines.
185 flattened = []
186 for i in highest_priority_indices:
187 flattened += stack_frame_indices[i]
188
189 # If no stack frame information is available, return inf. Else, return min.
190 if not flattened:
191 return INFINITY
192 else:
193 return min(flattened)
194
195
196 def AddHyperlink(text, link):
197 """Returns a string with HTML link tag.
198
199 Args:
200 text: A string to add link.
201 link: A link to add to the string.
202
203 Returns:
204 A string with hyperlink added.
205 """
206 sanitized_link = cgi.escape(link, quote=True)
207 sanitized_text = cgi.escape(text)
208 return '<a href="%s">%s</a>' % (sanitized_link, sanitized_text)
209
210
211 def PrettifyList(l):
212 """Returns a string representation of a list.
213
214 It adds comma in between the elements and removes the brackets.
215 Args:
216 l: A list to prettify.
217 Returns:
218 A string representation of the list.
219 """
220 return str(l)[1:-1]
221
222
223 def PrettifyFiles(file_list):
224 """Returns a string representation of a list of file names.
225
226 Args:
227 file_list: A list of tuple, (file_name, file_url).
228 Returns:
229 A string representation of file names with their urls.
230 """
231 ret = ['\n']
232 for file_name, file_url in file_list:
233 ret.append(' %s\n' % AddHyperlink(file_name, file_url))
234 return ''.join(ret)
235
236
237 def Intersection(crashed_line_list, stack_frame_index, changed_line_numbers,
238 line_range=3):
239 """Finds the overlap betwee changed lines and crashed lines.
240
241 Finds the intersection of the lines that caused the crash and
242 lines that the file changes. The intersection looks within 3 lines
243 of the line that caused the crash.
244
245 Args:
246 crashed_line_list: A list of lines that the file crashed on.
247 stack_frame_index: A list of positions in stack for each of the lines.
248 changed_line_numbers: A list of lines that the file changed.
249 line_range: Number of lines to look backwards from crashed lines.
250
251 Returns:
252 line_intersection: Intersection between crashed_line_list and
253 changed_line_numbers.
254 stack_frame_index_intersection: Stack number for each of the intersections.
255 """
256 line_intersection = []
257 stack_frame_index_intersection = []
258
259 # Iterate through the crashed lines, and its occurence in stack.
260 for (line, stack_frame_index) in zip(crashed_line_list, stack_frame_index):
261
stgao 2014/08/07 21:03:37 It seems the code has empty lines after for. Would
jeun 2014/08/07 22:03:20 Done.
262 # Also check previous 3 lines.
stgao 2014/08/07 21:03:37 Comment needs updating, as 3 is invalid now.
jeun 2014/08/07 22:03:20 Done.
263 line_minus_n = range(line - line_range, line + 1)
264
265 for changed_line in changed_line_numbers:
266
267 # If a CL does not change crahsed line, check next line.
268 if changed_line not in line_minus_n:
269 continue
270
271 # If the changed line is exactly the crashed line, add that line.
272 if line in changed_line_numbers:
273 intersected_line = line
274
275 # If the changed line is in 3 lines of the crashed line, add the line.
276 else:
277 intersected_line = changed_line
278
279 # Avoid adding the same line twice.
280 if intersected_line not in line_intersection:
281 line_intersection.append(intersected_line)
282 stack_frame_index_intersection.append(stack_frame_index)
283
284 break
285
286 return (line_intersection, stack_frame_index_intersection)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698