Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2015 The Chromium Authors. All rights reserved. | 1 # Copyright 2015 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 unittest | 5 import unittest |
| 6 | 6 |
| 7 from telemetry.timeline import memory_dump_event | 7 from telemetry.timeline import memory_dump_event |
| 8 import mock | 8 import mock |
| 9 | 9 |
| 10 | 10 |
| 11 def TestProcessDumpEvent(dump_id='123456ABCDEF', pid=1234, start=0, mmaps=None, | 11 def MakeRawMemoryDumpEvent(dump_id='123456ABCDEF', pid=1234, start=0, |
| 12 allocators=None): | 12 mmaps=None, allocators=None): |
| 13 | |
| 13 def vm_region(mapped_file, byte_stats): | 14 def vm_region(mapped_file, byte_stats): |
| 14 return { | 15 return { |
| 15 'mf': mapped_file, | 16 'mf': mapped_file, |
| 16 'bs': {k: hex(v) for k, v in byte_stats.iteritems()}} | 17 'bs': {k: hex(v) for k, v in byte_stats.iteritems()}} |
| 17 | 18 |
| 18 def attrs(sizes): | 19 def attrs(sizes): |
| 19 return {'attrs': {k: {'value': hex(v), 'units': 'bytes'} | 20 return {'attrs': {k: {'value': hex(v), 'units': 'bytes'} |
| 20 for k, v in sizes.iteritems()}} | 21 for k, v in sizes.iteritems()}} |
| 21 | 22 |
| 22 if allocators is None: | 23 if allocators is None: |
| 23 allocators = {} | 24 allocators = {} |
| 24 | 25 |
| 25 event = {'ph': 'v', 'id': dump_id, 'pid': pid, 'ts': start * 1000, | 26 event = {'ph': 'v', 'id': dump_id, 'pid': pid, 'ts': start * 1000, |
| 26 'args': {'dumps': {'allocators': { | 27 'args': {'dumps': {'allocators': { |
| 27 name: attrs(sizes) for name, sizes in allocators.iteritems()}}}} | 28 name: attrs(sizes) for name, sizes in allocators.iteritems()}}}} |
| 28 if mmaps: | 29 if mmaps: |
| 29 event['args']['dumps']['process_mmaps'] = { | 30 event['args']['dumps']['process_mmaps'] = { |
| 30 'vm_regions': [vm_region(mapped_file, byte_stats) | 31 'vm_regions': [vm_region(mapped_file, byte_stats) |
| 31 for mapped_file, byte_stats in mmaps.iteritems()]} | 32 for mapped_file, byte_stats in mmaps.iteritems()]} |
| 32 | 33 |
| 34 return event | |
| 35 | |
| 36 | |
| 37 def TestProcessDumpEvent(dump_id='123456ABCDEF', pid=1234, start=0, mmaps=None, | |
| 38 allocators=None): | |
| 39 event = MakeRawMemoryDumpEvent(dump_id, pid, start, mmaps=mmaps, | |
| 40 allocators=allocators) | |
| 33 process = mock.Mock() | 41 process = mock.Mock() |
| 34 process.pid = event['pid'] | 42 process.pid = event['pid'] |
| 35 return memory_dump_event.ProcessMemoryDumpEvent(process, event) | 43 return memory_dump_event.ProcessMemoryDumpEvent(process, [event]) |
| 36 | 44 |
| 37 | 45 |
| 38 class ProcessMemoryDumpEventUnitTest(unittest.TestCase): | 46 class ProcessMemoryDumpEventUnitTest(unittest.TestCase): |
| 47 | |
| 39 def testProcessMemoryDump_allocators(self): | 48 def testProcessMemoryDump_allocators(self): |
| 40 memory_dump = TestProcessDumpEvent(allocators={ | 49 process = mock.Mock() |
| 41 'v8': {'size': 10, 'allocated_objects_size' : 5}, | 50 process.pid = 1234 |
| 42 'v8/allocated_objects': {'size': 4}, | 51 events = [ |
| 43 'skia': {'not_size': 10, 'allocated_objects_size' : 5}, | 52 MakeRawMemoryDumpEvent( |
| 44 'skia/cache1': {'size': 24}, | 53 pid=process.pid, allocators={ |
| 45 'skia/cache2': {'not_size': 20}, | 54 'v8': {'size': 10, 'allocated_objects_size': 5}, |
| 46 'skia/cache2/obj1': {'size': 8}, | 55 'v8/allocated_objects': {'size': 4}, |
| 47 'skia/cache2/obj2': {'size': 9}, | 56 'skia': {'not_size': 10, |
| 48 'skia_different/obj': {'size': 30}, | 57 'allocated_objects_size': 5}, |
| 49 'skia_different/obj/not_counted': {'size': 26}, | 58 'skia/cache1': {'size': 24} |
| 50 'global/0xdead': {'size': 26} | 59 } |
| 51 }) | 60 ), |
| 52 EXPECTED = { | 61 MakeRawMemoryDumpEvent( |
| 53 'skia': {'allocated_objects_size': 5, 'not_size': 30, 'size': 41}, | 62 pid=process.pid, allocators={ |
| 54 'v8': {'allocated_objects_size': 5, 'size': 10}, | 63 'skia/cache2': {'not_size': 20}, |
| 55 'skia_different': {'size': 30}} | 64 'skia/cache2/obj1': {'size': 8}, |
| 65 'skia/cache2/obj2': {'size': 9}, | |
| 66 'skia_different/obj': {'size': 30}, | |
| 67 'skia_different/obj/not_counted': {'size': 26}, | |
| 68 'global/0xdead': {'size': 26} | |
| 69 } | |
| 70 ) | |
| 71 ] | |
| 72 memory_dump = memory_dump_event.ProcessMemoryDumpEvent(process, events) | |
| 56 | 73 |
| 57 self.assertEquals(memory_dump._allocators, EXPECTED) | 74 EXPECTED_ALLOCATORS = { |
| 75 'skia': { | |
| 76 'allocated_objects_size': 5, | |
| 77 'not_size': 30, | |
| 78 'size': 41 | |
| 79 }, | |
| 80 'v8': { | |
| 81 'allocated_objects_size': 5, | |
| 82 'size': 10 | |
| 83 }, | |
| 84 'skia_different': {'size': 30} | |
| 85 } | |
| 86 | |
| 87 self.assertEquals(memory_dump._allocators, EXPECTED_ALLOCATORS) | |
| 58 | 88 |
| 59 def testProcessMemoryDump_mmaps(self): | 89 def testProcessMemoryDump_mmaps(self): |
| 60 ALL = [2 ** x for x in range(8)] | 90 ALL = [2 ** x for x in range(8)] |
| 61 (JAVA_SPACES, JAVA_CACHE, ASHMEM, NATIVE_1, NATIVE_2, | 91 (JAVA_SPACES, JAVA_CACHE, ASHMEM, NATIVE_1, NATIVE_2, STACK, FILES_APK, |
| 62 STACK, FILES_APK, DEVICE_GPU) = ALL | 92 DEVICE_GPU) = ALL |
| 63 | 93 |
| 64 memory_dump = TestProcessDumpEvent(mmaps={ | 94 memory_dump = TestProcessDumpEvent(mmaps={ |
| 65 '/dev/ashmem/dalvik-space-foo': {'pss': JAVA_SPACES}, | 95 '/dev/ashmem/dalvik-space-foo': {'pss': JAVA_SPACES}, |
| 66 '/dev/ashmem/dalvik-jit-code-cache': {'pss': JAVA_CACHE}, | 96 '/dev/ashmem/dalvik-jit-code-cache': {'pss': JAVA_CACHE}, |
| 67 '/dev/ashmem/other-random-stuff': {'pss': ASHMEM}, | 97 '/dev/ashmem/other-random-stuff': {'pss': ASHMEM}, |
| 68 '[heap] bar': {'pss': NATIVE_1}, | 98 '[heap] bar': {'pss': NATIVE_1}, |
| 69 '': {'pss': NATIVE_2}, | 99 '': {'pss': NATIVE_2}, |
| 70 '[stack thingy]': {'pss': STACK}, | 100 '[stack thingy]': {'pss': STACK}, |
| 71 'my_little_app.apk': {'pss': FILES_APK}, | 101 'my_little_app.apk': {'pss': FILES_APK}, |
| 72 '/dev/mali': {'pss': DEVICE_GPU}, | 102 '/dev/mali': {'pss': DEVICE_GPU} |
| 73 }) | 103 }) |
| 74 | 104 |
| 75 EXPECTED = { | 105 EXPECTED = { |
| 76 '/': sum(ALL), | 106 '/': sum(ALL), |
| 77 '/Android/Java runtime': JAVA_SPACES + JAVA_CACHE, | 107 '/Android/Java runtime': JAVA_SPACES + JAVA_CACHE, |
| 78 '/Android/Ashmem': ASHMEM, | 108 '/Android/Ashmem': ASHMEM, |
| 79 '/Android': JAVA_SPACES + JAVA_CACHE + ASHMEM, | 109 '/Android': JAVA_SPACES + JAVA_CACHE + ASHMEM, |
| 80 '/Native heap': NATIVE_1 + NATIVE_2, | 110 '/Native heap': NATIVE_1 + NATIVE_2, |
| 81 '/Stack': STACK, | 111 '/Stack': STACK, |
| 82 '/Files/apk': FILES_APK, | 112 '/Files/apk': FILES_APK, |
| 83 '/Devices': DEVICE_GPU} | 113 '/Devices': DEVICE_GPU} |
| 84 | 114 |
| 85 self.assertTrue(memory_dump.has_mmaps) | 115 self.assertTrue(memory_dump.has_mmaps) |
| 86 for path, value in EXPECTED.iteritems(): | 116 for path, value in EXPECTED.iteritems(): |
| 117 self.assertEquals( | |
| 118 value, | |
| 119 memory_dump.GetMemoryBucket(path).GetValue('proportional_resident')) | |
| 120 | |
| 121 def testProcessMemoryDump_composability(self): | |
| 122 java_spaces = 100 | |
| 123 process = mock.Mock() | |
| 124 process.pid = 1234 | |
| 125 allocators = {'v8': {'size': 10}} | |
| 126 mmaps = {'/dev/ashmem/dalvik-space-foo': {'pss': java_spaces}} | |
| 127 | |
| 128 events = [MakeRawMemoryDumpEvent(pid=process.pid, allocators=allocators), | |
| 129 MakeRawMemoryDumpEvent(pid=process.pid, mmaps=mmaps)] | |
| 130 memory_dump = memory_dump_event.ProcessMemoryDumpEvent(process, events) | |
| 131 | |
| 132 self.assertEquals(memory_dump._allocators, allocators) | |
| 133 | |
| 134 EXPECTED_MMAPS = { | |
| 135 '/': java_spaces, | |
| 136 '/Android/Java runtime': java_spaces, | |
| 137 '/Android': java_spaces, | |
| 138 } | |
| 139 | |
| 140 self.assertTrue(memory_dump.has_mmaps) | |
| 141 for path, value in EXPECTED_MMAPS.iteritems(): | |
| 87 self.assertEquals(value, | 142 self.assertEquals(value, |
| 88 memory_dump.GetMemoryBucket(path).GetValue( | 143 memory_dump.GetMemoryBucket(path).GetValue('proportional_resident')) |
| 89 'proportional_resident')) | |
| 90 | 144 |
| 91 | 145 |
| 92 class MemoryDumpEventUnitTest(unittest.TestCase): | 146 class MemoryDumpEventUnitTest(unittest.TestCase): |
| 93 def testRepr(self): | 147 def testRepr(self): |
| 94 process_dump1 = TestProcessDumpEvent( | 148 process_dump1 = TestProcessDumpEvent( |
| 95 mmaps={'/dev/ashmem/other-ashmem': {'pss': 5}}, | 149 mmaps={'/dev/ashmem/other-ashmem': {'pss': 5}}, |
| 96 allocators={'v8': {'size': 10, 'allocated_objects_size' : 5}}) | 150 allocators={'v8': {'size': 10, 'allocated_objects_size' : 5}}) |
| 97 process_dump2 = TestProcessDumpEvent( | 151 process_dump2 = TestProcessDumpEvent( |
| 98 mmaps={'/dev/ashmem/libc malloc': {'pss': 42, 'pd': 27}}, | 152 mmaps={'/dev/ashmem/libc malloc': {'pss': 42, 'pd': 27}}, |
| 99 allocators={'v8': {'size': 20, 'allocated_objects_size' : 10}, | 153 allocators={'v8': {'size': 20, 'allocated_objects_size' : 10}, |
| 100 'oilpan': {'size': 40}}) | 154 'oilpan': {'size': 40}}) |
| 101 global_dump = memory_dump_event.GlobalMemoryDump( | 155 global_dump = memory_dump_event.GlobalMemoryDump( |
| 102 [process_dump1, process_dump2]) | 156 [process_dump1, process_dump2]) |
| 103 | 157 |
| 104 self.assertEquals( | 158 self.assertEquals( |
| 105 repr(process_dump1), | 159 repr(process_dump1), |
| 106 'ProcessMemoryDumpEvent[pid=1234, allocated_objects_v8=5,' | 160 'ProcessMemoryDumpEvent[pid=1234, allocated_objects_v8=5, ' |
| 107 ' allocator_v8=10, mmaps_ashmem=5, mmaps_java_heap=0,' | 161 'allocator_v8=10, mmaps_ashmem=5, mmaps_overall_pss=5]') |
| 108 ' mmaps_native_heap=0, mmaps_overall_pss=5, mmaps_private_dirty=0]') | |
| 109 self.assertEquals( | 162 self.assertEquals( |
| 110 repr(process_dump2), | 163 repr(process_dump2), |
| 111 'ProcessMemoryDumpEvent[pid=1234, allocated_objects_v8=10,' | 164 'ProcessMemoryDumpEvent[pid=1234, allocated_objects_v8=10, ' |
| 112 ' allocator_oilpan=40, allocator_v8=20, mmaps_ashmem=0,' | 165 'allocator_oilpan=40, allocator_v8=20, mmaps_native_heap=42, ' |
| 113 ' mmaps_java_heap=0, mmaps_native_heap=42, mmaps_overall_pss=42,' | 166 'mmaps_overall_pss=42, mmaps_private_dirty=27]') |
| 114 ' mmaps_private_dirty=27]') | |
| 115 self.assertEquals( | 167 self.assertEquals( |
| 116 repr(global_dump), | 168 repr(global_dump), |
| 117 'GlobalMemoryDump[id=123456ABCDEF, allocated_objects_v8=15,' | 169 'GlobalMemoryDump[id=123456ABCDEF, allocated_objects_v8=15, ' |
| 118 ' allocator_oilpan=40, allocator_v8=30, mmaps_ashmem=5,' | 170 'allocator_oilpan=40, allocator_v8=30, mmaps_ashmem=5, ' |
| 119 ' mmaps_java_heap=0, mmaps_native_heap=42, mmaps_overall_pss=47,' | 171 'mmaps_native_heap=42, mmaps_overall_pss=47, mmaps_private_dirty=27]') |
| 120 ' mmaps_private_dirty=27]') | |
| 121 | 172 |
| 122 def testDumpEventsTiming(self): | 173 def testDumpEventsTiming(self): |
| 174 process = mock.Mock() | |
| 175 process.pid = 1 | |
| 176 composable_events = [ | |
| 177 MakeRawMemoryDumpEvent(pid=process.pid, start=8), | |
| 178 MakeRawMemoryDumpEvent(pid=process.pid, start=16), | |
| 179 MakeRawMemoryDumpEvent(pid=process.pid, start=10) | |
| 180 ] | |
| 123 memory_dump = memory_dump_event.GlobalMemoryDump([ | 181 memory_dump = memory_dump_event.GlobalMemoryDump([ |
| 182 memory_dump_event.ProcessMemoryDumpEvent(process, composable_events), | |
|
perezju
2016/01/13 16:30:34
keep the composed process_dump on a variable, and
ssid
2016/01/14 14:26:21
Done.
| |
| 124 TestProcessDumpEvent(pid=3, start=8), | 183 TestProcessDumpEvent(pid=3, start=8), |
| 125 TestProcessDumpEvent(pid=1, start=4), | |
| 126 TestProcessDumpEvent(pid=2, start=13), | 184 TestProcessDumpEvent(pid=2, start=13), |
| 127 TestProcessDumpEvent(pid=4, start=7)]) | 185 TestProcessDumpEvent(pid=4, start=7)]) |
| 128 | 186 |
| 129 self.assertFalse(memory_dump.has_mmaps) | 187 self.assertFalse(memory_dump.has_mmaps) |
| 130 self.assertEquals(4, | 188 self.assertEquals(4, len(list(memory_dump.IterProcessMemoryDumps()))) |
| 131 len(list(memory_dump.IterProcessMemoryDumps()))) | 189 self.assertAlmostEquals(7.0, memory_dump.start) |
| 132 self.assertAlmostEquals(4.0, | 190 self.assertAlmostEquals(16.0, memory_dump.end) |
| 133 memory_dump.start) | 191 self.assertAlmostEquals(9.0, memory_dump.duration) |
| 134 self.assertAlmostEquals(13.0, | |
| 135 memory_dump.end) | |
| 136 self.assertAlmostEquals(9.0, | |
| 137 memory_dump.duration) | |
| 138 | 192 |
| 139 def testGetMemoryUsage(self): | 193 def testGetMemoryUsage(self): |
| 140 ALL = [2 ** x for x in range(7)] | 194 ALL = [2 ** x for x in range(7)] |
| 141 (JAVA_HEAP_1, JAVA_HEAP_2, ASHMEM_1, ASHMEM_2, NATIVE, | 195 (JAVA_HEAP_1, JAVA_HEAP_2, ASHMEM_1, ASHMEM_2, NATIVE, |
| 142 DIRTY_1, DIRTY_2) = ALL | 196 DIRTY_1, DIRTY_2) = ALL |
| 143 | 197 |
| 144 memory_dump = memory_dump_event.GlobalMemoryDump([ | 198 memory_dump = memory_dump_event.GlobalMemoryDump([ |
| 145 TestProcessDumpEvent(pid=1, mmaps={ | 199 TestProcessDumpEvent(pid=1, mmaps={ |
| 146 '/dev/ashmem/dalvik-alloc space': {'pss': JAVA_HEAP_1}}), | 200 '/dev/ashmem/dalvik-alloc space': {'pss': JAVA_HEAP_1}}), |
| 147 TestProcessDumpEvent(pid=2, mmaps={ | 201 TestProcessDumpEvent(pid=2, mmaps={ |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 163 def testGetMemoryUsageWithAllocators(self): | 217 def testGetMemoryUsageWithAllocators(self): |
| 164 process_dump1 = TestProcessDumpEvent( | 218 process_dump1 = TestProcessDumpEvent( |
| 165 mmaps={'/dev/ashmem/other-ashmem': {'pss': 5}}, | 219 mmaps={'/dev/ashmem/other-ashmem': {'pss': 5}}, |
| 166 allocators={'v8': {'size': 10, 'allocated_objects_size' : 5}}) | 220 allocators={'v8': {'size': 10, 'allocated_objects_size' : 5}}) |
| 167 process_dump2 = TestProcessDumpEvent( | 221 process_dump2 = TestProcessDumpEvent( |
| 168 mmaps={'/dev/ashmem/other-ashmem': {'pss': 5}}, | 222 mmaps={'/dev/ashmem/other-ashmem': {'pss': 5}}, |
| 169 allocators={'v8': {'size': 20, 'allocated_objects_size' : 10}}) | 223 allocators={'v8': {'size': 20, 'allocated_objects_size' : 10}}) |
| 170 memory_dump = memory_dump_event.GlobalMemoryDump( | 224 memory_dump = memory_dump_event.GlobalMemoryDump( |
| 171 [process_dump1, process_dump2]) | 225 [process_dump1, process_dump2]) |
| 172 self.assertEquals({'mmaps_overall_pss': 10, | 226 self.assertEquals({'mmaps_overall_pss': 10, |
| 173 'mmaps_private_dirty': 0, | |
| 174 'mmaps_java_heap': 0, | |
| 175 'mmaps_ashmem': 10, | 227 'mmaps_ashmem': 10, |
| 176 'mmaps_native_heap': 0, | |
| 177 'allocator_v8': 30, | 228 'allocator_v8': 30, |
| 178 'allocated_objects_v8': 15}, | 229 'allocated_objects_v8': 15}, |
| 179 memory_dump.GetMemoryUsage()) | 230 memory_dump.GetMemoryUsage()) |
| 180 | 231 |
| 181 def testGetMemoryUsageWithAndroidMemtrack(self): | 232 def testGetMemoryUsageWithAndroidMemtrack(self): |
| 182 GL1, EGL1, GL2, EGL2 = [2 ** x for x in range(4)] | 233 GL1, EGL1, GL2, EGL2 = [2 ** x for x in range(4)] |
| 183 process_dump1 = TestProcessDumpEvent( | 234 process_dump1 = TestProcessDumpEvent( |
| 184 allocators={'gpu/android_memtrack/gl': {'memtrack_pss' : GL1}, | 235 allocators={'gpu/android_memtrack/gl': {'memtrack_pss' : GL1}, |
| 185 'gpu/android_memtrack/graphics': {'memtrack_pss': EGL1}}) | 236 'gpu/android_memtrack/graphics': {'memtrack_pss': EGL1}}) |
| 186 process_dump2 = TestProcessDumpEvent( | 237 process_dump2 = TestProcessDumpEvent( |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 199 memory_dump = memory_dump_event.GlobalMemoryDump([ | 250 memory_dump = memory_dump_event.GlobalMemoryDump([ |
| 200 TestProcessDumpEvent( | 251 TestProcessDumpEvent( |
| 201 mmaps={'/dev/ashmem/libc malloc': {'pss': HEAP + TRACING_2, | 252 mmaps={'/dev/ashmem/libc malloc': {'pss': HEAP + TRACING_2, |
| 202 'pd': DIRTY + TRACING_2}}, | 253 'pd': DIRTY + TRACING_2}}, |
| 203 allocators={ | 254 allocators={ |
| 204 'tracing': {'size': TRACING_1, 'resident_size': TRACING_2}, | 255 'tracing': {'size': TRACING_1, 'resident_size': TRACING_2}, |
| 205 'malloc': {'size': MALLOC + TRACING_1}})]) | 256 'malloc': {'size': MALLOC + TRACING_1}})]) |
| 206 | 257 |
| 207 self.assertEquals({'mmaps_overall_pss': HEAP, | 258 self.assertEquals({'mmaps_overall_pss': HEAP, |
| 208 'mmaps_private_dirty': DIRTY, | 259 'mmaps_private_dirty': DIRTY, |
| 209 'mmaps_java_heap': 0, | |
| 210 'mmaps_ashmem': 0, | |
| 211 'mmaps_native_heap': HEAP, | 260 'mmaps_native_heap': HEAP, |
| 212 'allocator_tracing': TRACING_1, | 261 'allocator_tracing': TRACING_1, |
| 213 'allocator_malloc': MALLOC}, | 262 'allocator_malloc': MALLOC}, |
| 214 memory_dump.GetMemoryUsage()) | 263 memory_dump.GetMemoryUsage()) |
| OLD | NEW |