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/memory/shared_memory.h" 8 #include "base/strings/stringprintf.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 SharedMemoryTracker::Usage::Usage() = default; 15 16 SharedMemoryTracker::Usage::Usage(const Usage& rhs) = default; 17 18 SharedMemoryTracker::Usage::~Usage() = default; 19 20 // static 21 SharedMemoryTracker* SharedMemoryTracker::GetInstance() { 22 static SharedMemoryTracker* instance = new SharedMemoryTracker; 23 return instance; 24 } 25 26 void SharedMemoryTracker::IncrementMemoryUsage( 27 const SharedMemory& shared_memory) { 28 Usage usage; 29 // |shared_memory|'s unique ID must be generated here and it'd be too late at 30 // OnMemoryDump. An ID is generated with a SharedMemoryHandle, but the handle 31 // might already be closed at that time. Now IncrementMemoryUsage is called 32 // just after mmap and the handle must live then. See the discussion at 33 // crbug.com/604726#c30. 34 SharedMemory::UniqueId id; 35 if (!shared_memory.GetUniqueId(&id)) 36 return; 37 usage.unique_id = id; 38 usage.size = shared_memory.mapped_size(); 39 AutoLock hold(usages_lock_); 40 usages_[&shared_memory] = usage; 41 } 42 43 void SharedMemoryTracker::DecrementMemoryUsage( 44 const SharedMemory& shared_memory) { 45 AutoLock hold(usages_lock_); 46 usages_.erase(&shared_memory); 47 } 48 49 bool SharedMemoryTracker::OnMemoryDump(const trace_event::MemoryDumpArgs& args, 50 trace_event::ProcessMemoryDump* pmd) { 51 std::unordered_map<SharedMemory::UniqueId, size_t, SharedMemory::UniqueIdHash> 52 sizes; 53 { 54 AutoLock hold(usages_lock_); 55 for (const auto& usage : usages_) 56 sizes[usage.second.unique_id] += usage.second.size; 57 } 58 for (auto& size : sizes) { 59 const SharedMemory::UniqueId& id = size.first; 60 std::string dump_name = StringPrintf("%s/%lld.%lld", "shared_memory", 61 static_cast<long long>(id.first), 62 static_cast<long long>(id.second)); 63 auto guid = trace_event::MemoryAllocatorDumpGuid(dump_name); 64 trace_event::MemoryAllocatorDump* local_dump = 65 pmd->CreateAllocatorDump(dump_name); 66 // TODO(hajimehoshi): The size is not resident size but virtual size so far. 67 // Fix this to record resident size. 68 local_dump->AddScalar(trace_event::MemoryAllocatorDump::kNameSize, 69 trace_event::MemoryAllocatorDump::kUnitsBytes, 70 size.second); 71 trace_event::MemoryAllocatorDump* global_dump = 72 pmd->CreateSharedGlobalAllocatorDump(guid); 73 global_dump->AddScalar(trace_event::MemoryAllocatorDump::kNameSize, 74 trace_event::MemoryAllocatorDump::kUnitsBytes, 75 size.second); 76 // TOOD(hajimehoshi): Detect which the shared memory comes from browser, 77 // renderer or GPU process. 78 // TODO(hajimehoshi): Shared memory reported by GPU and discardable is 79 // currently double-counted. Add ownership edges to avoid this. 80 pmd->AddOwnershipEdge(local_dump->guid(), global_dump->guid()); 81 } 82 return true; 83 } 84 85 SharedMemoryTracker::SharedMemoryTracker() { 86 trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( 87 this, "SharedMemoryTracker", nullptr); 88 } 89 90 SharedMemoryTracker::~SharedMemoryTracker() = default; 91 92 } // namespace 93