| OLD | NEW |
| 1 # Copyright (c) 2014 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import os | 5 import os |
| 6 from threading import Lock, Thread | 6 from threading import Lock |
| 7 | 7 |
| 8 import blame | 8 import blame |
| 9 from common import utils | 9 from common import utils |
| 10 import component_dictionary | 10 import component_dictionary |
| 11 import crash_utils | 11 import crash_utils |
| 12 import git_repository_parser | 12 import git_repository_parser |
| 13 import match_set | 13 import match_set |
| 14 import svn_repository_parser | 14 import svn_repository_parser |
| 15 | 15 |
| 16 | 16 |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 132 stacktrace. | 132 stacktrace. |
| 133 component_path: The path of the component to search for. | 133 component_path: The path of the component to search for. |
| 134 component_name: The name of the component to search for. | 134 component_name: The name of the component to search for. |
| 135 repository_parser: The parser object to parse the line diff. | 135 repository_parser: The parser object to parse the line diff. |
| 136 codereview_api_url: A code review url to retrieve data from. | 136 codereview_api_url: A code review url to retrieve data from. |
| 137 | 137 |
| 138 Returns: | 138 Returns: |
| 139 Matches, a set of match objects. | 139 Matches, a set of match objects. |
| 140 """ | 140 """ |
| 141 matches = match_set.MatchSet(codereview_api_url) | 141 matches = match_set.MatchSet(codereview_api_url) |
| 142 threads = [] | |
| 143 | 142 |
| 143 tasks = [] |
| 144 # Iterate through the crashed files in the stacktrace. | 144 # Iterate through the crashed files in the stacktrace. |
| 145 for crashed_file_path in file_to_crash_info: | 145 for crashed_file_path in file_to_crash_info: |
| 146 # Ignore header file. | 146 # Ignore header file. |
| 147 if crashed_file_path.endswith('.h'): | 147 if crashed_file_path.endswith('.h'): |
| 148 continue | 148 continue |
| 149 | 149 |
| 150 # If the file in the stacktrace is not changed in any commits, continue. | 150 # If the file in the stacktrace is not changed in any commits, continue. |
| 151 for changed_file_path in file_to_revision_info: | 151 for changed_file_path in file_to_revision_info: |
| 152 changed_file_name = changed_file_path.split('/')[-1].lower() | 152 changed_file_name = changed_file_path.split('/')[-1].lower() |
| 153 crashed_file_name = crashed_file_path.split('/')[-1].lower() | 153 crashed_file_name = crashed_file_path.split('/')[-1].lower() |
| (...skipping 11 matching lines...) Expand all Loading... |
| 165 functions = file_to_crash_info.GetCrashFunctions(crashed_file_path) | 165 functions = file_to_crash_info.GetCrashFunctions(crashed_file_path) |
| 166 | 166 |
| 167 # Iterate through the CLs that this file path is changed. | 167 # Iterate through the CLs that this file path is changed. |
| 168 for (cl, file_change_type) in file_to_revision_info[changed_file_path]: | 168 for (cl, file_change_type) in file_to_revision_info[changed_file_path]: |
| 169 # If the file change is delete, ignore this CL. | 169 # If the file change is delete, ignore this CL. |
| 170 if file_change_type == 'D': | 170 if file_change_type == 'D': |
| 171 continue | 171 continue |
| 172 | 172 |
| 173 revision = revisions_info_map[cl] | 173 revision = revisions_info_map[cl] |
| 174 | 174 |
| 175 match_thread = Thread( | 175 tasks.append({ |
| 176 target=GenerateMatchEntry, | 176 'function': GenerateMatchEntry, |
| 177 args=[matches, revision, cl, changed_file_path, functions, | 177 'args':[matches, revision, cl, changed_file_path, functions, |
| 178 component_path, component_name, crashed_line_numbers, | 178 component_path, component_name, crashed_line_numbers, |
| 179 stack_frame_nums, file_change_type, | 179 stack_frame_nums, file_change_type, |
| 180 repository_parser]) | 180 repository_parser]}) |
| 181 threads.append(match_thread) | |
| 182 match_thread.start() | |
| 183 | 181 |
| 184 for match_thread in threads: | 182 # Run all the tasks. |
| 185 match_thread.join() | 183 crash_utils.RunTasks(tasks) |
| 186 | 184 |
| 187 matches.RemoveRevertedCLs() | 185 matches.RemoveRevertedCLs() |
| 188 | 186 |
| 189 return matches | 187 return matches |
| 190 | 188 |
| 191 | 189 |
| 192 def FindMatchForComponent(component_path, file_to_crash_info, changelog, | 190 def FindMatchForComponent(component_path, file_to_crash_info, changelog, |
| 193 callstack_priority, results, results_lock): | 191 callstack_priority, results, results_lock): |
| 194 """Parses changelog and finds suspected CLs for a given component. | 192 """Parses changelog and finds suspected CLs for a given component. |
| 195 | 193 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 234 components: A set of components to look for. | 232 components: A set of components to look for. |
| 235 component_to_changelog_map: A map from component to its parsed changelog. | 233 component_to_changelog_map: A map from component to its parsed changelog. |
| 236 results: A list to aggregrate results from all stacktraces. | 234 results: A list to aggregrate results from all stacktraces. |
| 237 results_lock: A lock that guards results. | 235 results_lock: A lock that guards results. |
| 238 """ | 236 """ |
| 239 # Create component dictionary from the component and call stack. | 237 # Create component dictionary from the component and call stack. |
| 240 component_dict = component_dictionary.ComponentDictionary(callstack, | 238 component_dict = component_dictionary.ComponentDictionary(callstack, |
| 241 components) | 239 components) |
| 242 callstack_priority = callstack.priority | 240 callstack_priority = callstack.priority |
| 243 | 241 |
| 244 # Iterate through all components and create new thread for each component. | 242 # Iterate through all components. |
| 245 threads = [] | |
| 246 for component_path in component_dict: | 243 for component_path in component_dict: |
| 247 # If the component to consider in this callstack is not in the parsed list | 244 # If the component to consider in this callstack is not in the parsed list |
| 248 # of components, ignore this one. | 245 # of components, ignore this one. |
| 249 if component_path not in component_to_changelog_map: | 246 if component_path not in component_to_changelog_map: |
| 250 continue | 247 continue |
| 251 | 248 |
| 252 changelog = component_to_changelog_map[component_path] | 249 changelog = component_to_changelog_map[component_path] |
| 253 file_to_crash_info = component_dict.GetFileDict(component_path) | 250 file_to_crash_info = component_dict.GetFileDict(component_path) |
| 254 t = Thread( | 251 FindMatchForComponent(component_path, file_to_crash_info, changelog, |
| 255 target=FindMatchForComponent, | 252 callstack_priority, results, results_lock) |
| 256 args=[component_path, file_to_crash_info, changelog, | |
| 257 callstack_priority, results, results_lock]) | |
| 258 threads.append(t) | |
| 259 t.start() | |
| 260 | |
| 261 for t in threads: | |
| 262 t.join() | |
| 263 | 253 |
| 264 | 254 |
| 265 def FindMatchForStacktrace(stacktrace, components, | 255 def FindMatchForStacktrace(stacktrace, components, |
| 266 component_to_regression_dict): | 256 component_to_regression_dict): |
| 267 """Finds the culprit CL for stacktrace. | 257 """Finds the culprit CL for stacktrace. |
| 268 | 258 |
| 269 The passed stacktrace is either from release build stacktrace | 259 The passed stacktrace is either from release build stacktrace |
| 270 or debug build stacktrace. | 260 or debug build stacktrace. |
| 271 | 261 |
| 272 Args: | 262 Args: |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 313 # If the returned map from ParseChangeLog is empty, we don't need to look | 303 # If the returned map from ParseChangeLog is empty, we don't need to look |
| 314 # further because either the parsing failed or the changelog is empty. | 304 # further because either the parsing failed or the changelog is empty. |
| 315 if not (revisions and file_to_revision_map): | 305 if not (revisions and file_to_revision_map): |
| 316 continue | 306 continue |
| 317 | 307 |
| 318 component_to_changelog_map[component_path] = (repository_parser, | 308 component_to_changelog_map[component_path] = (repository_parser, |
| 319 component_name, | 309 component_name, |
| 320 revisions, | 310 revisions, |
| 321 file_to_revision_map) | 311 file_to_revision_map) |
| 322 | 312 |
| 323 # Create separate threads for each of the call stack in the stacktrace. | 313 # Analyze each of the call stacks in the stacktrace. |
| 324 threads = [] | |
| 325 for callstack in stacktrace.stack_list: | 314 for callstack in stacktrace.stack_list: |
| 326 t = Thread( | 315 FindMatchForCallstack(callstack, components, component_to_changelog_map, |
| 327 target=FindMatchForCallstack, | 316 results, results_lock) |
| 328 args=[callstack, components, component_to_changelog_map, | |
| 329 results, results_lock]) | |
| 330 threads.append(t) | |
| 331 t.start() | |
| 332 | |
| 333 for t in threads: | |
| 334 t.join() | |
| 335 | 317 |
| 336 return results | 318 return results |
| 337 | 319 |
| 338 | 320 |
| 339 def SortMatchesFunction(match_with_stack_priority): | 321 def SortMatchesFunction(match_with_stack_priority): |
| 340 """A function to sort the match triple. | 322 """A function to sort the match triple. |
| 341 | 323 |
| 342 Currently, it sorts the list by: | 324 Currently, it sorts the list by: |
| 343 1) The highest priority file change in the CL (changing crashed line is | 325 1) The highest priority file change in the CL (changing crashed line is |
| 344 higher priority than just changing the file). | 326 higher priority than just changing the file). |
| (...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 672 'The result is the blame information.') | 654 'The result is the blame information.') |
| 673 | 655 |
| 674 # When findit could not find any CL that changes file in stacktrace or if | 656 # When findit could not find any CL that changes file in stacktrace or if |
| 675 # if cannot get any blame information, return a message saying that no | 657 # if cannot get any blame information, return a message saying that no |
| 676 # results are available. | 658 # results are available. |
| 677 else: | 659 else: |
| 678 return_message = ('Findit could not find any suspected CLs.') | 660 return_message = ('Findit could not find any suspected CLs.') |
| 679 | 661 |
| 680 return (return_message, result) | 662 return (return_message, result) |
| 681 | 663 |
| OLD | NEW |