PageRenderTime 56ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/tools/memory_inspector/memory_inspector/core/native_heap_unittest.py

https://gitlab.com/jonnialva90/iridium-browser
Python | 147 lines | 88 code | 25 blank | 34 comment | 0 complexity | ade0d1d688dfad67e43be12e3ecd43c7 MD5 | raw file
  1. # Copyright 2014 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. The test scenario is as follows:
  6. VA space: |0 |4k |8k |12k |16k |20k ... |64k |65k |66k
  7. Mmaps: [ anon 1 ][anon 2] [anon 3] ... [ exe1 ][ exe2 ]
  8. Resident: *******-------*******-------******* (*:resident, -:not resident)
  9. Allocs: <1> <2> < 3 >
  10. | | |
  11. S.Traces: | | +-----------> st1[exe1 + 0, exe1 + 4]
  12. | +--------------------------> st1[exe1 + 0, exe1 + 4]
  13. +------------------------------> st2[exe1 + 0, exe2 + 4, post-exe2]
  14. Furthermore, the exe2 is a file mapping with non-zero (8k) offset.
  15. """
  16. import unittest
  17. from memory_inspector.core import memory_map
  18. from memory_inspector.core import native_heap
  19. from memory_inspector.core import stacktrace
  20. from memory_inspector.core import symbol
  21. from memory_inspector.core.memory_map import PAGE_SIZE
  22. class NativeHeapTest(unittest.TestCase):
  23. def runTest(self):
  24. nheap = native_heap.NativeHeap()
  25. EXE_1_MM_BASE = 64 * PAGE_SIZE
  26. EXE_2_MM_BASE = 65 * PAGE_SIZE
  27. EXE_2_FILE_OFF = 8192
  28. st1 = stacktrace.Stacktrace()
  29. st1.Add(nheap.GetStackFrame(EXE_1_MM_BASE))
  30. st1.Add(nheap.GetStackFrame(EXE_1_MM_BASE + 4))
  31. st2 = stacktrace.Stacktrace()
  32. st2.Add(nheap.GetStackFrame(EXE_1_MM_BASE))
  33. st2.Add(nheap.GetStackFrame(EXE_2_MM_BASE + 4))
  34. st2.Add(nheap.GetStackFrame(EXE_2_MM_BASE + PAGE_SIZE + 4))
  35. # Check that GetStackFrames keeps one unique object instance per address.
  36. # This is to guarantee that the symbolization logic (SymbolizeUsingSymbolDB)
  37. # can cheaply iterate on distinct stack frames rather than re-processing
  38. # every stack frame for each allocation (and save memory as well).
  39. self.assertIs(st1[0], st2[0])
  40. self.assertIsNot(st1[0], st1[1])
  41. self.assertIsNot(st2[0], st2[1])
  42. alloc1 = native_heap.Allocation(start=4, size=4, stack_trace=st1)
  43. alloc2 = native_heap.Allocation(start=4090, size=8, stack_trace=st1)
  44. alloc3 = native_heap.Allocation(start=8190, size=10000, stack_trace=st2)
  45. nheap.Add(alloc1)
  46. nheap.Add(alloc2)
  47. nheap.Add(alloc3)
  48. self.assertEqual(len(nheap.allocations), 3)
  49. self.assertIn(alloc1, nheap.allocations)
  50. self.assertIn(alloc2, nheap.allocations)
  51. self.assertIn(alloc3, nheap.allocations)
  52. ############################################################################
  53. # Test the relativization (absolute address -> mmap + offset) logic.
  54. ############################################################################
  55. mmap = memory_map
  56. mmap = memory_map.Map()
  57. mmap.Add(memory_map.MapEntry(EXE_1_MM_BASE, EXE_1_MM_BASE + PAGE_SIZE - 1,
  58. 'rw--', '/d/exe1', 0))
  59. mmap.Add(memory_map.MapEntry(EXE_2_MM_BASE, EXE_2_MM_BASE + PAGE_SIZE - 1,
  60. 'rw--', 'exe2',EXE_2_FILE_OFF))
  61. # Entry for EXE_3 is deliberately missing to check the fallback behavior.
  62. nheap.RelativizeStackFrames(mmap)
  63. self.assertEqual(st1[0].exec_file_rel_path, '/d/exe1')
  64. self.assertEqual(st1[0].exec_file_name, 'exe1')
  65. self.assertEqual(st1[0].offset, 0)
  66. self.assertEqual(st1[1].exec_file_rel_path, '/d/exe1')
  67. self.assertEqual(st1[1].exec_file_name, 'exe1')
  68. self.assertEqual(st1[1].offset, 4)
  69. self.assertEqual(st2[0].exec_file_rel_path, '/d/exe1')
  70. self.assertEqual(st2[0].exec_file_name, 'exe1')
  71. self.assertEqual(st2[0].offset, 0)
  72. self.assertEqual(st2[1].exec_file_rel_path, 'exe2')
  73. self.assertEqual(st2[1].exec_file_name, 'exe2')
  74. self.assertEqual(st2[1].offset, 4 + EXE_2_FILE_OFF)
  75. self.assertIsNone(st2[2].exec_file_rel_path)
  76. self.assertIsNone(st2[2].exec_file_name)
  77. self.assertIsNone(st2[2].offset)
  78. ############################################################################
  79. # Test the symbolization logic.
  80. ############################################################################
  81. syms = symbol.Symbols()
  82. syms.Add('/d/exe1', 0, symbol.Symbol('sym1', 'src1.c', 1)) # st1[0]
  83. syms.Add('exe2', 4 + EXE_2_FILE_OFF, symbol.Symbol('sym3')) # st2[1]
  84. nheap.SymbolizeUsingSymbolDB(syms)
  85. self.assertEqual(st1[0].symbol.name, 'sym1')
  86. self.assertEqual(st1[0].symbol.source_info[0].source_file_path, 'src1.c')
  87. self.assertEqual(st1[0].symbol.source_info[0].line_number, 1)
  88. # st1[1] should have no symbol info, because we didn't provide any above.
  89. self.assertIsNone(st1[1].symbol)
  90. # st2[0] and st1[0] were the same Frame. Expect identical symbols instances.
  91. self.assertIs(st2[0].symbol, st1[0].symbol)
  92. # st2[1] should have a symbols name, but no source line info.
  93. self.assertEqual(st2[1].symbol.name, 'sym3')
  94. self.assertEqual(len(st2[1].symbol.source_info), 0)
  95. # st2[2] should have no sym because we didn't even provide a mmap for exe3.
  96. self.assertIsNone(st2[2].symbol)
  97. ############################################################################
  98. # Test the resident size calculation logic (intersects mmaps and allocs).
  99. ############################################################################
  100. mmap.Add(
  101. memory_map.MapEntry(0, 8191, 'rw--', '', 0, resident_pages=[1]))
  102. mmap.Add(
  103. memory_map.MapEntry(8192, 12287, 'rw--', '', 0, resident_pages=[1]))
  104. # [12k, 16k] is deliberately missing to check the fallback behavior.
  105. mmap.Add(
  106. memory_map.MapEntry(16384, 20479, 'rw--', '', 0, resident_pages=[1]))
  107. nheap.CalculateResidentSize(mmap)
  108. # alloc1 [4, 8] is fully resident because it lays in the first resident 4k.
  109. self.assertEqual(alloc1.resident_size, 4)
  110. # alloc2 [4090, 4098] should have only 6 resident bytes ([4090,4096]), but
  111. # not the last two, which lay on the second page which is noijt resident.
  112. self.assertEqual(alloc2.resident_size, 6)
  113. # alloc3 [8190, 18190] is split as follows (* = resident):
  114. # [8190, 8192]: these 2 bytes are NOT resident, they lay in the 2nd page.
  115. # *[8192, 12288]: the 3rd page is resident and is fully covered by alloc3.
  116. # [12288, 16384]: the 4th page is fully covered as well, but not resident.
  117. # *[16384, 18190]: the 5th page is partially covered and resident.
  118. self.assertEqual(alloc3.resident_size, (12288 - 8192) + (18190 - 16384))