| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/trace_event/malloc_dump_provider.h" | 5 #include "base/trace_event/malloc_dump_provider.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include "base/allocator/allocator_extension.h" | 9 #include "base/allocator/allocator_extension.h" |
| 10 #include "base/allocator/allocator_shim.h" | 10 #include "base/allocator/allocator_shim.h" |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 182 MallocDumpProvider* MallocDumpProvider::GetInstance() { | 182 MallocDumpProvider* MallocDumpProvider::GetInstance() { |
| 183 return Singleton<MallocDumpProvider, | 183 return Singleton<MallocDumpProvider, |
| 184 LeakySingletonTraits<MallocDumpProvider>>::get(); | 184 LeakySingletonTraits<MallocDumpProvider>>::get(); |
| 185 } | 185 } |
| 186 | 186 |
| 187 MallocDumpProvider::MallocDumpProvider() | 187 MallocDumpProvider::MallocDumpProvider() |
| 188 : heap_profiler_enabled_(false), tid_dumping_heap_(kInvalidThreadId) {} | 188 : heap_profiler_enabled_(false), tid_dumping_heap_(kInvalidThreadId) {} |
| 189 | 189 |
| 190 MallocDumpProvider::~MallocDumpProvider() {} | 190 MallocDumpProvider::~MallocDumpProvider() {} |
| 191 | 191 |
| 192 // Called at trace dump point time. Creates a snapshot the memory counters for | 192 MallocStatistics MallocDumpProvider::GetStatistics() { |
| 193 // the current process. | 193 MallocStatistics stats; |
| 194 bool MallocDumpProvider::OnMemoryDump(const MemoryDumpArgs& args, | 194 |
| 195 ProcessMemoryDump* pmd) { | |
| 196 size_t total_virtual_size = 0; | |
| 197 size_t resident_size = 0; | |
| 198 size_t allocated_objects_size = 0; | |
| 199 size_t allocated_objects_count = 0; | |
| 200 #if defined(USE_TCMALLOC) | 195 #if defined(USE_TCMALLOC) |
| 201 bool res = | 196 bool res = allocator::GetNumericProperty("generic.heap_size", |
| 202 allocator::GetNumericProperty("generic.heap_size", &total_virtual_size); | 197 &stats.total_virtual_size); |
| 203 DCHECK(res); | 198 DCHECK(res); |
| 204 res = allocator::GetNumericProperty("generic.total_physical_bytes", | 199 res = allocator::GetNumericProperty("generic.total_physical_bytes", |
| 205 &resident_size); | 200 &stats.resident_size); |
| 206 DCHECK(res); | 201 DCHECK(res); |
| 207 res = allocator::GetNumericProperty("generic.current_allocated_bytes", | 202 res = allocator::GetNumericProperty("generic.current_allocated_bytes", |
| 208 &allocated_objects_size); | 203 &stats.allocated_objects_size); |
| 209 DCHECK(res); | 204 DCHECK(res); |
| 210 #elif defined(OS_MACOSX) || defined(OS_IOS) | 205 #elif defined(OS_MACOSX) || defined(OS_IOS) |
| 211 malloc_statistics_t stats = {0}; | 206 malloc_statistics_t stats = {0}; |
| 212 malloc_zone_statistics(nullptr, &stats); | 207 malloc_zone_statistics(nullptr, &stats); |
| 213 total_virtual_size = stats.size_allocated; | 208 stats.total_virtual_size = stats.size_allocated; |
| 214 allocated_objects_size = stats.size_in_use; | 209 stats.allocated_objects_size = stats.size_in_use; |
| 215 | 210 |
| 216 // The resident size is approximated to the max size in use, which would count | 211 // The resident size is approximated to the max size in use, which would count |
| 217 // the total size of all regions other than the free bytes at the end of each | 212 // the total size of all regions other than the free bytes at the end of each |
| 218 // region. In each allocation region the allocations are rounded off to a | 213 // region. In each allocation region the allocations are rounded off to a |
| 219 // fixed quantum, so the excess region will not be resident. | 214 // fixed quantum, so the excess region will not be resident. |
| 220 // See crrev.com/1531463004 for detailed explanation. | 215 // See crrev.com/1531463004 for detailed explanation. |
| 221 resident_size = stats.max_size_in_use; | 216 stats.resident_size = stats.max_size_in_use; |
| 222 #elif defined(OS_WIN) | 217 #elif defined(OS_WIN) |
| 223 WinHeapInfo all_heap_info = {}; | 218 WinHeapInfo all_heap_info = {}; |
| 224 WinHeapMemoryDumpImpl(&all_heap_info); | 219 WinHeapMemoryDumpImpl(&all_heap_info); |
| 225 total_virtual_size = | 220 stats.total_virtual_size = |
| 226 all_heap_info.committed_size + all_heap_info.uncommitted_size; | 221 all_heap_info.committed_size + all_heap_info.uncommitted_size; |
| 227 // Resident size is approximated with committed heap size. Note that it is | 222 // Resident size is approximated with committed heap size. Note that it is |
| 228 // possible to do this with better accuracy on windows by intersecting the | 223 // possible to do this with better accuracy on windows by intersecting the |
| 229 // working set with the virtual memory ranges occuipied by the heap. It's not | 224 // working set with the virtual memory ranges occuipied by the heap. It's not |
| 230 // clear that this is worth it, as it's fairly expensive to do. | 225 // clear that this is worth it, as it's fairly expensive to do. |
| 231 resident_size = all_heap_info.committed_size; | 226 stats.resident_size = all_heap_info.committed_size; |
| 232 allocated_objects_size = all_heap_info.allocated_size; | 227 stats.allocated_objects_size = all_heap_info.allocated_size; |
| 233 allocated_objects_count = all_heap_info.block_count; | 228 stats.allocated_objects_count = all_heap_info.block_count; |
| 234 #else | 229 #else |
| 235 struct mallinfo info = mallinfo(); | 230 struct mallinfo info = mallinfo(); |
| 236 DCHECK_GE(info.arena + info.hblkhd, info.uordblks); | 231 DCHECK_GE(info.arena + info.hblkhd, info.uordblks); |
| 237 | 232 |
| 238 // In case of Android's jemalloc |arena| is 0 and the outer pages size is | 233 // In case of Android's jemalloc |arena| is 0 and the outer pages size is |
| 239 // reported by |hblkhd|. In case of dlmalloc the total is given by | 234 // reported by |hblkhd|. In case of dlmalloc the total is given by |
| 240 // |arena| + |hblkhd|. For more details see link: http://goo.gl/fMR8lF. | 235 // |arena| + |hblkhd|. For more details see link: http://goo.gl/fMR8lF. |
| 241 total_virtual_size = info.arena + info.hblkhd; | 236 stats.total_virtual_size = info.arena + info.hblkhd; |
| 242 resident_size = info.uordblks; | 237 stats.resident_size = info.uordblks; |
| 243 | 238 |
| 244 // Total allocated space is given by |uordblks|. | 239 // Total allocated space is given by |uordblks|. |
| 245 allocated_objects_size = info.uordblks; | 240 stats.allocated_objects_size = info.uordblks; |
| 246 #endif | 241 #endif |
| 242 if (stats.resident_size > stats.allocated_objects_size) { |
| 243 // Explicitly specify why is extra memory resident. In tcmalloc it accounts |
| 244 // for free lists and caches. In mac and ios it accounts for the |
| 245 // fragmentation and metadata. |
| 246 stats.allocated_objects_size = |
| 247 stats.resident_size - stats.allocated_objects_size; |
| 248 } |
| 249 return stats; |
| 250 } |
| 251 |
| 252 // Called at trace dump point time. Creates a snapshot the memory counters for |
| 253 // the current process. |
| 254 bool MallocDumpProvider::OnMemoryDump(const MemoryDumpArgs& args, |
| 255 ProcessMemoryDump* pmd) { |
| 256 MallocStatistics stats = GetStatistics(); |
| 247 | 257 |
| 248 MemoryAllocatorDump* outer_dump = pmd->CreateAllocatorDump("malloc"); | 258 MemoryAllocatorDump* outer_dump = pmd->CreateAllocatorDump("malloc"); |
| 249 outer_dump->AddScalar("virtual_size", MemoryAllocatorDump::kUnitsBytes, | 259 outer_dump->AddScalar("virtual_size", MemoryAllocatorDump::kUnitsBytes, |
| 250 total_virtual_size); | 260 stats.total_virtual_size); |
| 251 outer_dump->AddScalar(MemoryAllocatorDump::kNameSize, | 261 outer_dump->AddScalar(MemoryAllocatorDump::kNameSize, |
| 252 MemoryAllocatorDump::kUnitsBytes, resident_size); | 262 MemoryAllocatorDump::kUnitsBytes, stats.resident_size); |
| 253 | 263 |
| 254 MemoryAllocatorDump* inner_dump = pmd->CreateAllocatorDump(kAllocatedObjects); | 264 MemoryAllocatorDump* inner_dump = pmd->CreateAllocatorDump(kAllocatedObjects); |
| 255 inner_dump->AddScalar(MemoryAllocatorDump::kNameSize, | 265 inner_dump->AddScalar(MemoryAllocatorDump::kNameSize, |
| 256 MemoryAllocatorDump::kUnitsBytes, | 266 MemoryAllocatorDump::kUnitsBytes, |
| 257 allocated_objects_size); | 267 stats.allocated_objects_size); |
| 258 if (allocated_objects_count != 0) { | 268 if (stats.allocated_objects_count != 0) { |
| 259 inner_dump->AddScalar(MemoryAllocatorDump::kNameObjectCount, | 269 inner_dump->AddScalar(MemoryAllocatorDump::kNameObjectCount, |
| 260 MemoryAllocatorDump::kUnitsObjects, | 270 MemoryAllocatorDump::kUnitsObjects, |
| 261 allocated_objects_count); | 271 stats.allocated_objects_count); |
| 262 } | 272 } |
| 263 | 273 |
| 264 if (resident_size > allocated_objects_size) { | 274 if (stats.metadata_fragmentation_caches > 0) { |
| 265 // Explicitly specify why is extra memory resident. In tcmalloc it accounts | 275 // Explicitly specify why is extra memory resident. In tcmalloc it accounts |
| 266 // for free lists and caches. In mac and ios it accounts for the | 276 // for free lists and caches. In mac and ios it accounts for the |
| 267 // fragmentation and metadata. | 277 // fragmentation and metadata. |
| 268 MemoryAllocatorDump* other_dump = | 278 MemoryAllocatorDump* other_dump = |
| 269 pmd->CreateAllocatorDump("malloc/metadata_fragmentation_caches"); | 279 pmd->CreateAllocatorDump("malloc/metadata_fragmentation_caches"); |
| 270 other_dump->AddScalar(MemoryAllocatorDump::kNameSize, | 280 other_dump->AddScalar(MemoryAllocatorDump::kNameSize, |
| 271 MemoryAllocatorDump::kUnitsBytes, | 281 MemoryAllocatorDump::kUnitsBytes, |
| 272 resident_size - allocated_objects_size); | 282 stats.metadata_fragmentation_caches); |
| 273 } | 283 } |
| 274 | 284 |
| 275 // Heap profiler dumps. | 285 // Heap profiler dumps. |
| 276 if (!heap_profiler_enabled_) | 286 if (!heap_profiler_enabled_) |
| 277 return true; | 287 return true; |
| 278 | 288 |
| 279 // The dumps of the heap profiler should be created only when heap profiling | 289 // The dumps of the heap profiler should be created only when heap profiling |
| 280 // was enabled (--enable-heap-profiling) AND a DETAILED dump is requested. | 290 // was enabled (--enable-heap-profiling) AND a DETAILED dump is requested. |
| 281 // However, when enabled, the overhead of the heap profiler should be always | 291 // However, when enabled, the overhead of the heap profiler should be always |
| 282 // reported to avoid oscillations of the malloc total in LIGHT dumps. | 292 // reported to avoid oscillations of the malloc total in LIGHT dumps. |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 tid_dumping_heap_ == PlatformThread::CurrentId()) | 367 tid_dumping_heap_ == PlatformThread::CurrentId()) |
| 358 return; | 368 return; |
| 359 AutoLock lock(allocation_register_lock_); | 369 AutoLock lock(allocation_register_lock_); |
| 360 if (!allocation_register_) | 370 if (!allocation_register_) |
| 361 return; | 371 return; |
| 362 allocation_register_->Remove(address); | 372 allocation_register_->Remove(address); |
| 363 } | 373 } |
| 364 | 374 |
| 365 } // namespace trace_event | 375 } // namespace trace_event |
| 366 } // namespace base | 376 } // namespace base |
| OLD | NEW |