| OLD | NEW |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. | 1 # Copyright 2016 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 from collections import defaultdict | 5 from collections import defaultdict |
| 6 import logging | 6 import logging |
| 7 | 7 |
| 8 from common.chrome_dependency_fetcher import ChromeDependencyFetcher | 8 from common.chrome_dependency_fetcher import ChromeDependencyFetcher |
| 9 from crash import changelist_classifier | 9 from crash.stacktrace import StackInfo |
| 10 from crash.changelist_classifier import StackInfo | 10 from crash.suspect import Suspect |
| 11 from crash.crash_report import CrashReport | 11 from crash.crash_report import CrashReport |
| 12 from crash.loglinear.model import UnnormalizedLogLinearModel | 12 from crash.loglinear.model import UnnormalizedLogLinearModel |
| 13 | 13 |
| 14 | 14 |
| 15 class LogLinearChangelistClassifier(object): | 15 class LogLinearChangelistClassifier(object): |
| 16 """A ``LogLinearModel``-based implementation of CL classification.""" | 16 """A ``LogLinearModel``-based implementation of CL classification.""" |
| 17 | 17 |
| 18 def __init__(self, get_repository, meta_feature, meta_weight, | 18 def __init__(self, get_repository, meta_feature, meta_weight, |
| 19 top_n_frames=7, top_n_suspects=3): | 19 top_n_frames=7, top_n_suspects=3): |
| 20 """ | 20 """ |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 62 | 62 |
| 63 Args: | 63 Args: |
| 64 report (CrashReport): the crash we seek to explain. | 64 report (CrashReport): the crash we seek to explain. |
| 65 | 65 |
| 66 Returns: | 66 Returns: |
| 67 A list of ``Suspect``s who may be to blame for the | 67 A list of ``Suspect``s who may be to blame for the |
| 68 ``report``. Notably these ``Suspect`` instances do not have | 68 ``report``. Notably these ``Suspect`` instances do not have |
| 69 all their fields filled in. They will be filled in later by | 69 all their fields filled in. They will be filled in later by |
| 70 ``RankSuspects``. | 70 ``RankSuspects``. |
| 71 """ | 71 """ |
| 72 # Look at all the frames from any stack in the crash report, and | 72 reverted_revisions = [] |
| 73 # organize the ones that come from dependencies we care about. | 73 revision_to_suspects = {} |
| 74 dep_to_file_to_stack_infos = defaultdict(lambda: defaultdict(list)) | 74 for dep_roll in report.dependency_rolls.itervalues(): |
| 75 for stack in report.stacktrace.stacks: | 75 repository = self._get_repository(dep_roll.repo_url) |
| 76 for frame in stack.frames: | 76 changelogs = repository.GetChangeLogs(dep_roll.old_revision, |
| 77 if frame.dep_path in report.dependencies: | 77 dep_roll.new_revision) |
| 78 dep_to_file_to_stack_infos[frame.dep_path][frame.file_path].append( | |
| 79 StackInfo(frame, stack.priority)) | |
| 80 | 78 |
| 81 dep_to_file_to_changelogs, ignore_cls = ( | 79 for changelog in changelogs or []: |
| 82 changelist_classifier.GetChangeLogsForFilesGroupedByDeps( | 80 # When someone reverts, we need to skip both the CL doing |
| 83 report.dependency_rolls, report.dependencies, | 81 # the reverting as well as the CL that got reverted. If |
| 84 self._get_repository)) | 82 # ``reverted_revision`` is true, then this CL reverts another one, |
| 83 # so we skip it and save the CL it reverts in ``reverted_cls`` to |
| 84 # be filtered out later. |
| 85 if changelog.reverted_revision: |
| 86 reverted_revisions.append(changelog.reverted_revision) |
| 87 continue |
| 85 | 88 |
| 86 # Get the possible suspects. | 89 revision_to_suspects[changelog.revision] = Suspect(changelog, |
| 87 return changelist_classifier.FindSuspects( | 90 dep_roll.path) |
| 88 dep_to_file_to_changelogs, | 91 |
| 89 dep_to_file_to_stack_infos, | 92 for reverted_revision in reverted_revisions: |
| 90 report.dependencies, | 93 del revision_to_suspects[reverted_revision] |
| 91 self._get_repository, | 94 |
| 92 ignore_cls) | 95 return revision_to_suspects.values() |
| 93 | 96 |
| 94 def RankSuspects(self, report, suspects): | 97 def RankSuspects(self, report, suspects): |
| 95 """Returns a lineup of the suspects in order of likelihood. | 98 """Returns a lineup of the suspects in order of likelihood. |
| 96 | 99 |
| 97 Suspects with a discardable score or lower ranking than top_n_suspects | 100 Suspects with a discardable score or lower ranking than top_n_suspects |
| 98 will be filtered. | 101 will be filtered. |
| 99 | 102 |
| 100 Args: | 103 Args: |
| 101 report (CrashReport): the crash we seek to explain. | 104 report (CrashReport): the crash we seek to explain. |
| 102 suspects (iterable of Suspect): the CLs to consider blaming for the crash. | 105 suspects (iterable of Suspect): the CLs to consider blaming for the crash. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 125 suspect.confidence = score | 128 suspect.confidence = score |
| 126 # features is ``MetaFeatureValue`` object containing all feature values. | 129 # features is ``MetaFeatureValue`` object containing all feature values. |
| 127 features = features_given_report(suspect) | 130 features = features_given_report(suspect) |
| 128 suspect.reasons = features.reason | 131 suspect.reasons = features.reason |
| 129 suspect.changed_files = [changed_file.ToDict() | 132 suspect.changed_files = [changed_file.ToDict() |
| 130 for changed_file in features.changed_files] | 133 for changed_file in features.changed_files] |
| 131 scored_suspects.append(suspect) | 134 scored_suspects.append(suspect) |
| 132 | 135 |
| 133 scored_suspects.sort(key=lambda suspect: suspect.confidence) | 136 scored_suspects.sort(key=lambda suspect: suspect.confidence) |
| 134 return scored_suspects[:self._top_n_suspects] | 137 return scored_suspects[:self._top_n_suspects] |
| OLD | NEW |