Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / tools / memory_inspector / memory_inspector / core / memory_map.py
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 import bisect
6
7
8 PAGE_SIZE = 4096
9
10
11 class Map(object):
12   """Models the memory map of a given |backends.Process|.
13
14   This is typically obtained by calling backends.Process.DumpMemoryMaps()."""
15
16   def __init__(self):
17     self.entries = []  # List of |MapEntry|, sorted by start address.
18
19   def Add(self, entry):
20     assert(isinstance(entry, MapEntry))
21     bisect.insort_right(self.entries, entry)
22
23   def Lookup(self, addr):
24     """Returns the MapEntry containing the given address, if any."""
25     idx = bisect.bisect_right(self.entries, addr) - 1
26     if idx < 0:
27       return None
28     entry = self.entries[idx]
29     assert(addr >= entry.start)
30     # bisect_right returns the latest element <= addr, but addr might fall after
31     # its end (in which case we want to return None here).
32     if addr > entry.end:
33       return None
34     return entry
35
36   def __getitem__(self, index):
37     return self.entries[index]
38
39   def __len__(self):
40     return len(self.entries)
41
42
43 class MapEntry(object):
44   """An entry (address range + stats) in a memory |Map|."""
45
46   def __init__(self, start, end, prot_flags, mapped_file, mapped_offset,
47       priv_dirty_bytes=0, priv_clean_bytes=0, shared_dirty_bytes=0,
48       shared_clean_bytes=0, resident_pages=None):
49     assert(end > start)
50     assert(start >= 0)
51     self.start = start
52     self.end = end
53     self.prot_flags = prot_flags
54     self.mapped_file = mapped_file
55     self.mapped_offset = mapped_offset
56     self.priv_dirty_bytes = priv_dirty_bytes
57     self.priv_clean_bytes = priv_clean_bytes
58     self.shared_dirty_bytes = shared_dirty_bytes
59     self.shared_clean_bytes = shared_clean_bytes
60     # resident_pages is a bitmap (array of bytes) in which each bit represents
61     # the presence of its corresponding page.
62     self.resident_pages = resident_pages or []
63
64   def GetRelativeMMOffset(self, abs_addr):
65     """Converts abs_addr to the corresponding offset in the mm.
66
67     Returns:
68       A tuple: (page_index, offset_in_page)
69     """
70     assert(self.Contains(abs_addr))
71     offset = abs_addr - self.start
72     return (offset / PAGE_SIZE, offset & (PAGE_SIZE - 1))
73
74   def GetRelativeFileOffset(self, abs_addr):
75     """Converts abs_addr to the corresponding offset in the mapped file."""
76     assert(self.Contains(abs_addr))
77     return abs_addr - self.start + self.mapped_offset
78
79   def IsPageResident(self, relative_page_index):
80     """Checks whether a given memory page is resident in memory."""
81     assert(relative_page_index >= 0 and
82            relative_page_index < self.len / PAGE_SIZE)
83     arr_idx = relative_page_index / 8
84     arr_bit = relative_page_index % 8
85     # Trailing zeros are trimmed by memdump (to optimize dump time).
86     if arr_idx >= len(self.resident_pages):
87       return False
88     return (self.resident_pages[arr_idx] & (1 << arr_bit)) != 0
89
90   def Contains(self, abs_addr):
91     """Determines whether a given absolute address belongs to the current mm."""
92     return abs_addr >= self.start and abs_addr <= self.end
93
94   def __cmp__(self, other):
95     """Comparison operator required for bisect."""
96     if isinstance(other, MapEntry):
97       return self.start - other.start
98     elif isinstance(other, (long, int)):
99       return self.start - other
100     else:
101       raise Exception('Cannot compare with %s' % other.__class__)
102
103   @property
104   def len(self):
105     return self.end - self.start + 1
106
107   @property
108   def num_pages(self):
109     return self.len / PAGE_SIZE
110
111   @property
112   def rss_bytes(self):
113     return (self.priv_dirty_bytes + self.priv_clean_bytes +
114             self.shared_dirty_bytes + self.shared_clean_bytes)