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

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

Powered by Google App Engine
This is Rietveld 408576698