def testEquals(self): a_names = related_name_map.RelatedNameMap() a_names.Set('a', 'A') self.assertNotEqual(a_names, generic_set.GenericSet([])) b_names = related_name_map.RelatedNameMap() self.assertNotEqual(a_names, b_names) b_names.Set('a', 'B') self.assertNotEqual(a_names, b_names) b_names.Set('a', 'A') self.assertEqual(a_names, b_names)
def testSerialize(self): names = related_name_map.RelatedNameMap() names.Set('a', 'x') names.Set('b', 'y') names.Set('c', 'z') s = histogram_serializer.HistogramSerializer() self.assertEqual(names.Serialize(s), [6, 0, 1, 2])
def testMerge(self): a_names = related_name_map.RelatedNameMap() a_names.Set('a', 'A') b_names = related_name_map.RelatedNameMap() b_names.Set('b', 'B') self.assertTrue(a_names.CanAddDiagnostic(b_names)) self.assertTrue(b_names.CanAddDiagnostic(a_names)) self.assertFalse(a_names.CanAddDiagnostic(generic_set.GenericSet([]))) a_names.AddDiagnostic(b_names) self.assertEqual(a_names.Get('b'), 'B') a_names.AddDiagnostic(b_names) self.assertEqual(a_names.Get('b'), 'B') b_names.Set('a', 'C') with self.assertRaises(ValueError): a_names.AddDiagnostic(b_names)
def testRoundtrip(self): names = related_name_map.RelatedNameMap() names.Set('a', 'A') d = names.AsDict() clone = diagnostic.Diagnostic.FromDict(d) self.assertEqual(histogram_unittest.ToJSON(d), histogram_unittest.ToJSON(clone.AsDict())) self.assertEqual(clone.Get('a'), 'A')
def testSerialize(self): hist = histogram.Histogram('aaa', 'count_biggerIsBetter') hist.description = 'lorem ipsum' hist.diagnostics['bbb'] = related_name_map.RelatedNameMap({ 'ccc': 'a:c', 'ddd': 'a:d', }) hist.diagnostics['hhh'] = generic_set.GenericSet(['ggg']) hist.AddSample(0, { 'bbb': breakdown.Breakdown.FromEntries({ 'ccc': 11, 'ddd': 31, }), 'eee': related_event_set.RelatedEventSet([{ 'stableId': 'fff', 'title': 'ggg', 'start': 3, 'duration': 4, }]), }) data = histogram_serializer.Serialize([hist]) self.assertEqual(data, [ [ 'aaa', [1, [1, 1000.0, 20]], '', 'ccc', 'ddd', [3, 4], 'ggg', 'avg', 'count', 'max', 'min', 'std', 'sum', 'lorem ipsum', 'a:c', 'a:d', ], { 'Breakdown': {'bbb': {5: [2, 5, 11, 31]}}, 'GenericSet': { 'hhh': {0: 6}, 'statisticsNames': {1: [7, 8, 9, 10, 11, 12]}, 'description': {3: 13}, }, 'RelatedEventSet': {'eee': {4: [['fff', 6, 3, 4]]}}, 'RelatedNameMap': {'bbb': {2: [5, 14, 15]}}, }, [ 0, 'count+', 1, [0, 1, 2, 3], [1, 0, None, 0, 0, 0, 0], {0: [1, [None, 4, 5]]}, 0, ] ])
def testMerge(self): events = related_event_set.RelatedEventSet() events.Add({ 'stableId': '0.0', 'title': 'foo', 'start': 0, 'duration': 1, }) generic = generic_set.GenericSet(['generic diagnostic']) generic2 = generic_set.GenericSet(['generic diagnostic 2']) related_map = related_name_map.RelatedNameMap() related_map.Set('a', 'histogram') hist = histogram.Histogram('', 'count') # When Histograms are merged, first an empty clone is created with an empty # DiagnosticMap. hist2 = histogram.Histogram('', 'count') hist2.diagnostics['a'] = generic hist.diagnostics.Merge(hist2.diagnostics) self.assertIs(generic, hist.diagnostics['a']) # Separate keys are not merged. hist3 = histogram.Histogram('', 'count') hist3.diagnostics['b'] = generic2 hist.diagnostics.Merge(hist3.diagnostics) self.assertIs(generic, hist.diagnostics['a']) self.assertIs(generic2, hist.diagnostics['b']) # Merging unmergeable diagnostics should produce an # UnmergeableDiagnosticSet. hist4 = histogram.Histogram('', 'count') hist4.diagnostics['a'] = related_map hist.diagnostics.Merge(hist4.diagnostics) self.assertIsInstance(hist.diagnostics['a'], ums.UnmergeableDiagnosticSet) diagnostics = list(hist.diagnostics['a']) self.assertIs(generic, diagnostics[0]) self.assertIs(related_map, diagnostics[1]) # UnmergeableDiagnosticSets are mergeable. hist5 = histogram.Histogram('', 'count') hist5.diagnostics['a'] = ums.UnmergeableDiagnosticSet( [events, generic2]) hist.diagnostics.Merge(hist5.diagnostics) self.assertIsInstance(hist.diagnostics['a'], ums.UnmergeableDiagnosticSet) diagnostics = list(hist.diagnostics['a']) self.assertIs(generic, diagnostics[0]) self.assertIs(related_map, diagnostics[1]) self.assertIs(events, diagnostics[2]) self.assertIs(generic2, diagnostics[3])
def Profile(self, root): self._histograms = histogram_set.HistogramSet() total_hist = self._GetOrCreateHistogram('heap') total_hist.diagnostics['types'] = related_name_map.RelatedNameMap() total_breakdown = breakdown.Breakdown() total_size = self._Recurse(root, total_hist.diagnostics['types'], total_breakdown) builtins_size = total_size - sum(subsize for _, subsize in total_breakdown) if builtins_size: total_breakdown.Set('(builtin types)', builtins_size) total_hist.AddSample(total_size, dict(types=total_breakdown)) self._histograms.AddSharedDiagnosticToAllHistograms( reserved_infos.TRACE_START.name, date_range.DateRange(time.time() * 1000)) return self._histograms
def _Recurse(self, obj, parent_related_names, parent_breakdown): if id(obj) in self._seen: return 0 self._seen.add(id(obj)) size = sys.getsizeof(obj) related_names = parent_related_names types_breakdown = parent_breakdown hist = None if _IsUserDefinedInstance(obj): type_name = type(obj).__name__ hist = self._GetOrCreateHistogram('heap:' + type_name) related_names = hist.diagnostics.get('types') if related_names is None: related_names = related_name_map.RelatedNameMap() types_breakdown = breakdown.Breakdown() if isinstance(obj, dict): for objkey, objvalue in obj.iteritems(): size += self._Recurse(objkey, related_names, types_breakdown) size += self._Recurse(objvalue, related_names, types_breakdown) elif isinstance(obj, (tuple, list, set, frozenset, collections.deque)): # Can't use collections.Iterable because strings are iterable, but # sys.getsizeof() already handles strings, we don't need to iterate over # them. for elem in obj: size += self._Recurse(elem, related_names, types_breakdown) # It is possible to subclass builtin types like dict and add properties to # them, so handle __dict__ and __slots__ even if obj is a dict/list/etc. properties_breakdown = breakdown.Breakdown() if hasattr(obj, '__dict__'): size += sys.getsizeof(obj.__dict__) for dkey, dvalue in obj.__dict__.iteritems(): size += self._Recurse(dkey, related_names, types_breakdown) dsize = self._Recurse(dvalue, related_names, types_breakdown) properties_breakdown.Set(dkey, dsize) size += dsize size += self._Recurse(obj.__dict__, related_names, types_breakdown) # It is possible for a class to use both __slots__ and __dict__ by listing # __dict__ as a slot. if hasattr(obj.__class__, '__slots__'): for slot in obj.__class__.__slots__: if slot == '__dict__': # obj.__dict__ was already handled continue if not hasattr(obj, slot): continue slot_size = self._Recurse(getattr(obj, slot), related_names, types_breakdown) properties_breakdown.Set(slot, slot_size) size += slot_size if hist: if len(related_names): hist.diagnostics['types'] = related_names parent_related_names.Set(type_name, hist.name) parent_breakdown.Set(type_name, parent_breakdown.Get(type_name) + size) builtins_size = size - sum(subsize for _, subsize in types_breakdown) if builtins_size: types_breakdown.Set('(builtin types)', builtins_size) sample_diagnostics = {'types': types_breakdown} if len(properties_breakdown): sample_diagnostics['properties'] = properties_breakdown if self._diagnostics_callback: sample_diagnostics.update(self._diagnostics_callback(obj)) hist.AddSample(size, sample_diagnostics) return size