def testGetMemoryUsageWithAndroidMemtrack(self): GL1, EGL1, GL2, EGL2 = [2**x for x in range(4)] process_dump1 = TestProcessDumpEvent( allocators={ 'gpu/android_memtrack/gl': { 'memtrack_pss': GL1 }, 'gpu/android_memtrack/graphics': { 'memtrack_pss': EGL1 } }) process_dump2 = TestProcessDumpEvent( allocators={ 'gpu/android_memtrack/gl': { 'memtrack_pss': GL2 }, 'gpu/android_memtrack/graphics': { 'memtrack_pss': EGL2 } }) memory_dump = memory_dump_event.GlobalMemoryDump( [process_dump1, process_dump2]) self.assertEquals( { 'android_memtrack_gl': GL1 + GL2, 'android_memtrack_graphics': EGL1 + EGL2 }, memory_dump.GetMemoryUsage())
def testGetMemoryUsageDiscountsTracing(self): ALL = [2**x for x in range(5)] (HEAP, DIRTY, MALLOC, TRACING_1, TRACING_2) = ALL memory_dump = memory_dump_event.GlobalMemoryDump([ TestProcessDumpEvent(mmaps={ '/dev/ashmem/libc malloc': { 'pss': HEAP + TRACING_2, 'pd': DIRTY + TRACING_2 } }, allocators={ 'tracing': { 'size': TRACING_1, 'resident_size': TRACING_2 }, 'malloc': { 'size': MALLOC + TRACING_1 } }) ]) self.assertEquals( { 'mmaps_overall_pss': HEAP, 'mmaps_private_dirty': DIRTY, 'mmaps_java_heap': 0, 'mmaps_ashmem': 0, 'mmaps_native_heap': HEAP, 'allocator_tracing': TRACING_1, 'allocator_malloc': MALLOC }, memory_dump.GetMemoryUsage())
def testGetMemoryUsageWithAllocators(self): process_dump1 = TestProcessDumpEvent( mmaps={'/dev/ashmem/other-ashmem': { 'pss': 5 }}, allocators={'v8': { 'size': 10, 'allocated_objects_size': 5 }}) process_dump2 = TestProcessDumpEvent( mmaps={'/dev/ashmem/other-ashmem': { 'pss': 5 }}, allocators={'v8': { 'size': 20, 'allocated_objects_size': 10 }}) memory_dump = memory_dump_event.GlobalMemoryDump( [process_dump1, process_dump2]) self.assertEquals( { 'mmaps_overall_pss': 10, 'mmaps_private_dirty': 0, 'mmaps_java_heap': 0, 'mmaps_ashmem': 10, 'mmaps_native_heap': 0, 'allocator_v8': 30, 'allocated_objects_v8': 15 }, memory_dump.GetMemoryUsage())
def testDumpEventsTiming(self): process = mock.Mock() process.pid = 1 composable_dump = memory_dump_event.ProcessMemoryDumpEvent( process, [ MakeRawMemoryDumpEvent(pid=process.pid, start=8), MakeRawMemoryDumpEvent(pid=process.pid, start=16), MakeRawMemoryDumpEvent(pid=process.pid, start=10) ]) self.assertAlmostEquals(8.0, composable_dump.start) self.assertAlmostEquals(16.0, composable_dump.end) memory_dump = memory_dump_event.GlobalMemoryDump([ composable_dump, TestProcessDumpEvent(pid=3, start=8), TestProcessDumpEvent(pid=2, start=13), TestProcessDumpEvent(pid=4, start=7) ]) self.assertFalse(memory_dump.has_mmaps) self.assertEquals(4, len(list(memory_dump.IterProcessMemoryDumps()))) self.assertItemsEqual([1, 2, 3, 4], memory_dump.pids) self.assertAlmostEquals(7.0, memory_dump.start) self.assertAlmostEquals(16.0, memory_dump.end) self.assertAlmostEquals(9.0, memory_dump.duration)
def MockTimelineModel(process_dumps): dumps_by_id = collections.defaultdict(list) for process_dump in process_dumps: dumps_by_id[process_dump.dump_id].append(process_dump) global_dumps = sorted((memory_dump_event.GlobalMemoryDump(dumps) for dumps in dumps_by_id.itervalues()), key=lambda dump: dump.start) mock_model = mock.Mock() mock_model.IterGlobalMemoryDumps = mock.Mock(return_value=global_dumps) return mock_model
def testDumpEventsTiming(self): memory_dump = memory_dump_event.GlobalMemoryDump([ TestProcessDumpEvent(pid=3, start=8), TestProcessDumpEvent(pid=1, start=4), TestProcessDumpEvent(pid=2, start=13), TestProcessDumpEvent(pid=4, start=7) ]) self.assertFalse(memory_dump.has_mmaps) self.assertEquals(4, len(list(memory_dump.IterProcessMemoryDumps()))) self.assertAlmostEquals(4.0, memory_dump.start) self.assertAlmostEquals(13.0, memory_dump.end) self.assertAlmostEquals(9.0, memory_dump.duration)
def testRepr(self): process_dump1 = TestProcessDumpEvent( mmaps={'/dev/ashmem/other-ashmem': { 'pss': 5 }}, allocators={'v8': { 'size': 10, 'allocated_objects_size': 5 }}) process_dump2 = TestProcessDumpEvent( mmaps={'/dev/ashmem/libc malloc': { 'pss': 42, 'pd': 27 }}, allocators={ 'v8': { 'size': 20, 'allocated_objects_size': 10 }, 'oilpan': { 'size': 40 } }) global_dump = memory_dump_event.GlobalMemoryDump( [process_dump1, process_dump2]) self.assertEquals( repr(process_dump1), 'ProcessMemoryDumpEvent[pid=1234, allocated_objects_v8=5,' ' allocator_v8=10, mmaps_ashmem=5, mmaps_java_heap=0,' ' mmaps_native_heap=0, mmaps_overall_pss=5, mmaps_private_dirty=0]' ) self.assertEquals( repr(process_dump2), 'ProcessMemoryDumpEvent[pid=1234, allocated_objects_v8=10,' ' allocator_oilpan=40, allocator_v8=20, mmaps_ashmem=0,' ' mmaps_java_heap=0, mmaps_native_heap=42, mmaps_overall_pss=42,' ' mmaps_private_dirty=27]') self.assertEquals( repr(global_dump), 'GlobalMemoryDump[id=123456ABCDEF, allocated_objects_v8=15,' ' allocator_oilpan=40, allocator_v8=30, mmaps_ashmem=5,' ' mmaps_java_heap=0, mmaps_native_heap=42, mmaps_overall_pss=47,' ' mmaps_private_dirty=27]')
def testGetMemoryUsage(self): ALL = [2**x for x in range(7)] (JAVA_HEAP_1, JAVA_HEAP_2, ASHMEM_1, ASHMEM_2, NATIVE, DIRTY_1, DIRTY_2) = ALL memory_dump = memory_dump_event.GlobalMemoryDump([ TestProcessDumpEvent( pid=1, mmaps={'/dev/ashmem/dalvik-alloc space': { 'pss': JAVA_HEAP_1 }}), TestProcessDumpEvent(pid=2, mmaps={ '/dev/ashmem/other-ashmem': { 'pss': ASHMEM_1, 'pd': DIRTY_1 } }), TestProcessDumpEvent(pid=3, mmaps={ '[heap] native': { 'pss': NATIVE, 'pd': DIRTY_2 }, '/dev/ashmem/dalvik-zygote space': { 'pss': JAVA_HEAP_2 } }), TestProcessDumpEvent( pid=4, mmaps={'/dev/ashmem/other-ashmem': { 'pss': ASHMEM_2 }}) ]) self.assertTrue(memory_dump.has_mmaps) self.assertItemsEqual([1, 2, 3, 4], memory_dump.pids) self.assertEquals( { 'mmaps_overall_pss': sum(ALL[:5]), 'mmaps_private_dirty': DIRTY_1 + DIRTY_2, 'mmaps_java_heap': JAVA_HEAP_1 + JAVA_HEAP_2, 'mmaps_ashmem': ASHMEM_1 + ASHMEM_2, 'mmaps_native_heap': NATIVE }, memory_dump.GetMemoryUsage())
def _CreateMemoryDumps(self): self._model.SetGlobalMemoryDumps( memory_dump_event.GlobalMemoryDump(events) for events in self._all_memory_dumps_by_dump_id.itervalues())
def AddResults(self, model, renderer_thread, interactions, results): # Note: This method will be called by TimelineBasedMeasurement once for # each thread x interaction_label combination; where |interactions| is # a list of all interactions sharing the same label that occurred in the # given |renderer_thread|. def ContainedIn(dump, interaction): return interaction.start < dump.start and dump.end < interaction.end def OccursDuringInteractions(dump): return ( # Dump must contain the rendrerer process that requested it, renderer_thread.parent.pid in dump.pids and # ... and fall within the span of an interaction record. any( ContainedIn(dump, interaction) for interaction in interactions)) def ReportResultsForProcess(memory_dumps, process_name): if not memory_dumps: metric_values = dict.fromkeys(DEFAULT_METRICS) num_processes = None none_reason = 'No memory dumps with mmaps found within interactions' else: metric_values = collections.defaultdict(list) num_processes = [] for dump in memory_dumps: for metric, value in dump.GetMemoryUsage().iteritems(): metric_values[metric].append(value) num_processes.append(dump.CountProcessMemoryDumps()) none_reason = None for metric, values in metric_values.iteritems(): results.AddValue( list_of_scalar_values.ListOfScalarValues( page=results.current_page, name='memory_%s_%s' % (metric, process_name), units='bytes', tir_label=interactions[0].label, values=values, none_value_reason=none_reason, improvement_direction=improvement_direction.DOWN)) results.AddValue( list_of_scalar_values.ListOfScalarValues( page=results.current_page, name='process_count_%s' % process_name, units='count', tir_label=interactions[0].label, values=num_processes, none_value_reason=none_reason, improvement_direction=improvement_direction.DOWN)) memory_dumps = filter(OccursDuringInteractions, model.IterGlobalMemoryDumps()) # Either all dumps should contain memory maps (Android, Linux), or none # of them (Windows, Mac). assert len(set(dump.has_mmaps for dump in memory_dumps)) <= 1 ReportResultsForProcess(memory_dumps, 'total') memory_dumps_by_process_name = collections.defaultdict(list) for memory_dump in memory_dumps: # Split this global memory_dump into individual process dumps, and then # group them by their process names. process_dumps_by_name = collections.defaultdict(list) for process_dump in memory_dump.IterProcessMemoryDumps(): process_name = process_dump.process_name.lower().replace( ' ', '_') process_dumps_by_name[process_name].append(process_dump) # Merge process dumps that have the same process name into a new # global dump. Note: this is slightly abusing GlobalMemoryDump so that # we can say dump.GetMemoryUsage() on the created dump objects to obtain # the memory usage aggregated per type. This should no longer be needed # after moving to TBMv2. See: http://crbug.com/581716 for process_name, process_dumps in process_dumps_by_name.iteritems( ): memory_dumps_by_process_name[process_name].append( memory_dump_event.GlobalMemoryDump(process_dumps)) for process_name, memory_dumps in memory_dumps_by_process_name.iteritems( ): ReportResultsForProcess(memory_dumps, process_name)