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