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

Side by Side Diff: appengine/findit/crash/component_classifier.py

Issue 2657913002: [Predator] Add ``Project`` class and ``ClassifySuspect`` method to project and component classifier (Closed)
Patch Set: Fix nits. Created 3 years, 10 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
« no previous file with comments | « appengine/findit/crash/component.py ('k') | appengine/findit/crash/findit_for_chromecrash.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 namedtuple 5 from collections import namedtuple
6 from collections import defaultdict 6 from collections import defaultdict
7 import logging 7 import logging
8 import re 8 import re
9 9
10 from crash.component import Component 10 from crash.component import Component
11 from crash.occurrence import RankByOccurrence 11 from crash.occurrence import RankByOccurrence
12 from libs.gitiles.diff import ChangeType 12 from libs.gitiles.diff import ChangeType
13 13
14 14
15 class ComponentClassifier(object): 15 class ComponentClassifier(object):
16 """Determines the component of a crash. 16 """Determines the component of a crash.
17 17
18 For example: ['Blink>DOM', 'Blink>HTML']. 18 For example: ['Blink>DOM', 'Blink>HTML'].
19 """ 19 """
20 20
21 def __init__(self, components, top_n): 21 def __init__(self, components, top_n_frames):
22 """Build a classifier for components. 22 """Build a classifier for components.
23 23
24 Args: 24 Args:
25 components (list of crash.component.Component): the components to 25 components (list of crash.component.Component): the components to
26 check for. 26 check for.
27 top_n (int): how many frames of the callstack to look at""" 27 top_n_frames (int): how many frames of the callstack to look at.
28 """
28 super(ComponentClassifier, self).__init__() 29 super(ComponentClassifier, self).__init__()
29 if not components: 30 self.components = components or []
30 logging.warning('Empty configuration for component classifier.') 31 self.top_n_frames = top_n_frames
31 components = [] # Ensure self.components is not None
32 self.components = components
33 self.top_n = top_n
34
35 def GetClassFromStackFrame(self, frame):
36 """Determine which component is responsible for this frame."""
37 for component in self.components:
38 if component.MatchesStackFrame(frame):
39 return component.component_name
40
41 return ''
42
43 # TODO(wrengr): refactor this into a method on Suspect which returns
44 # the cannonical frame (and documents why it's the one we return).
45 def GetClassFromSuspect(self, suspect):
46 """Determine which component is responsible for this suspect.
47
48 Note that Findit assumes files that the culprit suspect touched come from
49 the same component.
50 """
51 if suspect.file_to_stack_infos:
52 # file_to_stack_infos is a dict mapping file_path to stack_infos,
53 # where stack_infos is a list of (frame, callstack_priority)
54 # pairs. So ``.values()`` returns a list of the stack_infos in an
55 # arbitrary order; the first ``[0]`` grabs the "first" stack_infos;
56 # the second ``[0]`` grabs the first pair from the list; and
57 # the third ``[0]`` grabs the ``frame`` from the pair.
58 # TODO(wrengr): why is that the right frame to look at?
59 frame = suspect.file_to_stack_infos.values()[0][0][0]
60 return self.GetClassFromStackFrame(frame)
61
62 return ''
63 32
64 # TODO(http://crbug.com/657177): return the Component objects 33 # TODO(http://crbug.com/657177): return the Component objects
65 # themselves, rather than strings naming them. 34 # themselves, rather than strings naming them.
66 def Classify(self, suspects, crash_stack): 35 def ClassifyCallStack(self, stack, top_n_components=2):
67 """Classifies component of a crash. 36 """Classifies component of a crash.
68 37
69 Args: 38 Args:
39 stack (CallStack): The callstack that caused the crash.
40 top_n_components (int): The number of top components for the stack,
41 defaults to 2.
42
43 Returns:
44 List of top n components.
45 """
46 def GetComponentFromStackFrame(frame):
47 """Determine which component is responsible for this frame."""
48 for component in self.components:
49 if component.MatchesStackFrame(frame):
50 return component.component_name
51
52 return None
53
54 components = map(GetComponentFromStackFrame,
55 stack.frames[:self.top_n_frames])
56 return RankByOccurrence(components, top_n_components)
57
58 # TODO(http://crbug.com/657177): return the Component objects
59 # themselves, rather than strings naming them.
60 def ClassifySuspects(self, suspects, top_n_components=2):
61 """Classifies component of a list of suspects.
62
63 Args:
70 suspects (list of Suspect): Culprit suspects. 64 suspects (list of Suspect): Culprit suspects.
71 crash_stack (CallStack): The callstack that caused the crash. 65 top_n_components (int): The number of top components for the stack,
66 defaults to 2.
72 67
73 Returns: 68 Returns:
74 List of top 2 components. 69 List of top 2 components.
75 """ 70 """
76 # If ``suspects`` are available, we use the components from there since 71 components = []
77 # they're more reliable than the ones from the ``crash_stack``. 72 for suspect in suspects:
78 if suspects: 73 components.extend(self.ClassifySuspect(suspect))
79 classes = map(self.GetClassFromSuspect, suspects[:self.top_n])
80 else:
81 classes = map(self.GetClassFromStackFrame,
82 crash_stack.frames[:self.top_n])
83 74
84 return RankByOccurrence(classes, 2) 75 return RankByOccurrence(components, top_n_components,
76 rank_function=lambda x: -len(x))
85 77
86 # TODO(ymzhang): use component of new path as default. RENAME might 78 def ClassifySuspect(self, suspect, top_n_components=2):
87 # need to return two (old path new path may have different components) 79 """ Classifies components of a suspect.
88 def GetClassFromFileChangeInfo(self, file_change_info): 80
89 """Determine which component is responsible for a touched file.""" 81 Args:
90 if not file_change_info: 82 suspect (Suspect): a change log
83 top_n_components (int): number of components assigned to this suspect,
84 defaults to 2.
85
86 Returns:
87 List of components
88 """
89 if not suspect or not suspect.changelog:
91 return None 90 return None
92 91
93 for component in self.components: 92 def GetComponentFromTouchedFile(touched_file):
94 if (file_change_info.change_type == ChangeType.DELETE): 93 """Determine which component is responsible for a touched file."""
95 if component.MatchesFile(file_change_info.old_path): 94 for component in self.components:
96 return component.component_name 95 if component.MatchesTouchedFile(suspect.dep_path,
97 else: 96 touched_file.changed_path):
98 if component.MatchesFile(file_change_info.new_path):
99 return component.component_name 97 return component.component_name
100 98
101 return ''
102
103 def ClassifyChangeLog(self, change_log, top_n=2):
104 """ Classifies components of a change log.
105
106 Args:
107 change_log: a change log
108 top_n: number of components assigned to this change log, default is 2
109
110 Returns:
111 List of components
112 """
113 if not change_log:
114 return None 99 return None
115 100
116 classes = map(self.GetClassFromFileChangeInfo, change_log.touched_files) 101 components = map(GetComponentFromTouchedFile,
117 return RankByOccurrence(classes, top_n, rank_function=lambda x:-len(x)) 102 suspect.changelog.touched_files)
103 return RankByOccurrence(components, top_n_components,
104 rank_function=lambda x: -len(x))
OLDNEW
« no previous file with comments | « appengine/findit/crash/component.py ('k') | appengine/findit/crash/findit_for_chromecrash.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698