| OLD | NEW |
| (Empty) |
| 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 | |
| 3 # found in the LICENSE file. | |
| 4 | |
| 5 | |
| 6 class Occurrence(list): | |
| 7 """A list of indices where something occurs in a list. | |
| 8 | |
| 9 The list of indices can be accessed directly, since this class is a | |
| 10 subclass of |list|. In addition to this list, we also have a |name| | |
| 11 property which specifies what thing is occurring in those positions. For | |
| 12 our uses here, the name is a string denoting either a project name | |
| 13 (e.g., 'chromium' or 'chromium-skia') or a component name (e.g., | |
| 14 'Blink>API' or 'Blink>DOM'). | |
| 15 """ | |
| 16 def __init__(self, name, indices=None): | |
| 17 super(Occurrence, self).__init__(indices or []) | |
| 18 self.name = name | |
| 19 | |
| 20 | |
| 21 # TODO(wrengr): why not return the dict itself? Or if we're going to | |
| 22 # return a list, why not take in the ranking function so we can perform | |
| 23 # the sorting ourselves? | |
| 24 def GetOccurrences(names): | |
| 25 """Return a concordance of elements in a list. | |
| 26 | |
| 27 Args: | |
| 28 names (list): a list of "names". Typically names are strings, but | |
| 29 they're actually allowed to be anything which can serve as a key | |
| 30 in a dict. | |
| 31 | |
| 32 Returns: | |
| 33 A list of Occurrence objects. For each name in |names| we produce | |
| 34 an Occurrence object, which in turn contains a list of the indices | |
| 35 where that name occurs in |names|. | |
| 36 """ | |
| 37 occurrences = {} | |
| 38 for index, name in enumerate(names or []): | |
| 39 if name not in occurrences: | |
| 40 occurrences[name] = Occurrence(name, [index]) | |
| 41 else: | |
| 42 occurrences[name].append(index) | |
| 43 | |
| 44 return occurrences.values() | |
| 45 | |
| 46 | |
| 47 def DefaultRankFunction(class_occurrence): | |
| 48 """Default function for ranking classes. | |
| 49 | |
| 50 Note: The default behavior works for component classifier and for | |
| 51 project classifier, it works for cpp callstack class ranking. | |
| 52 | |
| 53 Returns: | |
| 54 A pair of the weight/priority for this |class_occurrence|, and the | |
| 55 index of the first occurrence of this class's name in the list the | |
| 56 |class_occurrence| came from. | |
| 57 """ | |
| 58 # If the top 2 frames are in this class, then give it highest priority. | |
| 59 if 0 in class_occurrence and 1 in class_occurrence: | |
| 60 return -float('inf'), class_occurrence[0] | |
| 61 | |
| 62 return -len(class_occurrence), class_occurrence[0] | |
| 63 | |
| 64 | |
| 65 # TODO(http://crbug.com/644476): this class needs a better name. | |
| 66 class Classifier(object): | |
| 67 """Classifies results or crash stack into a class or a list of classes.""" | |
| 68 | |
| 69 def GetClassFromStackFrame(self, frame): # pragma: no cover. | |
| 70 raise NotImplementedError() | |
| 71 | |
| 72 def GetClassFromResult(self, result): # pragma: no cover. | |
| 73 raise NotImplementedError() | |
| 74 | |
| 75 def _Classify(self, results, crash_stack, top_n, max_classes, | |
| 76 rank_function=DefaultRankFunction): | |
| 77 """Classifies a crash to a list of classes, ranked by rank_function. | |
| 78 | |
| 79 Extracts a list of classes from results or crash_stack, rank the classes and | |
| 80 returns max_classes number of classes on the top. | |
| 81 | |
| 82 Args: | |
| 83 results (list of Result): Culprit results. | |
| 84 crash_stack (CallStack): The callstack that caused the crash. | |
| 85 top_n (int): Number of top frames to be considered when classifying. | |
| 86 max_classes (int): Maximal number of classes to return. | |
| 87 rank_function (function): Used to rank classes based on Occurrence. | |
| 88 | |
| 89 Returns: | |
| 90 A list of classes for this crash, ordered by the |rank_function|. | |
| 91 """ | |
| 92 # Extracts the class list from culprit results if possible since it's more | |
| 93 # reliable. | |
| 94 if results: | |
| 95 classes = map(self.GetClassFromResult, results[:top_n]) | |
| 96 else: | |
| 97 classes = map(self.GetClassFromStackFrame, crash_stack[:top_n]) | |
| 98 | |
| 99 occurrences = sorted(GetOccurrences(classes), key=rank_function) | |
| 100 | |
| 101 # Filter out unnamed classes. | |
| 102 classes = [occurrence.name for occurrence in occurrences if occurrence.name] | |
| 103 | |
| 104 return classes[:max_classes] | |
| 105 | |
| 106 def Classify(self, results, crash_stack): # pragma: no cover. | |
| 107 raise NotImplementedError() | |
| OLD | NEW |