ssid | 0738685 | 2015-04-14 15:32:37 | [diff] [blame] | 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 |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "base/trace_event/malloc_dump_provider.h" |
| 6 | |
avi | bd1ed05 | 2015-12-24 04:03:44 | [diff] [blame] | 7 | #include <stddef.h> |
| 8 | |
| 9 | #include "base/allocator/allocator_extension.h" |
primiano | fd907216 | 2016-03-25 02:13:28 | [diff] [blame] | 10 | #include "base/allocator/allocator_shim.h" |
| 11 | #include "base/allocator/features.h" |
siggi | ba33ec0 | 2016-08-26 16:13:07 | [diff] [blame] | 12 | #include "base/debug/profiler.h" |
primiano | fd907216 | 2016-03-25 02:13:28 | [diff] [blame] | 13 | #include "base/trace_event/heap_profiler_allocation_context.h" |
| 14 | #include "base/trace_event/heap_profiler_allocation_context_tracker.h" |
| 15 | #include "base/trace_event/heap_profiler_allocation_register.h" |
| 16 | #include "base/trace_event/heap_profiler_heap_dump_writer.h" |
avi | bd1ed05 | 2015-12-24 04:03:44 | [diff] [blame] | 17 | #include "base/trace_event/process_memory_dump.h" |
primiano | fd907216 | 2016-03-25 02:13:28 | [diff] [blame] | 18 | #include "base/trace_event/trace_event_argument.h" |
avi | bd1ed05 | 2015-12-24 04:03:44 | [diff] [blame] | 19 | #include "build/build_config.h" |
| 20 | |
ssid | 3aa02fe | 2015-11-07 16:15:07 | [diff] [blame] | 21 | #if defined(OS_MACOSX) |
| 22 | #include <malloc/malloc.h> |
| 23 | #else |
ssid | 0738685 | 2015-04-14 15:32:37 | [diff] [blame] | 24 | #include <malloc.h> |
ssid | 3aa02fe | 2015-11-07 16:15:07 | [diff] [blame] | 25 | #endif |
siggi | 7bec59a | 2016-08-25 20:22:26 | [diff] [blame] | 26 | #if defined(OS_WIN) |
| 27 | #include <windows.h> |
| 28 | #endif |
ssid | 0738685 | 2015-04-14 15:32:37 | [diff] [blame] | 29 | |
ssid | 0738685 | 2015-04-14 15:32:37 | [diff] [blame] | 30 | namespace base { |
| 31 | namespace trace_event { |
| 32 | |
primiano | fd907216 | 2016-03-25 02:13:28 | [diff] [blame] | 33 | namespace { |
siggi | 7bec59a | 2016-08-25 20:22:26 | [diff] [blame] | 34 | #if BUILDFLAG(USE_EXPERIMENTAL_ALLOCATOR_SHIM) |
primiano | fd907216 | 2016-03-25 02:13:28 | [diff] [blame] | 35 | |
| 36 | using allocator::AllocatorDispatch; |
| 37 | |
| 38 | void* HookAlloc(const AllocatorDispatch* self, size_t size) { |
| 39 | const AllocatorDispatch* const next = self->next; |
| 40 | void* ptr = next->alloc_function(next, size); |
| 41 | if (ptr) |
| 42 | MallocDumpProvider::GetInstance()->InsertAllocation(ptr, size); |
| 43 | return ptr; |
| 44 | } |
| 45 | |
| 46 | void* HookZeroInitAlloc(const AllocatorDispatch* self, size_t n, size_t size) { |
| 47 | const AllocatorDispatch* const next = self->next; |
| 48 | void* ptr = next->alloc_zero_initialized_function(next, n, size); |
| 49 | if (ptr) |
| 50 | MallocDumpProvider::GetInstance()->InsertAllocation(ptr, n * size); |
| 51 | return ptr; |
| 52 | } |
| 53 | |
| 54 | void* HookllocAligned(const AllocatorDispatch* self, |
| 55 | size_t alignment, |
| 56 | size_t size) { |
| 57 | const AllocatorDispatch* const next = self->next; |
| 58 | void* ptr = next->alloc_aligned_function(next, alignment, size); |
| 59 | if (ptr) |
| 60 | MallocDumpProvider::GetInstance()->InsertAllocation(ptr, size); |
| 61 | return ptr; |
| 62 | } |
| 63 | |
| 64 | void* HookRealloc(const AllocatorDispatch* self, void* address, size_t size) { |
| 65 | const AllocatorDispatch* const next = self->next; |
| 66 | void* ptr = next->realloc_function(next, address, size); |
| 67 | MallocDumpProvider::GetInstance()->RemoveAllocation(address); |
| 68 | if (size > 0) // realloc(size == 0) means free(). |
| 69 | MallocDumpProvider::GetInstance()->InsertAllocation(ptr, size); |
| 70 | return ptr; |
| 71 | } |
| 72 | |
| 73 | void HookFree(const AllocatorDispatch* self, void* address) { |
| 74 | if (address) |
| 75 | MallocDumpProvider::GetInstance()->RemoveAllocation(address); |
| 76 | const AllocatorDispatch* const next = self->next; |
| 77 | next->free_function(next, address); |
| 78 | } |
| 79 | |
siggi | 46e1b07 | 2016-09-09 16:43:31 | [diff] [blame^] | 80 | size_t HookGetSizeEstimate(const AllocatorDispatch* self, void* address) { |
| 81 | const AllocatorDispatch* const next = self->next; |
| 82 | return next->get_size_estimate_function(next, address); |
| 83 | } |
| 84 | |
primiano | fd907216 | 2016-03-25 02:13:28 | [diff] [blame] | 85 | AllocatorDispatch g_allocator_hooks = { |
siggi | 46e1b07 | 2016-09-09 16:43:31 | [diff] [blame^] | 86 | &HookAlloc, /* alloc_function */ |
| 87 | &HookZeroInitAlloc, /* alloc_zero_initialized_function */ |
| 88 | &HookllocAligned, /* alloc_aligned_function */ |
| 89 | &HookRealloc, /* realloc_function */ |
| 90 | &HookFree, /* free_function */ |
| 91 | &HookGetSizeEstimate, /* get_size_estimate_function */ |
| 92 | nullptr, /* next */ |
primiano | fd907216 | 2016-03-25 02:13:28 | [diff] [blame] | 93 | }; |
primiano | fd907216 | 2016-03-25 02:13:28 | [diff] [blame] | 94 | #endif // BUILDFLAG(USE_EXPERIMENTAL_ALLOCATOR_SHIM) |
| 95 | |
siggi | 7bec59a | 2016-08-25 20:22:26 | [diff] [blame] | 96 | #if defined(OS_WIN) |
| 97 | // A structure containing some information about a given heap. |
| 98 | struct WinHeapInfo { |
| 99 | HANDLE heap_id; |
| 100 | size_t committed_size; |
| 101 | size_t uncommitted_size; |
| 102 | size_t allocated_size; |
| 103 | size_t block_count; |
| 104 | }; |
| 105 | |
| 106 | bool GetHeapInformation(WinHeapInfo* heap_info, |
| 107 | const std::set<void*>& block_to_skip) { |
| 108 | CHECK(::HeapLock(heap_info->heap_id) == TRUE); |
| 109 | PROCESS_HEAP_ENTRY heap_entry; |
| 110 | heap_entry.lpData = nullptr; |
| 111 | // Walk over all the entries in this heap. |
| 112 | while (::HeapWalk(heap_info->heap_id, &heap_entry) != FALSE) { |
| 113 | if (block_to_skip.count(heap_entry.lpData) == 1) |
| 114 | continue; |
| 115 | if ((heap_entry.wFlags & PROCESS_HEAP_ENTRY_BUSY) != 0) { |
| 116 | heap_info->allocated_size += heap_entry.cbData; |
| 117 | heap_info->block_count++; |
| 118 | } else if ((heap_entry.wFlags & PROCESS_HEAP_REGION) != 0) { |
| 119 | heap_info->committed_size += heap_entry.Region.dwCommittedSize; |
| 120 | heap_info->uncommitted_size += heap_entry.Region.dwUnCommittedSize; |
| 121 | } |
| 122 | } |
| 123 | CHECK(::HeapUnlock(heap_info->heap_id) == TRUE); |
| 124 | return true; |
| 125 | } |
| 126 | |
| 127 | void WinHeapMemoryDumpImpl(WinHeapInfo* all_heap_info) { |
| 128 | // This method might be flaky for 2 reasons: |
| 129 | // - GetProcessHeaps is racy by design. It returns a snapshot of the |
| 130 | // available heaps, but there's no guarantee that that snapshot remains |
| 131 | // valid. If a heap disappears between GetProcessHeaps() and HeapWalk() |
| 132 | // then chaos should be assumed. This flakyness is acceptable for tracing. |
| 133 | // - The MSDN page for HeapLock says: "If the HeapLock function is called on |
| 134 | // a heap created with the HEAP_NO_SERIALIZATION flag, the results are |
| 135 | // undefined." |
| 136 | // - Note that multiple heaps occur on Windows primarily because system and |
| 137 | // 3rd party DLLs will each create their own private heap. It's possible to |
| 138 | // retrieve the heap the CRT allocates from and report specifically on that |
| 139 | // heap. It's interesting to report all heaps, as e.g. loading or invoking |
| 140 | // on a Windows API may consume memory from a private heap. |
| 141 | #if defined(SYZYASAN) |
| 142 | if (base::debug::IsBinaryInstrumented()) |
| 143 | return; |
| 144 | #endif |
| 145 | |
| 146 | // Retrieves the number of heaps in the current process. |
| 147 | DWORD number_of_heaps = ::GetProcessHeaps(0, NULL); |
| 148 | |
| 149 | // Try to retrieve a handle to all the heaps owned by this process. Returns |
| 150 | // false if the number of heaps has changed. |
| 151 | // |
| 152 | // This is inherently racy as is, but it's not something that we observe a lot |
| 153 | // in Chrome, the heaps tend to be created at startup only. |
| 154 | std::unique_ptr<HANDLE[]> all_heaps(new HANDLE[number_of_heaps]); |
| 155 | if (::GetProcessHeaps(number_of_heaps, all_heaps.get()) != number_of_heaps) |
| 156 | return; |
| 157 | |
| 158 | // Skip the pointer to the heap array to avoid accounting the memory used by |
| 159 | // this dump provider. |
| 160 | std::set<void*> block_to_skip; |
| 161 | block_to_skip.insert(all_heaps.get()); |
| 162 | |
| 163 | // Retrieves some metrics about each heap. |
| 164 | for (size_t i = 0; i < number_of_heaps; ++i) { |
| 165 | WinHeapInfo heap_info = {0}; |
| 166 | heap_info.heap_id = all_heaps[i]; |
| 167 | GetHeapInformation(&heap_info, block_to_skip); |
| 168 | |
| 169 | all_heap_info->allocated_size += heap_info.allocated_size; |
| 170 | all_heap_info->committed_size += heap_info.committed_size; |
| 171 | all_heap_info->uncommitted_size += heap_info.uncommitted_size; |
| 172 | all_heap_info->block_count += heap_info.block_count; |
| 173 | } |
| 174 | } |
| 175 | #endif // defined(OS_WIN) |
| 176 | } // namespace |
| 177 | |
ssid | 0738685 | 2015-04-14 15:32:37 | [diff] [blame] | 178 | // static |
primiano | fadec05e | 2015-06-03 16:57:32 | [diff] [blame] | 179 | const char MallocDumpProvider::kAllocatedObjects[] = "malloc/allocated_objects"; |
| 180 | |
| 181 | // static |
ssid | 0738685 | 2015-04-14 15:32:37 | [diff] [blame] | 182 | MallocDumpProvider* MallocDumpProvider::GetInstance() { |
| 183 | return Singleton<MallocDumpProvider, |
| 184 | LeakySingletonTraits<MallocDumpProvider>>::get(); |
| 185 | } |
| 186 | |
primiano | fd907216 | 2016-03-25 02:13:28 | [diff] [blame] | 187 | MallocDumpProvider::MallocDumpProvider() |
| 188 | : heap_profiler_enabled_(false), tid_dumping_heap_(kInvalidThreadId) {} |
ssid | 0738685 | 2015-04-14 15:32:37 | [diff] [blame] | 189 | |
ssid | 3aa02fe | 2015-11-07 16:15:07 | [diff] [blame] | 190 | MallocDumpProvider::~MallocDumpProvider() {} |
ssid | 0738685 | 2015-04-14 15:32:37 | [diff] [blame] | 191 | |
| 192 | // Called at trace dump point time. Creates a snapshot the memory counters for |
| 193 | // the current process. |
ssid | 90694aeec | 2015-08-06 13:01:30 | [diff] [blame] | 194 | bool MallocDumpProvider::OnMemoryDump(const MemoryDumpArgs& args, |
| 195 | ProcessMemoryDump* pmd) { |
ssid | 0943409 | 2015-10-26 23:05:04 | [diff] [blame] | 196 | size_t total_virtual_size = 0; |
| 197 | size_t resident_size = 0; |
| 198 | size_t allocated_objects_size = 0; |
siggi | 7bec59a | 2016-08-25 20:22:26 | [diff] [blame] | 199 | size_t allocated_objects_count = 0; |
ssid | 86f78c1 | 2015-12-21 11:45:32 | [diff] [blame] | 200 | #if defined(USE_TCMALLOC) |
primiano | dda6c27 | 2015-12-07 16:51:04 | [diff] [blame] | 201 | bool res = |
| 202 | allocator::GetNumericProperty("generic.heap_size", &total_virtual_size); |
| 203 | DCHECK(res); |
| 204 | res = allocator::GetNumericProperty("generic.total_physical_bytes", |
| 205 | &resident_size); |
| 206 | DCHECK(res); |
| 207 | res = allocator::GetNumericProperty("generic.current_allocated_bytes", |
| 208 | &allocated_objects_size); |
| 209 | DCHECK(res); |
ssid | 86f78c1 | 2015-12-21 11:45:32 | [diff] [blame] | 210 | #elif defined(OS_MACOSX) || defined(OS_IOS) |
| 211 | malloc_statistics_t stats = {0}; |
| 212 | malloc_zone_statistics(nullptr, &stats); |
| 213 | total_virtual_size = stats.size_allocated; |
| 214 | allocated_objects_size = stats.size_in_use; |
| 215 | |
| 216 | // 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 |
| 218 | // region. In each allocation region the allocations are rounded off to a |
| 219 | // fixed quantum, so the excess region will not be resident. |
| 220 | // See crrev.com/1531463004 for detailed explanation. |
| 221 | resident_size = stats.max_size_in_use; |
siggi | 7bec59a | 2016-08-25 20:22:26 | [diff] [blame] | 222 | #elif defined(OS_WIN) |
| 223 | WinHeapInfo all_heap_info = {}; |
| 224 | WinHeapMemoryDumpImpl(&all_heap_info); |
| 225 | total_virtual_size = |
| 226 | all_heap_info.committed_size + all_heap_info.uncommitted_size; |
| 227 | // 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 |
| 229 | // 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. |
| 231 | resident_size = all_heap_info.committed_size; |
| 232 | allocated_objects_size = all_heap_info.allocated_size; |
| 233 | allocated_objects_count = all_heap_info.block_count; |
ssid | 3aa02fe | 2015-11-07 16:15:07 | [diff] [blame] | 234 | #else |
primiano | dda6c27 | 2015-12-07 16:51:04 | [diff] [blame] | 235 | struct mallinfo info = mallinfo(); |
| 236 | DCHECK_GE(info.arena + info.hblkhd, info.uordblks); |
ssid | 0943409 | 2015-10-26 23:05:04 | [diff] [blame] | 237 | |
primiano | dda6c27 | 2015-12-07 16:51:04 | [diff] [blame] | 238 | // 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 |
| 240 | // |arena| + |hblkhd|. For more details see link: http://goo.gl/fMR8lF. |
| 241 | total_virtual_size = info.arena + info.hblkhd; |
| 242 | resident_size = info.uordblks; |
siggi | 7bec59a | 2016-08-25 20:22:26 | [diff] [blame] | 243 | |
| 244 | // Total allocated space is given by |uordblks|. |
primiano | dda6c27 | 2015-12-07 16:51:04 | [diff] [blame] | 245 | allocated_objects_size = info.uordblks; |
ssid | 3aa02fe | 2015-11-07 16:15:07 | [diff] [blame] | 246 | #endif |
ssid | 0943409 | 2015-10-26 23:05:04 | [diff] [blame] | 247 | |
primiano | fadec05e | 2015-06-03 16:57:32 | [diff] [blame] | 248 | MemoryAllocatorDump* outer_dump = pmd->CreateAllocatorDump("malloc"); |
ssid | 0943409 | 2015-10-26 23:05:04 | [diff] [blame] | 249 | outer_dump->AddScalar("virtual_size", MemoryAllocatorDump::kUnitsBytes, |
| 250 | total_virtual_size); |
| 251 | outer_dump->AddScalar(MemoryAllocatorDump::kNameSize, |
| 252 | MemoryAllocatorDump::kUnitsBytes, resident_size); |
ssid | 0738685 | 2015-04-14 15:32:37 | [diff] [blame] | 253 | |
primiano | fadec05e | 2015-06-03 16:57:32 | [diff] [blame] | 254 | MemoryAllocatorDump* inner_dump = pmd->CreateAllocatorDump(kAllocatedObjects); |
| 255 | inner_dump->AddScalar(MemoryAllocatorDump::kNameSize, |
ssid | 0943409 | 2015-10-26 23:05:04 | [diff] [blame] | 256 | MemoryAllocatorDump::kUnitsBytes, |
| 257 | allocated_objects_size); |
siggi | 7bec59a | 2016-08-25 20:22:26 | [diff] [blame] | 258 | if (allocated_objects_count != 0) { |
siggi | 52114f27 | 2016-08-31 23:51:30 | [diff] [blame] | 259 | inner_dump->AddScalar(MemoryAllocatorDump::kNameObjectCount, |
siggi | 7bec59a | 2016-08-25 20:22:26 | [diff] [blame] | 260 | MemoryAllocatorDump::kUnitsObjects, |
| 261 | allocated_objects_count); |
| 262 | } |
ssid | 0738685 | 2015-04-14 15:32:37 | [diff] [blame] | 263 | |
siggi | 52114f27 | 2016-08-31 23:51:30 | [diff] [blame] | 264 | if (resident_size > allocated_objects_size) { |
ssid | 86f78c1 | 2015-12-21 11:45:32 | [diff] [blame] | 265 | // 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 |
| 267 | // fragmentation and metadata. |
| 268 | MemoryAllocatorDump* other_dump = |
| 269 | pmd->CreateAllocatorDump("malloc/metadata_fragmentation_caches"); |
| 270 | other_dump->AddScalar(MemoryAllocatorDump::kNameSize, |
| 271 | MemoryAllocatorDump::kUnitsBytes, |
| 272 | resident_size - allocated_objects_size); |
| 273 | } |
| 274 | |
primiano | fd907216 | 2016-03-25 02:13:28 | [diff] [blame] | 275 | // Heap profiler dumps. |
| 276 | if (!heap_profiler_enabled_) |
| 277 | return true; |
| 278 | |
| 279 | // 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. |
| 281 | // However, when enabled, the overhead of the heap profiler should be always |
| 282 | // reported to avoid oscillations of the malloc total in LIGHT dumps. |
| 283 | |
| 284 | tid_dumping_heap_ = PlatformThread::CurrentId(); |
| 285 | // At this point the Insert/RemoveAllocation hooks will ignore this thread. |
| 286 | // Enclosing all the temporariy data structures in a scope, so that the heap |
| 287 | // profiler does not see unabalanced malloc/free calls from these containers. |
| 288 | { |
| 289 | TraceEventMemoryOverhead overhead; |
ssid | 1eedc59 | 2016-04-15 01:56:44 | [diff] [blame] | 290 | hash_map<AllocationContext, AllocationMetrics> metrics_by_context; |
primiano | fd907216 | 2016-03-25 02:13:28 | [diff] [blame] | 291 | { |
| 292 | AutoLock lock(allocation_register_lock_); |
| 293 | if (allocation_register_) { |
| 294 | if (args.level_of_detail == MemoryDumpLevelOfDetail::DETAILED) { |
ssid | 1eedc59 | 2016-04-15 01:56:44 | [diff] [blame] | 295 | for (const auto& alloc_size : *allocation_register_) { |
| 296 | AllocationMetrics& metrics = metrics_by_context[alloc_size.context]; |
| 297 | metrics.size += alloc_size.size; |
| 298 | metrics.count++; |
| 299 | } |
primiano | fd907216 | 2016-03-25 02:13:28 | [diff] [blame] | 300 | } |
| 301 | allocation_register_->EstimateTraceMemoryOverhead(&overhead); |
| 302 | } |
| 303 | } // lock(allocation_register_lock_) |
bashi | b873c0d4 | 2016-05-12 05:41:04 | [diff] [blame] | 304 | pmd->DumpHeapUsage(metrics_by_context, overhead, "malloc"); |
primiano | fd907216 | 2016-03-25 02:13:28 | [diff] [blame] | 305 | } |
| 306 | tid_dumping_heap_ = kInvalidThreadId; |
| 307 | |
ssid | 0738685 | 2015-04-14 15:32:37 | [diff] [blame] | 308 | return true; |
| 309 | } |
| 310 | |
primiano | fd907216 | 2016-03-25 02:13:28 | [diff] [blame] | 311 | void MallocDumpProvider::OnHeapProfilingEnabled(bool enabled) { |
| 312 | #if BUILDFLAG(USE_EXPERIMENTAL_ALLOCATOR_SHIM) |
| 313 | if (enabled) { |
| 314 | { |
| 315 | AutoLock lock(allocation_register_lock_); |
| 316 | allocation_register_.reset(new AllocationRegister()); |
| 317 | } |
| 318 | allocator::InsertAllocatorDispatch(&g_allocator_hooks); |
| 319 | } else { |
| 320 | AutoLock lock(allocation_register_lock_); |
| 321 | allocation_register_.reset(); |
| 322 | // Insert/RemoveAllocation below will no-op if the register is torn down. |
| 323 | // Once disabled, heap profiling will not re-enabled anymore for the |
| 324 | // lifetime of the process. |
| 325 | } |
| 326 | #endif |
| 327 | heap_profiler_enabled_ = enabled; |
| 328 | } |
| 329 | |
| 330 | void MallocDumpProvider::InsertAllocation(void* address, size_t size) { |
| 331 | // CurrentId() can be a slow operation (crbug.com/497226). This apparently |
| 332 | // redundant condition short circuits the CurrentID() calls when unnecessary. |
| 333 | if (tid_dumping_heap_ != kInvalidThreadId && |
| 334 | tid_dumping_heap_ == PlatformThread::CurrentId()) |
| 335 | return; |
| 336 | |
| 337 | // AllocationContextTracker will return nullptr when called re-reentrantly. |
| 338 | // This is the case of GetInstanceForCurrentThread() being called for the |
| 339 | // first time, which causes a new() inside the tracker which re-enters the |
| 340 | // heap profiler, in which case we just want to early out. |
vmpstr | 5170bf9 | 2016-06-29 02:15:58 | [diff] [blame] | 341 | auto* tracker = AllocationContextTracker::GetInstanceForCurrentThread(); |
primiano | fd907216 | 2016-03-25 02:13:28 | [diff] [blame] | 342 | if (!tracker) |
| 343 | return; |
| 344 | AllocationContext context = tracker->GetContextSnapshot(); |
| 345 | |
| 346 | AutoLock lock(allocation_register_lock_); |
| 347 | if (!allocation_register_) |
| 348 | return; |
| 349 | |
| 350 | allocation_register_->Insert(address, size, context); |
| 351 | } |
| 352 | |
| 353 | void MallocDumpProvider::RemoveAllocation(void* address) { |
| 354 | // No re-entrancy is expected here as none of the calls below should |
| 355 | // cause a free()-s (|allocation_register_| does its own heap management). |
| 356 | if (tid_dumping_heap_ != kInvalidThreadId && |
| 357 | tid_dumping_heap_ == PlatformThread::CurrentId()) |
| 358 | return; |
| 359 | AutoLock lock(allocation_register_lock_); |
| 360 | if (!allocation_register_) |
| 361 | return; |
| 362 | allocation_register_->Remove(address); |
| 363 | } |
| 364 | |
ssid | 0738685 | 2015-04-14 15:32:37 | [diff] [blame] | 365 | } // namespace trace_event |
| 366 | } // namespace base |