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
3 // found in the LICENSE file.
4 
5 #ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
6 #define BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
7 
8 #include <stddef.h>
9 
10 #include <map>
11 #include <unordered_map>
12 #include <vector>
13 
14 #include "base/base_export.h"
15 #include "base/macros.h"
16 #include "base/memory/ref_counted.h"
17 #include "base/trace_event/heap_profiler_allocation_context.h"
18 #include "base/trace_event/memory_allocator_dump.h"
19 #include "base/trace_event/memory_allocator_dump_guid.h"
20 #include "base/trace_event/memory_dump_request_args.h"
21 #include "build/build_config.h"
22 
23 // Define COUNT_RESIDENT_BYTES_SUPPORTED if platform supports counting of the
24 // resident memory.
25 #if !defined(OS_NACL) && !defined(OS_BSD)
26 #define COUNT_RESIDENT_BYTES_SUPPORTED
27 #endif
28 
29 namespace perfetto {
30 namespace protos {
31 namespace pbzero {
32 class MemoryTrackerSnapshot;
33 }
34 }  // namespace protos
35 }  // namespace perfetto
36 
37 namespace base {
38 
39 class UnguessableToken;
40 
41 namespace trace_event {
42 
43 class TracedValue;
44 
45 // ProcessMemoryDump is as a strongly typed container which holds the dumps
46 // produced by the MemoryDumpProvider(s) for a specific process.
47 class BASE_EXPORT ProcessMemoryDump {
48  public:
49   struct BASE_EXPORT MemoryAllocatorDumpEdge {
50     bool operator==(const MemoryAllocatorDumpEdge&) const;
51     bool operator!=(const MemoryAllocatorDumpEdge&) const;
52 
53     MemoryAllocatorDumpGuid source;
54     MemoryAllocatorDumpGuid target;
55     int importance = 0;
56     bool overridable = false;
57   };
58 
59   // Maps allocator dumps absolute names (allocator_name/heap/subheap) to
60   // MemoryAllocatorDump instances.
61   using AllocatorDumpsMap =
62       std::map<std::string, std::unique_ptr<MemoryAllocatorDump>>;
63 
64   // Stores allocator dump edges indexed by source allocator dump GUID.
65   using AllocatorDumpEdgesMap =
66       std::map<MemoryAllocatorDumpGuid, MemoryAllocatorDumpEdge>;
67 
68 #if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
69   // Returns the number of bytes in a kernel memory page. Some platforms may
70   // have a different value for kernel page sizes from user page sizes. It is
71   // important to use kernel memory page sizes for resident bytes calculation.
72   // In most cases, the two are the same.
73   static size_t GetSystemPageSize();
74 
75   // Returns the total bytes resident for a virtual address range, with given
76   // |start_address| and |mapped_size|. |mapped_size| is specified in bytes. The
77   // value returned is valid only if the given range is currently mmapped by the
78   // process. The |start_address| must be page-aligned.
79   static size_t CountResidentBytes(void* start_address, size_t mapped_size);
80 
81   // The same as above, but the given mapped range should belong to the
82   // shared_memory's mapped region.
83   static base::Optional<size_t> CountResidentBytesInSharedMemory(
84       void* start_address,
85       size_t mapped_size);
86 #endif
87 
88   explicit ProcessMemoryDump(const MemoryDumpArgs& dump_args);
89   ProcessMemoryDump(ProcessMemoryDump&&);
90   ~ProcessMemoryDump();
91 
92   ProcessMemoryDump& operator=(ProcessMemoryDump&&);
93 
94   // Creates a new MemoryAllocatorDump with the given name and returns the
95   // empty object back to the caller.
96   // Arguments:
97   //   absolute_name: a name that uniquely identifies allocator dumps produced
98   //       by this provider. It is possible to specify nesting by using a
99   //       path-like string (e.g., v8/isolate1/heap1, v8/isolate1/heap2).
100   //       Leading or trailing slashes are not allowed.
101   //   guid: an optional identifier, unique among all processes within the
102   //       scope of a global dump. This is only relevant when using
103   //       AddOwnershipEdge() to express memory sharing. If omitted,
104   //       it will be automatically generated.
105   // ProcessMemoryDump handles the memory ownership of its MemoryAllocatorDumps.
106   MemoryAllocatorDump* CreateAllocatorDump(const std::string& absolute_name);
107   MemoryAllocatorDump* CreateAllocatorDump(const std::string& absolute_name,
108                                            const MemoryAllocatorDumpGuid& guid);
109 
110   // Looks up a MemoryAllocatorDump given its allocator and heap names, or
111   // nullptr if not found.
112   MemoryAllocatorDump* GetAllocatorDump(const std::string& absolute_name) const;
113 
114   // Do NOT use this method. All dump providers should use
115   // CreateAllocatorDump(). Tries to create a new MemoryAllocatorDump only if it
116   // doesn't already exist. Creating multiple dumps with same name using
117   // GetOrCreateAllocatorDump() would override the existing scalars in MAD and
118   // cause misreporting. This method is used only in rare cases multiple
119   // components create allocator dumps with same name and only one of them adds
120   // size.
121   MemoryAllocatorDump* GetOrCreateAllocatorDump(
122       const std::string& absolute_name);
123 
124   // Creates a shared MemoryAllocatorDump, to express cross-process sharing.
125   // Shared allocator dumps are allowed to have duplicate guids within the
126   // global scope, in order to reference the same dump from multiple processes.
127   // See the design doc goo.gl/keU6Bf for reference usage patterns.
128   MemoryAllocatorDump* CreateSharedGlobalAllocatorDump(
129       const MemoryAllocatorDumpGuid& guid);
130 
131   // Creates a shared MemoryAllocatorDump as CreateSharedGlobalAllocatorDump,
132   // but with a WEAK flag. A weak dump will be discarded unless a non-weak dump
133   // is created using CreateSharedGlobalAllocatorDump by at least one process.
134   // The WEAK flag does not apply if a non-weak dump with the same GUID already
135   // exists or is created later. All owners and children of the discarded dump
136   // will also be discarded transitively.
137   MemoryAllocatorDump* CreateWeakSharedGlobalAllocatorDump(
138       const MemoryAllocatorDumpGuid& guid);
139 
140   // Looks up a shared MemoryAllocatorDump given its guid.
141   MemoryAllocatorDump* GetSharedGlobalAllocatorDump(
142       const MemoryAllocatorDumpGuid& guid) const;
143 
144   // Returns the map of the MemoryAllocatorDumps added to this dump.
allocator_dumps()145   const AllocatorDumpsMap& allocator_dumps() const { return allocator_dumps_; }
146 
mutable_allocator_dumps_for_serialization()147   AllocatorDumpsMap* mutable_allocator_dumps_for_serialization() const {
148     // Mojo takes a const input argument even for move-only types that can be
149     // mutate while serializing (like this one). Hence the const_cast.
150     return const_cast<AllocatorDumpsMap*>(&allocator_dumps_);
151   }
152   void SetAllocatorDumpsForSerialization(
153       std::vector<std::unique_ptr<MemoryAllocatorDump>>);
154 
155   // Only for mojo serialization.
156   std::vector<MemoryAllocatorDumpEdge> GetAllEdgesForSerialization() const;
157   void SetAllEdgesForSerialization(const std::vector<MemoryAllocatorDumpEdge>&);
158 
159   // Dumps heap usage with |allocator_name|.
160   void DumpHeapUsage(
161       const std::unordered_map<base::trace_event::AllocationContext,
162                                base::trace_event::AllocationMetrics>&
163           metrics_by_context,
164       base::trace_event::TraceEventMemoryOverhead& overhead,
165       const char* allocator_name);
166 
167   // Adds an ownership relationship between two MemoryAllocatorDump(s) with the
168   // semantics: |source| owns |target|, and has the effect of attributing
169   // the memory usage of |target| to |source|. |importance| is optional and
170   // relevant only for the cases of co-ownership, where it acts as a z-index:
171   // the owner with the highest importance will be attributed |target|'s memory.
172   // If an edge is present, its importance will not be updated unless
173   // |importance| is larger.
174   void AddOwnershipEdge(const MemoryAllocatorDumpGuid& source,
175                         const MemoryAllocatorDumpGuid& target,
176                         int importance);
177   void AddOwnershipEdge(const MemoryAllocatorDumpGuid& source,
178                         const MemoryAllocatorDumpGuid& target);
179 
180   // Adds edges that can be overriden by a later or earlier call to
181   // AddOwnershipEdge() with the same source and target with a different
182   // |importance| value.
183   void AddOverridableOwnershipEdge(const MemoryAllocatorDumpGuid& source,
184                                    const MemoryAllocatorDumpGuid& target,
185                                    int importance);
186 
187   // Creates ownership edges for shared memory. Handles the case of cross
188   // process sharing and importance of ownership for the case with and without
189   // the shared memory dump provider. This handles both shared memory from both
190   // legacy base::SharedMemory as well as current base::SharedMemoryMapping. The
191   // weak version creates a weak global dump.
192   // |client_local_dump_guid| The guid of the local dump created by the client
193   // of base::SharedMemory.
194   // |shared_memory_guid| The ID of the shared memory that is assigned globally,
195   // used to create global dump edges in the new model.
196   // |importance| Importance of the global dump edges to say if the current
197   // process owns the memory segment.
198   void CreateSharedMemoryOwnershipEdge(
199       const MemoryAllocatorDumpGuid& client_local_dump_guid,
200       const UnguessableToken& shared_memory_guid,
201       int importance);
202   void CreateWeakSharedMemoryOwnershipEdge(
203       const MemoryAllocatorDumpGuid& client_local_dump_guid,
204       const UnguessableToken& shared_memory_guid,
205       int importance);
206 
allocator_dumps_edges()207   const AllocatorDumpEdgesMap& allocator_dumps_edges() const {
208     return allocator_dumps_edges_;
209   }
210 
211   // Utility method to add a suballocation relationship with the following
212   // semantics: |source| is suballocated from |target_node_name|.
213   // This creates a child node of |target_node_name| and adds an ownership edge
214   // between |source| and the new child node. As a result, the UI will not
215   // account the memory of |source| in the target node.
216   void AddSuballocation(const MemoryAllocatorDumpGuid& source,
217                         const std::string& target_node_name);
218 
219   // Removes all the MemoryAllocatorDump(s) contained in this instance. This
220   // ProcessMemoryDump can be safely reused as if it was new once this returns.
221   void Clear();
222 
223   // Merges all MemoryAllocatorDump(s) contained in |other| inside this
224   // ProcessMemoryDump, transferring their ownership to this instance.
225   // |other| will be an empty ProcessMemoryDump after this method returns.
226   // This is to allow dump providers to pre-populate ProcessMemoryDump instances
227   // and later move their contents into the ProcessMemoryDump passed as argument
228   // of the MemoryDumpProvider::OnMemoryDump(ProcessMemoryDump*) callback.
229   void TakeAllDumpsFrom(ProcessMemoryDump* other);
230 
231   // Populate the traced value with information about the memory allocator
232   // dumps.
233   void SerializeAllocatorDumpsInto(TracedValue* value) const;
234 
235   void SerializeAllocatorDumpsInto(
236       perfetto::protos::pbzero::MemoryTrackerSnapshot* memory_snapshot,
237       const base::ProcessId pid) const;
238 
dump_args()239   const MemoryDumpArgs& dump_args() const { return dump_args_; }
240 
241  private:
242   FRIEND_TEST_ALL_PREFIXES(ProcessMemoryDumpTest, BackgroundModeTest);
243   FRIEND_TEST_ALL_PREFIXES(ProcessMemoryDumpTest, SharedMemoryOwnershipTest);
244   FRIEND_TEST_ALL_PREFIXES(ProcessMemoryDumpTest, GuidsTest);
245 
246   MemoryAllocatorDump* AddAllocatorDumpInternal(
247       std::unique_ptr<MemoryAllocatorDump> mad);
248 
249   // A per-process token, valid throughout all the lifetime of the current
250   // process, used to disambiguate dumps with the same name generated in
251   // different processes.
process_token()252   const UnguessableToken& process_token() const { return process_token_; }
set_process_token_for_testing(UnguessableToken token)253   void set_process_token_for_testing(UnguessableToken token) {
254     process_token_ = token;
255   }
256 
257   // Returns the Guid of the dump for the given |absolute_name| for
258   // for the given process' token. |process_token| is used to disambiguate GUIDs
259   // derived from the same name under different processes.
260   MemoryAllocatorDumpGuid GetDumpId(const std::string& absolute_name);
261 
262   void CreateSharedMemoryOwnershipEdgeInternal(
263       const MemoryAllocatorDumpGuid& client_local_dump_guid,
264       const UnguessableToken& shared_memory_guid,
265       int importance,
266       bool is_weak);
267 
268   MemoryAllocatorDump* GetBlackHoleMad();
269 
270   UnguessableToken process_token_;
271   AllocatorDumpsMap allocator_dumps_;
272 
273   // Keeps track of relationships between MemoryAllocatorDump(s).
274   AllocatorDumpEdgesMap allocator_dumps_edges_;
275 
276   // Level of detail of the current dump.
277   MemoryDumpArgs dump_args_;
278 
279   // This allocator dump is returned when an invalid dump is created in
280   // background mode. The attributes of the dump are ignored and not added to
281   // the trace.
282   std::unique_ptr<MemoryAllocatorDump> black_hole_mad_;
283 
284   // When set to true, the DCHECK(s) for invalid dump creations on the
285   // background mode are disabled for testing.
286   static bool is_black_hole_non_fatal_for_testing_;
287 
288   DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDump);
289 };
290 
291 }  // namespace trace_event
292 }  // namespace base
293 
294 #endif  // BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
295