Index: tools/findit/findit_for_crash.py |
diff --git a/tools/findit/findit_for_crash.py b/tools/findit/findit_for_crash.py |
index 2fab473cb481838b774c381bd8593cffbfa62fa9..c12d6b8a60b958d8762514cc0abf9efda43cf877 100644 |
--- a/tools/findit/findit_for_crash.py |
+++ b/tools/findit/findit_for_crash.py |
@@ -1,4 +1,4 @@ |
-# Copyright 2014 The Chromium Authors. All rights reserved. |
+# Copyright (c) 2014 The Chromium Authors. All rights reserved. |
# Use of this source code is governed by a BSD-style license that can be |
# found in the LICENSE file. |
@@ -79,13 +79,15 @@ def GenerateMatchEntry( |
# Find the intersection between the lines that this file crashed on and |
# the changed lines. |
- (line_number_intersection, stack_frame_index_intersection) = ( |
+ (line_number_intersection, stack_frame_index_intersection, functions) = ( |
crash_utils.Intersection( |
- crashed_line_numbers, stack_frame_indices, changed_line_numbers)) |
+ crashed_line_numbers, stack_frame_indices, changed_line_numbers, |
+ function)) |
# Find the minimum distance between the changed lines and crashed lines. |
- min_distance = crash_utils.FindMinLineDistance(crashed_line_numbers, |
- changed_line_numbers) |
+ (min_distance, min_crashed_line, min_changed_line) = \ |
+ crash_utils.FindMinLineDistance(crashed_line_numbers, |
+ changed_line_numbers) |
# Check whether this CL changes the crashed lines or not. |
if line_number_intersection: |
@@ -103,15 +105,17 @@ def GenerateMatchEntry( |
# Update the min distance only if it is less than the current one. |
if min_distance < match.min_distance: |
match.min_distance = min_distance |
+ match.min_distance_info = (file_name, min_crashed_line, min_changed_line) |
# If this CL does not change the crashed line, all occurrence of this |
# file in the stack has the same priority. |
if not stack_frame_index_intersection: |
stack_frame_index_intersection = stack_frame_indices |
+ functions = function |
match.stack_frame_indices.append(stack_frame_index_intersection) |
match.changed_file_urls.append(diff_url) |
match.priorities.append(priority) |
- match.function_list.append(function) |
+ match.function_list.append(functions) |
def FindMatch(revisions_info_map, file_to_revision_info, file_to_crash_info, |
@@ -145,14 +149,13 @@ def FindMatch(revisions_info_map, file_to_revision_info, file_to_crash_info, |
# If the file in the stacktrace is not changed in any commits, continue. |
for changed_file_path in file_to_revision_info: |
- changed_file_name = changed_file_path.split('/')[-1] |
- crashed_file_name = crashed_file_path.split('/')[-1] |
- |
+ changed_file_name = changed_file_path.split('/')[-1].lower() |
+ crashed_file_name = crashed_file_path.split('/')[-1].lower() |
if changed_file_name != crashed_file_name: |
continue |
if not crash_utils.GuessIfSameSubPath( |
- changed_file_path, crashed_file_path): |
+ changed_file_path.lower(), crashed_file_path.lower()): |
continue |
crashed_line_numbers = file_to_crash_info.GetCrashedLineNumbers( |
@@ -356,9 +359,10 @@ def SortMatchesFunction(match_with_stack_priority): |
return (min(match.priorities), |
stack_priority, |
+ match.min_distance, |
crash_utils.FindMinStackFrameNumber(match.stack_frame_indices, |
match.priorities), |
- -len(match.changed_files), match.min_distance) |
+ -len(match.changed_files)) |
def SortAndFilterMatches(matches, num_important_frames=5): |
@@ -379,7 +383,6 @@ def SortAndFilterMatches(matches, num_important_frames=5): |
is_important_frame = False |
highest_priority_stack = crash_utils.INFINITY |
matches.sort(key=SortMatchesFunction) |
- |
# Iterate through the matches to find out what results are significant. |
for stack_priority, cl, match in matches: |
# Check if the current match changes crashed line. |
@@ -434,47 +437,56 @@ def GenerateReasonForMatches(matches): |
# (how the file is modified). |
match_by_priority = zip( |
match.priorities, match.crashed_line_numbers, match.changed_files, |
- match.changed_file_urls) |
+ match.stack_frame_indices, match.function_list) |
# Sort the zipped changed files in the match by their priority so that the |
# changed lines comes first in the reason. |
match_by_priority.sort( |
- key=lambda (priority, crashed_line_number, file_name, url): priority) |
+ key=lambda (priority, crashed_line_numbers, file_name, |
+ stack_frame_indices, function_list): priority) |
# Iterate through the sorted match. |
for i in range(len(match_by_priority)): |
- (priority, crashed_line_number, file_name, file_url) = \ |
- match_by_priority[i] |
+ (priority, crashed_line_numbers, file_name, stack_frame_indices, |
+ function_list) = match_by_priority[i] |
# If the file in the match is a line change, append a explanation. |
if priority == LINE_CHANGE_PRIORITY: |
+ crashed_line_numbers = [crashed_line_number |
+ for lines in crashed_line_numbers |
+ for crashed_line_number in lines] |
reason.append( |
- 'Line %s of file %s which potentially caused the crash ' |
- 'according to the stacktrace, is changed in this cl.\n' % |
- (crash_utils.PrettifyList(crashed_line_number), |
- crash_utils.PrettifyFiles([(file_name, file_url)]))) |
+ 'Line %s of file %s which potentially caused the crash ' |
+ 'according to the stacktrace, is changed in this cl' |
+ ' (From stack frame %s, function %s).' % |
+ (crash_utils.PrettifyList(crashed_line_numbers), |
+ file_name, |
+ crash_utils.PrettifyList(stack_frame_indices), |
+ crash_utils.PrettifyList(function_list))) |
else: |
# Get all the files that are not line change. |
rest_of_the_files = match_by_priority[i:] |
if len(rest_of_the_files) == 1: |
- file_string = 'File %s is changed in this cl.\n' |
+ file_string = 'File %s is changed in this cl ' |
else: |
- file_string = 'Files %s are changed in this cl.\n' |
+ file_string = 'Files %s are changed in this cl ' |
- # Create a list of file name and its url, and prettify the list. |
- file_name_with_url = [(file_name, file_url) |
- for (_, _, file_name, file_url) |
- in rest_of_the_files] |
- pretty_file_name_url = crash_utils.PrettifyFiles(file_name_with_url) |
+ # Create a list of file names, and prettify the list. |
+ file_names = [ |
+ file_name for (_, _, file_name, _, _) in rest_of_the_files] |
+ pretty_file_names = crash_utils.PrettifyList(file_names) |
# Add the reason, break because we took care of the rest of the files. |
- reason.append(file_string % pretty_file_name_url) |
+ file_string += ('(From stack frames %s, functions %s)' % |
+ (crash_utils.PrettifyList(stack_frame_indices), |
+ crash_utils.PrettifyList(function_list))) |
+ reason.append(file_string % pretty_file_names) |
break |
# Set the reason as string. |
- match.reason = ''.join(reason) |
+ match.reason = '\n'.join(reason) |
def CombineMatches(matches): |
@@ -505,6 +517,17 @@ def CombineMatches(matches): |
# Combine the reason if the current match is already in there. |
found_match.reason += match.reason |
+ if match.min_distance < found_match.min_distance: |
+ found_match.min_distance = match.min_distance |
+ found_match.min_distance_info = match.min_distance_info |
+ |
+ for stack_index, cl, match in combined_matches: |
+ if match.min_distance_info: |
+ file_name, min_crashed_line, min_changed_line = match.min_distance_info |
+ match.reason += \ |
+ ('\nMininimum distance from crashed line to changed line: %d. ' |
+ '(File: %s, Crashed on: %d, Changed: %d).' % |
+ (match.min_distance, file_name, min_crashed_line, min_changed_line)) |
return combined_matches |
@@ -535,7 +558,6 @@ def ParseCrashComponents(main_stack): |
Args: |
main_stack: Main stack from the stacktrace. |
- top_n_frames: A number of frames to regard as crashing frame. |
Returns: |
A set of components. |
@@ -564,10 +586,14 @@ def GenerateAndFilterBlameList(callstack, component_to_crash_revision_dict, |
Returns: |
A list of blame results. |
""" |
+ if component_to_regression_dict: |
+ parsed_deps = component_to_regression_dict |
+ else: |
+ parsed_deps = component_to_crash_revision_dict |
+ |
# Setup parser objects to use for parsing blame information. |
svn_parser = svn_repository_parser.SVNParser(CONFIG['svn']) |
- git_parser = git_repository_parser.GitParser(component_to_regression_dict, |
- CONFIG['git']) |
+ git_parser = git_repository_parser.GitParser(parsed_deps, CONFIG['git']) |
parsers = {} |
parsers['svn'] = svn_parser |
parsers['git'] = git_parser |
@@ -602,12 +628,16 @@ def FindItForCrash(stacktrace_list, |
""" |
# If regression information is not available, return blame information. |
if not component_to_regression_dict: |
- return_message = ( |
- 'Regression information is not available. The result is ' |
- 'the blame information.') |
result = GenerateAndFilterBlameList(callstack, |
component_to_crash_revision_dict, |
component_to_regression_dict) |
+ if result: |
+ return_message = ( |
+ 'Regression information is not available. The result is ' |
+ 'the blame information.') |
+ else: |
+ return_message = ('Findit could not find any suspected CLs.') |
+ |
return (return_message, result) |
for stacktrace in stacktrace_list: |
@@ -622,24 +652,33 @@ def FindItForCrash(stacktrace_list, |
result_for_stacktrace = FindMatchForStacktrace( |
stacktrace, components, component_to_regression_dict) |
+ filtered_result = FilterAndGenerateReasonForMatches(result_for_stacktrace) |
# If the result is empty, check the next stacktrace. Else, return the |
# filtered result. |
- if not result_for_stacktrace: |
+ if not filtered_result: |
continue |
return_message = ( |
'The result is a list of CLs that change the crashed files.') |
- result = FilterAndGenerateReasonForMatches(result_for_stacktrace) |
- return (return_message, result) |
+ return (return_message, filtered_result) |
# If no match is found, return the blame information for the input |
# callstack. |
- return_message = ( |
- 'There are no CLs that change the crashed files. The result is the ' |
- 'blame information.') |
result = GenerateAndFilterBlameList( |
callstack, component_to_crash_revision_dict, |
component_to_regression_dict) |
+ |
+ if result: |
+ return_message = ( |
+ 'No CL in the regression changes the crashed files. The result is ' |
+ 'the blame information.') |
+ |
+ # When findit could not find any CL that changes file in stacktrace or if |
+ # if cannot get any blame information, return a message saying that no |
+ # results are available. |
+ else: |
+ return_message = ('Findit could not find any suspected CLs.') |
+ |
return (return_message, result) |