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

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

Issue 2414523002: [Findit] Reorganizing findit_for_*.py (Closed)
Patch Set: Finally fixed the mock tests! Created 4 years, 1 month 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/crash_pipeline.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 import logging 6 import logging
7 import re 7 import re
8 8
9 from crash.classifier import Classifier 9 from crash.occurrence import RankByOccurrence
10 10
11 11 # TODO(http://crbug.com/659346): write coverage tests.
12 # TODO(wrengr): write coverage tests the old version was lacking.
13 class Component(namedtuple('Component', 12 class Component(namedtuple('Component',
14 ['component_name', 'path_regex', 'function_regex'])): # pragma: no cover 13 ['component_name', 'path_regex', 'function_regex'])): # pragma: no cover
15 """A representation of a "component" in Chromium. 14 """A representation of a "component" in Chromium.
16 15
17 For example: 'Blink>DOM' or 'Blink>HTML'. Notably, a component knows 16 For example: 'Blink>DOM' or 'Blink>HTML'. Notably, a component knows
18 how to identify itself. Hence, given a stack frame or change list 17 how to identify itself. Hence, given a stack frame or change list
19 or whatever, we ask the Component whether it matches that frame, 18 or whatever, we ask the Component whether it matches that frame,
20 CL, etc.""" 19 CL, etc."""
21 __slots__ = () 20 __slots__ = ()
22 21
23 def __new__(cls, component_name, path_regex, function_regex=None): 22 def __new__(cls, component_name, path_regex, function_regex=None):
24 return super(cls, Component).__new__(cls, 23 return super(cls, Component).__new__(cls,
25 component_name, 24 component_name,
26 re.compile(path_regex), 25 re.compile(path_regex),
27 re.compile(function_regex) if function_regex else None) 26 re.compile(function_regex) if function_regex else None)
28 27
29 def MatchesStackFrame(self, frame): 28 def MatchesStackFrame(self, frame):
30 """Return true if this component matches the frame.""" 29 """Return true if this component matches the frame."""
31 if not self.path_regex.match(frame.dep_path + frame.file_path): 30 if not self.path_regex.match(frame.dep_path + frame.file_path):
32 return False 31 return False
33 32
34 # We interpret function_regex=None to mean the regex that matches 33 # We interpret function_regex=None to mean the regex that matches
35 # everything. 34 # everything.
36 if not self.function_regex: 35 if not self.function_regex:
37 return True 36 return True
38 return self.function_regex.match(frame.function) 37 return self.function_regex.match(frame.function)
39 38
40 39
41 class ComponentClassifier(Classifier): 40 class ComponentClassifier(object):
42 """Determines the component of a crash. 41 """Determines the component of a crash.
43 42
44 For example: ['Blink>DOM', 'Blink>HTML']. 43 For example: ['Blink>DOM', 'Blink>HTML'].
45 """ 44 """
46 45
47 def __init__(self, components, top_n): 46 def __init__(self, components, top_n):
48 """Build a classifier for components. 47 """Build a classifier for components.
49 48
50 Args: 49 Args:
51 components (list of crash.component.Component): the components to 50 components (list of crash.component.Component): the components to
52 check for. 51 check for.
53 top_n (int): how many frames of the callstack to look at""" 52 top_n (int): how many frames of the callstack to look at"""
54 super(ComponentClassifier, self).__init__() 53 super(ComponentClassifier, self).__init__()
55 if not components: 54 if not components:
56 logging.warning('Empty configuration for component classifier.') 55 logging.warning('Empty configuration for component classifier.')
57 components = [] # Ensure self.components is not None 56 components = [] # Ensure self.components is not None
58 self.components = components 57 self.components = components
59 self.top_n = top_n 58 self.top_n = top_n
60 59
61 def GetClassFromStackFrame(self, frame): 60 def GetClassFromStackFrame(self, frame):
62 """Determine which component is responsible for this frame.""" 61 """Determine which component is responsible for this frame."""
63 for component in self.components: 62 for component in self.components:
64 if component.MatchesStackFrame(frame): 63 if component.MatchesStackFrame(frame):
65 return component.component_name 64 return component.component_name
66 65
67 return '' 66 return ''
68 67
68 # TODO(wrengr): refactor this into a method on Result which returns
69 # the cannonical frame (and documents why it's the one we return).
69 def GetClassFromResult(self, result): 70 def GetClassFromResult(self, result):
70 """Gets the component from a result. 71 """Determine which component is responsible for this result.
71 72
72 Note that Findit assumes files that the culprit result touched come from 73 Note that Findit assumes files that the culprit result touched come from
73 the same component. 74 the same component.
74 """ 75 """
75 if result.file_to_stack_infos: 76 if result.file_to_stack_infos:
76 # A file in culprit result should always have its stack_info, namely a 77 # file_to_stack_infos is a dict mapping file_path to stack_infos,
77 # list of (frame, callstack_priority) pairs. 78 # where stack_infos is a list of (frame, callstack_priority)
78 frame, _ = result.file_to_stack_infos.values()[0][0] 79 # pairs. So |.values()| returns a list of the stack_infos in an
80 # arbitrary order; the first |[0]| grabs the "first" stack_infos;
81 # the second |[0]| grabs the first pair from the list; and the third
82 # |[0]| grabs the |frame| from the pair.
83 # TODO(wrengr): why is that the right frame to look at?
84 frame = result.file_to_stack_infos.values()[0][0][0]
79 return self.GetClassFromStackFrame(frame) 85 return self.GetClassFromStackFrame(frame)
80 86
81 return '' 87 return ''
82 88
89 # TODO(http://crbug.com/657177): return the Component objects
90 # themselves, rather than strings naming them.
83 def Classify(self, results, crash_stack): 91 def Classify(self, results, crash_stack):
84 """Classifies project of a crash. 92 """Classifies component of a crash.
85 93
86 Args: 94 Args:
87 results (list of Result): Culprit results. 95 results (list of Result): Culprit results.
88 crash_stack (CallStack): The callstack that caused the crash. 96 crash_stack (CallStack): The callstack that caused the crash.
89 97
90 Returns: 98 Returns:
91 List of top 2 components. 99 List of top 2 components.
92 """ 100 """
93 return self._Classify(results, crash_stack, self.top_n, 2) 101 # If |results| are available, we use the components from there since
102 # they're more reliable than the ones from the |crash_stack|.
103 if results:
104 classes = map(self.GetClassFromResult, results[:self.top_n])
105 else:
106 classes = map(self.GetClassFromStackFrame, crash_stack[:self.top_n])
107
108 return RankByOccurrence(classes, 2)
OLDNEW
« no previous file with comments | « appengine/findit/crash/component.py ('k') | appengine/findit/crash/crash_pipeline.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698