1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260
  261
  262
  263
  264
  265
  266
  267
  268
  269
  270
  271
  272
  273
  274
  275
  276
  277
  278
  279
  280
  281
  282
  283
  284
  285
  286
  287
  288
  289
  290
  291
  292
  293
  294

base / trace_event / process_memory_dump.h [blame]

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
#define BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_

#include <stddef.h>

#include <map>
#include <optional>
#include <unordered_map>
#include <vector>

#include "base/base_export.h"
#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
#include "base/trace_event/heap_profiler_allocation_context.h"
#include "base/trace_event/memory_allocator_dump.h"
#include "base/trace_event/memory_allocator_dump_guid.h"
#include "base/trace_event/memory_dump_request_args.h"
#include "build/build_config.h"

// Define COUNT_RESIDENT_BYTES_SUPPORTED if platform supports counting of the
// resident memory.
#if !BUILDFLAG(IS_NACL)
#define COUNT_RESIDENT_BYTES_SUPPORTED
#endif

namespace perfetto {
namespace protos {
namespace pbzero {
class MemoryTrackerSnapshot;
}
}  // namespace protos
}  // namespace perfetto

namespace base {

class UnguessableToken;

namespace trace_event {

class TracedValue;

// ProcessMemoryDump is as a strongly typed container which holds the dumps
// produced by the MemoryDumpProvider(s) for a specific process.
class BASE_EXPORT ProcessMemoryDump {
 public:
  struct BASE_EXPORT MemoryAllocatorDumpEdge {
    friend bool operator==(const MemoryAllocatorDumpEdge&,
                           const MemoryAllocatorDumpEdge&) = default;

    MemoryAllocatorDumpGuid source;
    MemoryAllocatorDumpGuid target;
    int importance = 0;
    bool overridable = false;
  };

  // Maps allocator dumps absolute names (allocator_name/heap/subheap) to
  // MemoryAllocatorDump instances.
  using AllocatorDumpsMap =
      std::map<std::string, std::unique_ptr<MemoryAllocatorDump>>;

  // Stores allocator dump edges indexed by source allocator dump GUID.
  using AllocatorDumpEdgesMap =
      std::map<MemoryAllocatorDumpGuid, MemoryAllocatorDumpEdge>;

#if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
  // Returns the number of bytes in a kernel memory page. Some platforms may
  // have a different value for kernel page sizes from user page sizes. It is
  // important to use kernel memory page sizes for resident bytes calculation.
  // In most cases, the two are the same.
  static size_t GetSystemPageSize();

  // Returns the total bytes resident for a virtual address range, with given
  // |start_address| and |mapped_size|. |mapped_size| is specified in bytes. The
  // value returned is valid only if the given range is currently mmapped by the
  // process. The |start_address| must be page-aligned.
  static std::optional<size_t> CountResidentBytes(void* start_address,
                                                  size_t mapped_size);

  // The same as above, but the given mapped range should belong to the
  // shared_memory's mapped region.
  static std::optional<size_t> CountResidentBytesInSharedMemory(
      void* start_address,
      size_t mapped_size);
#endif

  explicit ProcessMemoryDump(const MemoryDumpArgs& dump_args);
  ProcessMemoryDump(ProcessMemoryDump&&);

  ProcessMemoryDump(const ProcessMemoryDump&) = delete;
  ProcessMemoryDump& operator=(const ProcessMemoryDump&) = delete;

  ~ProcessMemoryDump();

  ProcessMemoryDump& operator=(ProcessMemoryDump&&);

  // Creates a new MemoryAllocatorDump with the given name and returns the
  // empty object back to the caller.
  // Arguments:
  //   absolute_name: a name that uniquely identifies allocator dumps produced
  //       by this provider. It is possible to specify nesting by using a
  //       path-like string (e.g., v8/isolate1/heap1, v8/isolate1/heap2).
  //       Leading or trailing slashes are not allowed.
  //   guid: an optional identifier, unique among all processes within the
  //       scope of a global dump. This is only relevant when using
  //       AddOwnershipEdge() to express memory sharing. If omitted,
  //       it will be automatically generated.
  // ProcessMemoryDump handles the memory ownership of its MemoryAllocatorDumps.
  MemoryAllocatorDump* CreateAllocatorDump(const std::string& absolute_name);
  MemoryAllocatorDump* CreateAllocatorDump(const std::string& absolute_name,
                                           const MemoryAllocatorDumpGuid& guid);

  // Looks up a MemoryAllocatorDump given its allocator and heap names, or
  // nullptr if not found.
  MemoryAllocatorDump* GetAllocatorDump(const std::string& absolute_name) const;

  // Do NOT use this method. All dump providers should use
  // CreateAllocatorDump(). Tries to create a new MemoryAllocatorDump only if it
  // doesn't already exist. Creating multiple dumps with same name using
  // GetOrCreateAllocatorDump() would override the existing scalars in MAD and
  // cause misreporting. This method is used only in rare cases multiple
  // components create allocator dumps with same name and only one of them adds
  // size.
  MemoryAllocatorDump* GetOrCreateAllocatorDump(
      const std::string& absolute_name);

  // Creates a shared MemoryAllocatorDump, to express cross-process sharing.
  // Shared allocator dumps are allowed to have duplicate guids within the
  // global scope, in order to reference the same dump from multiple processes.
  // See the design doc goo.gl/keU6Bf for reference usage patterns.
  MemoryAllocatorDump* CreateSharedGlobalAllocatorDump(
      const MemoryAllocatorDumpGuid& guid);

  // Creates a shared MemoryAllocatorDump as CreateSharedGlobalAllocatorDump,
  // but with a WEAK flag. A weak dump will be discarded unless a non-weak dump
  // is created using CreateSharedGlobalAllocatorDump by at least one process.
  // The WEAK flag does not apply if a non-weak dump with the same GUID already
  // exists or is created later. All owners and children of the discarded dump
  // will also be discarded transitively.
  MemoryAllocatorDump* CreateWeakSharedGlobalAllocatorDump(
      const MemoryAllocatorDumpGuid& guid);

  // Looks up a shared MemoryAllocatorDump given its guid.
  MemoryAllocatorDump* GetSharedGlobalAllocatorDump(
      const MemoryAllocatorDumpGuid& guid) const;

  // Returns the map of the MemoryAllocatorDumps added to this dump.
  const AllocatorDumpsMap& allocator_dumps() const LIFETIME_BOUND {
    return allocator_dumps_;
  }

  AllocatorDumpsMap* mutable_allocator_dumps_for_serialization() const {
    // Mojo takes a const input argument even for move-only types that can be
    // mutate while serializing (like this one). Hence the const_cast.
    return const_cast<AllocatorDumpsMap*>(&allocator_dumps_);
  }
  void SetAllocatorDumpsForSerialization(
      std::vector<std::unique_ptr<MemoryAllocatorDump>>);

  // Only for mojo serialization.
  std::vector<MemoryAllocatorDumpEdge> GetAllEdgesForSerialization() const;
  void SetAllEdgesForSerialization(const std::vector<MemoryAllocatorDumpEdge>&);

  // Adds an ownership relationship between two MemoryAllocatorDump(s) with the
  // semantics: |source| owns |target|, and has the effect of attributing
  // the memory usage of |target| to |source|. |importance| is optional and
  // relevant only for the cases of co-ownership, where it acts as a z-index:
  // the owner with the highest importance will be attributed |target|'s memory.
  // If an edge is present, its importance will not be updated unless
  // |importance| is larger.
  void AddOwnershipEdge(const MemoryAllocatorDumpGuid& source,
                        const MemoryAllocatorDumpGuid& target,
                        int importance);
  void AddOwnershipEdge(const MemoryAllocatorDumpGuid& source,
                        const MemoryAllocatorDumpGuid& target);

  // Adds edges that can be overriden by a later or earlier call to
  // AddOwnershipEdge() with the same source and target with a different
  // |importance| value.
  void AddOverridableOwnershipEdge(const MemoryAllocatorDumpGuid& source,
                                   const MemoryAllocatorDumpGuid& target,
                                   int importance);

  // Creates ownership edges for shared memory. Handles the case of cross
  // process sharing and importance of ownership for the case with and without
  // the shared memory dump provider. This handles both shared memory from both
  // legacy base::SharedMemory as well as current base::SharedMemoryMapping. The
  // weak version creates a weak global dump.
  // |client_local_dump_guid| The guid of the local dump created by the client
  // of base::SharedMemory.
  // |shared_memory_guid| The ID of the shared memory that is assigned globally,
  // used to create global dump edges in the new model.
  // |importance| Importance of the global dump edges to say if the current
  // process owns the memory segment.
  void CreateSharedMemoryOwnershipEdge(
      const MemoryAllocatorDumpGuid& client_local_dump_guid,
      const UnguessableToken& shared_memory_guid,
      int importance);
  void CreateWeakSharedMemoryOwnershipEdge(
      const MemoryAllocatorDumpGuid& client_local_dump_guid,
      const UnguessableToken& shared_memory_guid,
      int importance);

  const AllocatorDumpEdgesMap& allocator_dumps_edges() const LIFETIME_BOUND {
    return allocator_dumps_edges_;
  }

  // Utility method to add a suballocation relationship with the following
  // semantics: |source| is suballocated from |target_node_name|.
  // This creates a child node of |target_node_name| and adds an ownership edge
  // between |source| and the new child node. As a result, the UI will not
  // account the memory of |source| in the target node.
  void AddSuballocation(const MemoryAllocatorDumpGuid& source,
                        const std::string& target_node_name);

  // Removes all the MemoryAllocatorDump(s) contained in this instance. This
  // ProcessMemoryDump can be safely reused as if it was new once this returns.
  void Clear();

  // Merges all MemoryAllocatorDump(s) contained in |other| inside this
  // ProcessMemoryDump, transferring their ownership to this instance.
  // |other| will be an empty ProcessMemoryDump after this method returns.
  // This is to allow dump providers to pre-populate ProcessMemoryDump instances
  // and later move their contents into the ProcessMemoryDump passed as argument
  // of the MemoryDumpProvider::OnMemoryDump(ProcessMemoryDump*) callback.
  void TakeAllDumpsFrom(ProcessMemoryDump* other);

  // Populate the traced value with information about the memory allocator
  // dumps.
  void SerializeAllocatorDumpsInto(TracedValue* value) const;

  void SerializeAllocatorDumpsInto(
      perfetto::protos::pbzero::MemoryTrackerSnapshot* memory_snapshot,
      const base::ProcessId pid) const;

  const MemoryDumpArgs& dump_args() const LIFETIME_BOUND { return dump_args_; }

 private:
  FRIEND_TEST_ALL_PREFIXES(ProcessMemoryDumpTest, BackgroundModeTest);
  FRIEND_TEST_ALL_PREFIXES(ProcessMemoryDumpTest, SharedMemoryOwnershipTest);
  FRIEND_TEST_ALL_PREFIXES(ProcessMemoryDumpTest, GuidsTest);

  MemoryAllocatorDump* AddAllocatorDumpInternal(
      std::unique_ptr<MemoryAllocatorDump> mad);

  // A per-process token, valid throughout all the lifetime of the current
  // process, used to disambiguate dumps with the same name generated in
  // different processes.
  const UnguessableToken& process_token() const LIFETIME_BOUND {
    return process_token_;
  }
  void set_process_token_for_testing(UnguessableToken token) {
    process_token_ = token;
  }

  // Returns the Guid of the dump for the given |absolute_name| for
  // for the given process' token. |process_token| is used to disambiguate GUIDs
  // derived from the same name under different processes.
  MemoryAllocatorDumpGuid GetDumpId(const std::string& absolute_name);

  void CreateSharedMemoryOwnershipEdgeInternal(
      const MemoryAllocatorDumpGuid& client_local_dump_guid,
      const UnguessableToken& shared_memory_guid,
      int importance,
      bool is_weak);

  MemoryAllocatorDump* GetBlackHoleMad(const std::string& absolute_name);

  UnguessableToken process_token_;
  AllocatorDumpsMap allocator_dumps_;

  // Keeps track of relationships between MemoryAllocatorDump(s).
  AllocatorDumpEdgesMap allocator_dumps_edges_;

  // Level of detail of the current dump.
  MemoryDumpArgs dump_args_;

  // This allocator dump is returned when an invalid dump is created in
  // background mode. The attributes of the dump are ignored and not added to
  // the trace.
  std::unique_ptr<MemoryAllocatorDump> black_hole_mad_;

  // When set to true, the DCHECK(s) for invalid dump creations on the
  // background mode are disabled for testing.
  static bool is_black_hole_non_fatal_for_testing_;
};

}  // namespace trace_event
}  // namespace base

#endif  // BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_