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

Side by Side Diff: appengine/findit/crash/project_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
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 import logging 5 import logging
6 6
7 from crash.occurrence import RankByOccurrence 7 from crash.occurrence import RankByOccurrence
8 from crash.project import Project
8 from crash.type_enums import LanguageType 9 from crash.type_enums import LanguageType
9 from model.crash.crash_config import CrashConfig 10 from model.crash.crash_config import CrashConfig
10 11
11 12
12 class ProjectClassifier(object): 13 class ProjectClassifier(object):
13 """Determines the project of a crash - (project_name, project_path). 14 """Determines the project of a crash - (project_name, project_path).
14 15
15 For example: ('chromium', 'src/'), ('skia', 'src/skia/'), ...etc. 16 For example: ('chromium', 'src/'), ('skia', 'src/skia/'), ...etc.
16 """ 17 """
17 18
18 # TODO(http://crbug.com/657177): remove dependency on CrashConfig. 19 # TODO(http://crbug.com/657177): remove dependency on CrashConfig.
19 def __init__(self): 20 def __init__(self, projects, top_n_frames,
21 non_chromium_project_rank_priority=None):
20 super(ProjectClassifier, self).__init__() 22 super(ProjectClassifier, self).__init__()
21 self.project_classifier_config = CrashConfig.Get().project_classifier 23 self.projects = projects
22 if self.project_classifier_config: 24 self.top_n_frames = top_n_frames
23 self.project_classifier_config['host_directories'].sort( 25 self.non_chromium_project_rank_priority = non_chromium_project_rank_priority
24 key=lambda host: -len(host.split('/')))
25 26
26 # TODO(http://crbug.com/657177): refactor this into a method on Project. 27 @staticmethod
27 def _GetProjectFromDepPath(self, dep_path): 28 def _GetTopProject(projects, rank_function=None):
28 """Returns the project name from a dep path.""" 29 """Gets the highest ranking class among projects."""
29 if not dep_path: 30 projects = RankByOccurrence(projects, 1, rank_function=rank_function)
30 return ''
31 31
32 if dep_path == 'src/': 32 if projects:
33 return 'chromium' 33 return projects[0]
34 34
35 for host_directory in self.project_classifier_config['host_directories']: 35 logging.warning('ProjectClassifier.Classify: no projects found.')
36 if dep_path.startswith(host_directory): 36 return None
37 path = dep_path[len(host_directory):]
38 return 'chromium-%s' % path.split('/')[0].lower()
39 37
40 # Unknown path, return the whole path as project name. 38 def ClassifyCallStack(self, crash_stack):
41 return 'chromium-%s' % '_'.join(dep_path.split('/')) 39 """Determines which project is responsible for this crash stack.
42
43 # TODO(http://crbug.com/657177): refactor this into Project.MatchesStackFrame.
44 def GetClassFromStackFrame(self, frame):
45 """Determine which project is responsible for this frame."""
46 for marker, name in self.project_classifier_config[
47 'function_marker_to_project_name'].iteritems():
48 if frame.function.startswith(marker):
49 return name
50
51 for marker, name in self.project_classifier_config[
52 'file_path_marker_to_project_name'].iteritems():
53 if marker in frame.file_path or marker in frame.raw_file_path:
54 return name
55
56 return self._GetProjectFromDepPath(frame.dep_path)
57
58 # TODO(wrengr): refactor this into a method on Suspect which returns
59 # the cannonical frame (and documents why it's the one we return).
60 def GetClassFromSuspect(self, suspect):
61 """Determine which project is responsible for this suspect."""
62 if suspect.file_to_stack_infos:
63 # file_to_stack_infos is a dict mapping file_path to stack_infos,
64 # where stack_infos is a list of (frame, callstack_priority)
65 # pairs. So ``.values()`` returns a list of the stack_infos in an
66 # arbitrary order; the first ``[0]`` grabs the "first" stack_infos;
67 # the second ``[0]`` grabs the first pair from the list; and
68 # the third ``[0]`` grabs the ``frame`` from the pair.
69 # TODO(wrengr): why is that the right frame to look at?
70 frame = suspect.file_to_stack_infos.values()[0][0][0]
71 return self.GetClassFromStackFrame(frame)
72
73 return ''
74
75 def Classify(self, suspects, crash_stack):
76 """Classify project of a crash.
77 40
78 Args: 41 Args:
79 suspects (list of Suspect): culprit suspects. 42 suspects (list of Suspect): culprit suspects.
80 crash_stack (CallStack): the callstack that caused the crash.
81 43
82 Returns: 44 Returns:
83 The name of the most-suspected project; or the empty string on failure. 45 The name of the most-suspected project; or the empty string on failure.
84 """ 46 """
85 if not self.project_classifier_config:
86 logging.warning('ProjectClassifier.Classify: Empty configuration.')
87 return None
88
89 rank_function = None 47 rank_function = None
90 if crash_stack.language_type == LanguageType.JAVA: 48 if crash_stack.language_type == LanguageType.JAVA:
91 def _RankFunctionForJava(occurrence): 49 def RankFunctionForJava(occurrence):
92 # TODO(wrengr): why are we weighting by the length, instead of 50 # TODO(wrengr): why are we weighting by the length, instead of
93 # the negative length as we do in the DefaultOccurrenceRanging? 51 # the negative length as we do in the DefaultOccurrenceRanging?
94 weight = len(occurrence) 52 weight = len(occurrence)
95 project_name = occurrence.name 53 project_name = occurrence.name
96 if 'chromium' in project_name: 54 if 'chromium' in project_name:
97 index = 0 55 index = 0
98 else: 56 else:
99 index = self.project_classifier_config[ 57 index = self.non_chromium_project_rank_priority[project_name]
100 'non_chromium_project_rank_priority'][project_name]
101 return (weight, index) 58 return (weight, index)
102 59
103 rank_function = _RankFunctionForJava 60 rank_function = RankFunctionForJava
104 61
105 top_n_frames = self.project_classifier_config['top_n'] 62 def GetProjectFromStackFrame(frame):
106 # If ``suspects`` are available, we use the projects from there since 63 """Determine which project is responsible for this frame."""
107 # they're more reliable than the ones from the ``crash_stack``. 64 for project in self.projects:
108 if suspects: 65 if project.MatchesStackFrame(frame):
109 classes = map(self.GetClassFromSuspect, suspects[:top_n_frames]) 66 return project.GetName(frame.dep_path)
110 else:
111 classes = map(self.GetClassFromStackFrame,
112 crash_stack.frames[:top_n_frames])
113 67
114 # Since we're only going to return the highest-ranked class, might 68 return None
115 # as well set ``max_classes`` to 1.
116 projects = RankByOccurrence(classes, 1, rank_function=rank_function)
117 69
118 if projects: 70 projects = map(GetProjectFromStackFrame,
119 return projects[0] 71 crash_stack.frames[:self.top_n_frames])
120 72
121 logging.warning('ProjectClassifier.Classify: no projects found.') 73 return ProjectClassifier._GetTopProject(projects,
122 return '' 74 rank_function=rank_function)
75
76 def ClassifySuspect(self, suspect):
77 """Determine which project is responsible for this suspect."""
78 if not suspect or not suspect.changelog:
79 return None
80
81 def GetProjectFromTouchedFile(touched_file):
82 for project in self.projects:
83 if project.MatchesTouchedFile(suspect.dep_path,
84 touched_file.changed_path):
85 return project.GetName(suspect.dep_path)
86
87 return None
88
89 projects = map(GetProjectFromTouchedFile, suspect.changelog.touched_files)
90 return ProjectClassifier._GetTopProject(projects,
91 rank_function=lambda x:-len(x))
92
93 def ClassifySuspects(self, suspects):
94 """Determines which project is resposible for these suspects.
95
96 Args:
97 suspects (list of Suspect): culprit suspects.
98
99 Returns:
100 The name of the most-suspected project; or the empty string on failure.
101 """
102 projects = map(self.ClassifySuspect, suspects)
103 return ProjectClassifier._GetTopProject(projects,
104 rank_function=lambda x:-len(x))
OLDNEW
« no previous file with comments | « appengine/findit/crash/project.py ('k') | appengine/findit/crash/test/component_classifier_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698