• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/memory/shared_memory_tracker.h"
6 
7 #include "base/check.h"
8 #include "base/notreached.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/trace_event/base_tracing.h"
11 #include "base/tracing_buildflags.h"
12 
13 #if BUILDFLAG(ENABLE_BASE_TRACING)
14 #include "base/trace_event/memory_dump_manager.h"  // no-presubmit-check
15 #include "base/trace_event/process_memory_dump.h"  // no-presubmit-check
16 #include "third_party/abseil-cpp/absl/types/optional.h"
17 #endif  // BUILDFLAG(ENABLE_BASE_TRACING)
18 
19 namespace base {
20 
21 const char SharedMemoryTracker::kDumpRootName[] = "shared_memory";
22 
23 // static
GetInstance()24 SharedMemoryTracker* SharedMemoryTracker::GetInstance() {
25   static SharedMemoryTracker* instance = new SharedMemoryTracker;
26   return instance;
27 }
28 
29 // static
GetDumpNameForTracing(const UnguessableToken & id)30 std::string SharedMemoryTracker::GetDumpNameForTracing(
31     const UnguessableToken& id) {
32   DCHECK(!id.is_empty());
33   return std::string(kDumpRootName) + "/" + id.ToString();
34 }
35 
36 // static
37 trace_event::MemoryAllocatorDumpGuid
GetGlobalDumpIdForTracing(const UnguessableToken & id)38 SharedMemoryTracker::GetGlobalDumpIdForTracing(const UnguessableToken& id) {
39   std::string dump_name = GetDumpNameForTracing(id);
40   return trace_event::MemoryAllocatorDumpGuid(dump_name);
41 }
42 
43 const trace_event::MemoryAllocatorDump*
GetOrCreateSharedMemoryDump(const SharedMemoryMapping & shared_memory,trace_event::ProcessMemoryDump * pmd)44 SharedMemoryTracker::GetOrCreateSharedMemoryDump(
45     const SharedMemoryMapping& shared_memory,
46     trace_event::ProcessMemoryDump* pmd) {
47   return GetOrCreateSharedMemoryDumpInternal(shared_memory.raw_memory_ptr(),
48                                              shared_memory.mapped_size(),
49                                              shared_memory.guid(), pmd);
50 }
51 
IncrementMemoryUsage(const SharedMemoryMapping & mapping)52 void SharedMemoryTracker::IncrementMemoryUsage(
53     const SharedMemoryMapping& mapping) {
54   AutoLock hold(usages_lock_);
55   DCHECK(usages_.find(mapping.raw_memory_ptr()) == usages_.end());
56   usages_.emplace(mapping.raw_memory_ptr(),
57                   UsageInfo(mapping.mapped_size(), mapping.guid()));
58 }
59 
DecrementMemoryUsage(const SharedMemoryMapping & mapping)60 void SharedMemoryTracker::DecrementMemoryUsage(
61     const SharedMemoryMapping& mapping) {
62   AutoLock hold(usages_lock_);
63   DCHECK(usages_.find(mapping.raw_memory_ptr()) != usages_.end());
64   usages_.erase(mapping.raw_memory_ptr());
65 }
66 
SharedMemoryTracker()67 SharedMemoryTracker::SharedMemoryTracker() {
68 #if BUILDFLAG(ENABLE_BASE_TRACING)
69   trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
70       this, "SharedMemoryTracker", nullptr);
71 #endif  // BUILDFLAG(ENABLE_BASE_TRACING)
72 }
73 
74 SharedMemoryTracker::~SharedMemoryTracker() = default;
75 
OnMemoryDump(const trace_event::MemoryDumpArgs & args,trace_event::ProcessMemoryDump * pmd)76 bool SharedMemoryTracker::OnMemoryDump(const trace_event::MemoryDumpArgs& args,
77                                        trace_event::ProcessMemoryDump* pmd) {
78   AutoLock hold(usages_lock_);
79   for (const auto& usage : usages_) {
80     const trace_event::MemoryAllocatorDump* dump =
81         GetOrCreateSharedMemoryDumpInternal(
82             usage.first, usage.second.mapped_size, usage.second.mapped_id, pmd);
83     DCHECK(dump);
84   }
85   return true;
86 }
87 
88 // static
89 const trace_event::MemoryAllocatorDump*
GetOrCreateSharedMemoryDumpInternal(void * mapped_memory,size_t mapped_size,const UnguessableToken & mapped_id,trace_event::ProcessMemoryDump * pmd)90 SharedMemoryTracker::GetOrCreateSharedMemoryDumpInternal(
91     void* mapped_memory,
92     size_t mapped_size,
93     const UnguessableToken& mapped_id,
94     trace_event::ProcessMemoryDump* pmd) {
95 #if BUILDFLAG(ENABLE_BASE_TRACING)
96   const std::string dump_name = GetDumpNameForTracing(mapped_id);
97   trace_event::MemoryAllocatorDump* local_dump =
98       pmd->GetAllocatorDump(dump_name);
99   if (local_dump)
100     return local_dump;
101 
102   size_t virtual_size = mapped_size;
103   // If resident size is not available, a virtual size is used as fallback.
104   size_t size = virtual_size;
105 #if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
106   absl::optional<size_t> resident_size =
107       trace_event::ProcessMemoryDump::CountResidentBytesInSharedMemory(
108           mapped_memory, mapped_size);
109   if (resident_size.has_value())
110     size = resident_size.value();
111 #endif
112 
113   local_dump = pmd->CreateAllocatorDump(dump_name);
114   local_dump->AddScalar(trace_event::MemoryAllocatorDump::kNameSize,
115                         trace_event::MemoryAllocatorDump::kUnitsBytes, size);
116   local_dump->AddScalar("virtual_size",
117                         trace_event::MemoryAllocatorDump::kUnitsBytes,
118                         virtual_size);
119   auto global_dump_guid = GetGlobalDumpIdForTracing(mapped_id);
120   trace_event::MemoryAllocatorDump* global_dump =
121       pmd->CreateSharedGlobalAllocatorDump(global_dump_guid);
122   global_dump->AddScalar(trace_event::MemoryAllocatorDump::kNameSize,
123                          trace_event::MemoryAllocatorDump::kUnitsBytes, size);
124 
125   // The edges will be overriden by the clients with correct importance.
126   pmd->AddOverridableOwnershipEdge(local_dump->guid(), global_dump->guid(),
127                                    0 /* importance */);
128   return local_dump;
129 #else   // BUILDFLAG(ENABLE_BASE_TRACING)
130   NOTREACHED();
131   return nullptr;
132 #endif  // BUILDFLAG(ENABLE_BASE_TRACING)
133 }
134 
135 }  // namespace
136