Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2015 The Chromium Authors |
ssid | 0738685 | 2015-04-14 15:32:37 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
danakj | 51d26a4 | 2024-04-25 14:23:56 | [diff] [blame] | 5 | #ifdef UNSAFE_BUFFERS_BUILD |
| 6 | // TODO(crbug.com/40284755): Remove this and spanify to fix the errors. |
| 7 | #pragma allow_unsafe_buffers |
| 8 | #endif |
| 9 | |
ssid | 0738685 | 2015-04-14 15:32:37 | [diff] [blame] | 10 | #include "base/trace_event/malloc_dump_provider.h" |
| 11 | |
avi | bd1ed05 | 2015-12-24 04:03:44 | [diff] [blame] | 12 | #include <stddef.h> |
| 13 | |
brettw | 1ce49f6 | 2017-04-27 19:42:32 | [diff] [blame] | 14 | #include <unordered_map> |
| 15 | |
Scott Violet | 4416579 | 2018-02-22 02:08:08 | [diff] [blame] | 16 | #include "base/allocator/buildflags.h" |
siggi | ba33ec0 | 2016-08-26 16:13:07 | [diff] [blame] | 17 | #include "base/debug/profiler.h" |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 18 | #include "base/format_macros.h" |
Benoit Lize | 6d5fdab5 | 2021-03-02 12:51:41 | [diff] [blame] | 19 | #include "base/metrics/histogram_functions.h" |
Peter Kasting | a0b914dc | 2022-07-14 18:43:19 | [diff] [blame] | 20 | #include "base/numerics/safe_conversions.h" |
Benoit Lize | 59ede6d3 | 2021-03-10 09:16:33 | [diff] [blame] | 21 | #include "base/strings/stringprintf.h" |
avi | bd1ed05 | 2015-12-24 04:03:44 | [diff] [blame] | 22 | #include "base/trace_event/process_memory_dump.h" |
David 'Digit' Turner | 8e6ae28 | 2018-10-26 08:03:51 | [diff] [blame] | 23 | #include "base/trace_event/traced_value.h" |
avi | bd1ed05 | 2015-12-24 04:03:44 | [diff] [blame] | 24 | #include "build/build_config.h" |
Arthur Sonzogni | fd39d61 | 2024-06-26 08:16:23 | [diff] [blame] | 25 | #include "partition_alloc/buildflags.h" |
Etienne Dechamps | 4dacf2b | 2024-12-19 16:31:05 | [diff] [blame] | 26 | |
| 27 | #if PA_BUILDFLAG(USE_PARTITION_ALLOC) |
| 28 | #include "partition_alloc/partition_alloc_config.h" // nogncheck |
| 29 | #include "partition_alloc/partition_bucket_lookup.h" // nogncheck |
| 30 | #endif |
avi | bd1ed05 | 2015-12-24 04:03:44 | [diff] [blame] | 31 | |
Xiaohan Wang | 38e4ebb | 2022-01-19 06:57:43 | [diff] [blame] | 32 | #if BUILDFLAG(IS_APPLE) |
ssid | 3aa02fe | 2015-11-07 16:15:07 | [diff] [blame] | 33 | #include <malloc/malloc.h> |
| 34 | #else |
ssid | 0738685 | 2015-04-14 15:32:37 | [diff] [blame] | 35 | #include <malloc.h> |
ssid | 3aa02fe | 2015-11-07 16:15:07 | [diff] [blame] | 36 | #endif |
Xiaohan Wang | 38e4ebb | 2022-01-19 06:57:43 | [diff] [blame] | 37 | #if BUILDFLAG(IS_WIN) |
siggi | 7bec59a | 2016-08-25 20:22:26 | [diff] [blame] | 38 | #include <windows.h> |
| 39 | #endif |
ssid | 0738685 | 2015-04-14 15:32:37 | [diff] [blame] | 40 | |
Xiaohan Wang | 38e4ebb | 2022-01-19 06:57:43 | [diff] [blame] | 41 | #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) |
Marek Ruszczynski | 219e3eb7 | 2021-06-28 21:23:51 | [diff] [blame] | 42 | #include <features.h> |
| 43 | #endif |
| 44 | |
Arthur Sonzogni | 62e877a | 2024-04-30 16:09:43 | [diff] [blame] | 45 | #if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) |
Yuki Shiino | b94fcd3 | 2024-05-02 10:16:15 | [diff] [blame] | 46 | #include "base/no_destructor.h" |
Yuki Shiino | 985ab91e | 2024-03-14 07:20:46 | [diff] [blame] | 47 | #include "partition_alloc/shim/allocator_shim_default_dispatch_to_partition_alloc.h" |
Benoit Lize | 097d9ce3 | 2020-10-26 12:33:39 | [diff] [blame] | 48 | #endif |
| 49 | |
Bartek Nowierski | af8d5d2 | 2023-01-11 11:01:02 | [diff] [blame] | 50 | #if PA_CONFIG(THREAD_CACHE_ALLOC_STATS) |
Etienne Dechamps | 4dacf2b | 2024-12-19 16:31:05 | [diff] [blame] | 51 | #include "partition_alloc/partition_alloc_constants.h" // nogncheck |
Benoit Lize | a497519 | 2021-07-15 14:32:29 | [diff] [blame] | 52 | #endif |
| 53 | |
Peter Kasting | 811504a7 | 2025-01-09 03:18:50 | [diff] [blame] | 54 | namespace base::trace_event { |
ssid | 0738685 | 2015-04-14 15:32:37 | [diff] [blame] | 55 | |
primiano | fd907216 | 2016-03-25 02:13:28 | [diff] [blame] | 56 | namespace { |
Xiaohan Wang | 38e4ebb | 2022-01-19 06:57:43 | [diff] [blame] | 57 | #if BUILDFLAG(IS_WIN) |
siggi | 7bec59a | 2016-08-25 20:22:26 | [diff] [blame] | 58 | // A structure containing some information about a given heap. |
| 59 | struct WinHeapInfo { |
siggi | 7bec59a | 2016-08-25 20:22:26 | [diff] [blame] | 60 | size_t committed_size; |
| 61 | size_t uncommitted_size; |
| 62 | size_t allocated_size; |
| 63 | size_t block_count; |
| 64 | }; |
| 65 | |
kraynov | ad50729 | 2016-11-25 18:01:23 | [diff] [blame] | 66 | // NOTE: crbug.com/665516 |
| 67 | // Unfortunately, there is no safe way to collect information from secondary |
| 68 | // heaps due to limitations and racy nature of this piece of WinAPI. |
siggi | 82535f6 | 2016-12-06 22:29:03 | [diff] [blame] | 69 | void WinHeapMemoryDumpImpl(WinHeapInfo* crt_heap_info) { |
siggi | 82535f6 | 2016-12-06 22:29:03 | [diff] [blame] | 70 | // Iterate through whichever heap our CRT is using. |
| 71 | HANDLE crt_heap = reinterpret_cast<HANDLE>(_get_heap_handle()); |
| 72 | ::HeapLock(crt_heap); |
kraynov | ad50729 | 2016-11-25 18:01:23 | [diff] [blame] | 73 | PROCESS_HEAP_ENTRY heap_entry; |
| 74 | heap_entry.lpData = nullptr; |
| 75 | // Walk over all the entries in the main heap. |
siggi | 82535f6 | 2016-12-06 22:29:03 | [diff] [blame] | 76 | while (::HeapWalk(crt_heap, &heap_entry) != FALSE) { |
kraynov | ad50729 | 2016-11-25 18:01:23 | [diff] [blame] | 77 | if ((heap_entry.wFlags & PROCESS_HEAP_ENTRY_BUSY) != 0) { |
siggi | 82535f6 | 2016-12-06 22:29:03 | [diff] [blame] | 78 | crt_heap_info->allocated_size += heap_entry.cbData; |
| 79 | crt_heap_info->block_count++; |
kraynov | ad50729 | 2016-11-25 18:01:23 | [diff] [blame] | 80 | } else if ((heap_entry.wFlags & PROCESS_HEAP_REGION) != 0) { |
siggi | 82535f6 | 2016-12-06 22:29:03 | [diff] [blame] | 81 | crt_heap_info->committed_size += heap_entry.Region.dwCommittedSize; |
| 82 | crt_heap_info->uncommitted_size += heap_entry.Region.dwUnCommittedSize; |
liamjm | c56e1ffa | 2016-10-15 01:04:46 | [diff] [blame] | 83 | } |
siggi | 7bec59a | 2016-08-25 20:22:26 | [diff] [blame] | 84 | } |
siggi | 82535f6 | 2016-12-06 22:29:03 | [diff] [blame] | 85 | CHECK(::HeapUnlock(crt_heap) == TRUE); |
siggi | 7bec59a | 2016-08-25 20:22:26 | [diff] [blame] | 86 | } |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 87 | |
| 88 | void ReportWinHeapStats(MemoryDumpLevelOfDetail level_of_detail, |
| 89 | ProcessMemoryDump* pmd, |
| 90 | size_t* total_virtual_size, |
| 91 | size_t* resident_size, |
| 92 | size_t* allocated_objects_size, |
| 93 | size_t* allocated_objects_count) { |
| 94 | // This is too expensive on Windows, crbug.com/780735. |
Ho Cheung | adbf3fb | 2023-09-08 02:01:11 | [diff] [blame] | 95 | if (level_of_detail == MemoryDumpLevelOfDetail::kDetailed) { |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 96 | WinHeapInfo main_heap_info = {}; |
| 97 | WinHeapMemoryDumpImpl(&main_heap_info); |
| 98 | *total_virtual_size += |
| 99 | main_heap_info.committed_size + main_heap_info.uncommitted_size; |
| 100 | // Resident size is approximated with committed heap size. Note that it is |
| 101 | // possible to do this with better accuracy on windows by intersecting the |
| 102 | // working set with the virtual memory ranges occuipied by the heap. It's |
| 103 | // not clear that this is worth it, as it's fairly expensive to do. |
| 104 | *resident_size += main_heap_info.committed_size; |
| 105 | *allocated_objects_size += main_heap_info.allocated_size; |
| 106 | *allocated_objects_count += main_heap_info.block_count; |
| 107 | |
| 108 | if (pmd) { |
| 109 | MemoryAllocatorDump* win_heap_dump = |
| 110 | pmd->CreateAllocatorDump("malloc/win_heap"); |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 111 | win_heap_dump->AddScalar(MemoryAllocatorDump::kNameSize, |
| 112 | MemoryAllocatorDump::kUnitsBytes, |
| 113 | main_heap_info.allocated_size); |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 114 | } |
| 115 | } |
| 116 | } |
Xiaohan Wang | 38e4ebb | 2022-01-19 06:57:43 | [diff] [blame] | 117 | #endif // BUILDFLAG(IS_WIN) |
Benoit Lize | 097d9ce3 | 2020-10-26 12:33:39 | [diff] [blame] | 118 | |
Arthur Sonzogni | 62e877a | 2024-04-30 16:09:43 | [diff] [blame] | 119 | #if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 120 | void ReportPartitionAllocStats(ProcessMemoryDump* pmd, |
| 121 | MemoryDumpLevelOfDetail level_of_detail, |
| 122 | size_t* total_virtual_size, |
| 123 | size_t* resident_size, |
Benoit Lize | 8d380a2 | 2022-01-06 18:51:34 | [diff] [blame] | 124 | size_t* allocated_objects_size, |
Keishi Hattori | e1464c3 | 2022-04-18 19:27:21 | [diff] [blame] | 125 | size_t* allocated_objects_count, |
Keishi Hattori | db0566a2 | 2022-06-28 07:25:38 | [diff] [blame] | 126 | uint64_t* syscall_count, |
| 127 | size_t* cumulative_brp_quarantined_size, |
| 128 | size_t* cumulative_brp_quarantined_count) { |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 129 | MemoryDumpPartitionStatsDumper partition_stats_dumper("malloc", pmd, |
| 130 | level_of_detail); |
Ho Cheung | adbf3fb | 2023-09-08 02:01:11 | [diff] [blame] | 131 | bool is_light_dump = level_of_detail == MemoryDumpLevelOfDetail::kBackground; |
Anton Bikineev | ebd5dc3 | 2021-03-05 09:12:25 | [diff] [blame] | 132 | |
Yuki Shiino | 2ff8131 | 2022-09-05 13:11:55 | [diff] [blame] | 133 | auto* allocator = allocator_shim::internal::PartitionAllocMalloc::Allocator(); |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 134 | allocator->DumpStats("allocator", is_light_dump, &partition_stats_dumper); |
Benoit Lize | 097d9ce3 | 2020-10-26 12:33:39 | [diff] [blame] | 135 | |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 136 | auto* original_allocator = |
Yuki Shiino | 2ff8131 | 2022-09-05 13:11:55 | [diff] [blame] | 137 | allocator_shim::internal::PartitionAllocMalloc::OriginalAllocator(); |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 138 | if (original_allocator) { |
| 139 | original_allocator->DumpStats("original", is_light_dump, |
| 140 | &partition_stats_dumper); |
Benoit Lize | 097d9ce3 | 2020-10-26 12:33:39 | [diff] [blame] | 141 | } |
Benoit Lize | 9021e274 | 2021-01-11 11:30:32 | [diff] [blame] | 142 | |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 143 | *total_virtual_size += partition_stats_dumper.total_resident_bytes(); |
Benoit Lize | d3ad25ac | 2021-08-17 19:36:47 | [diff] [blame] | 144 | *resident_size += partition_stats_dumper.total_resident_bytes(); |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 145 | *allocated_objects_size += partition_stats_dumper.total_active_bytes(); |
Keishi Hattori | e1464c3 | 2022-04-18 19:27:21 | [diff] [blame] | 146 | *allocated_objects_count += partition_stats_dumper.total_active_count(); |
Benoit Lize | 8d380a2 | 2022-01-06 18:51:34 | [diff] [blame] | 147 | *syscall_count += partition_stats_dumper.syscall_count(); |
Arthur Sonzogni | 62e877a | 2024-04-30 16:09:43 | [diff] [blame] | 148 | #if PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) |
Keishi Hattori | db0566a2 | 2022-06-28 07:25:38 | [diff] [blame] | 149 | *cumulative_brp_quarantined_size += |
| 150 | partition_stats_dumper.cumulative_brp_quarantined_bytes(); |
| 151 | *cumulative_brp_quarantined_count += |
| 152 | partition_stats_dumper.cumulative_brp_quarantined_count(); |
Arthur Sonzogni | 62e877a | 2024-04-30 16:09:43 | [diff] [blame] | 153 | #endif // PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) |
Benoit Lize | 097d9ce3 | 2020-10-26 12:33:39 | [diff] [blame] | 154 | } |
Arthur Sonzogni | 62e877a | 2024-04-30 16:09:43 | [diff] [blame] | 155 | #endif // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) |
Benoit Lize | 097d9ce3 | 2020-10-26 12:33:39 | [diff] [blame] | 156 | |
Arthur Sonzogni | 62e877a | 2024-04-30 16:09:43 | [diff] [blame] | 157 | #if !PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(IS_APPLE) |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 158 | void ReportAppleAllocStats(size_t* total_virtual_size, |
| 159 | size_t* resident_size, |
| 160 | size_t* allocated_objects_size) { |
| 161 | malloc_statistics_t stats = {0}; |
| 162 | malloc_zone_statistics(nullptr, &stats); |
| 163 | *total_virtual_size += stats.size_allocated; |
| 164 | *allocated_objects_size += stats.size_in_use; |
| 165 | |
| 166 | // Resident size is approximated pretty well by stats.max_size_in_use. |
| 167 | // However, on macOS, freed blocks are both resident and reusable, which is |
| 168 | // semantically equivalent to deallocated. The implementation of libmalloc |
| 169 | // will also only hold a fixed number of freed regions before actually |
| 170 | // starting to deallocate them, so stats.max_size_in_use is also not |
| 171 | // representative of the peak size. As a result, stats.max_size_in_use is |
| 172 | // typically somewhere between actually resident [non-reusable] pages, and |
| 173 | // peak size. This is not very useful, so we just use stats.size_in_use for |
| 174 | // resident_size, even though it's an underestimate and fails to account for |
| 175 | // fragmentation. See |
| 176 | // https://bugs.chromium.org/p/chromium/issues/detail?id=695263#c1. |
| 177 | *resident_size += stats.size_in_use; |
| 178 | } |
| 179 | #endif |
| 180 | |
Arthur Sonzogni | 62e877a | 2024-04-30 16:09:43 | [diff] [blame] | 181 | #if (PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(IS_ANDROID)) || \ |
| 182 | (!PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && !BUILDFLAG(IS_WIN) && \ |
Peter Kasting | a0b914dc | 2022-07-14 18:43:19 | [diff] [blame] | 183 | !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_FUCHSIA)) |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 184 | void ReportMallinfoStats(ProcessMemoryDump* pmd, |
| 185 | size_t* total_virtual_size, |
| 186 | size_t* resident_size, |
| 187 | size_t* allocated_objects_size, |
| 188 | size_t* allocated_objects_count) { |
| 189 | #if defined(__GLIBC__) && defined(__GLIBC_PREREQ) |
| 190 | #if __GLIBC_PREREQ(2, 33) |
| 191 | #define MALLINFO2_FOUND_IN_LIBC |
| 192 | struct mallinfo2 info = mallinfo2(); |
| 193 | #endif |
| 194 | #endif // defined(__GLIBC__) && defined(__GLIBC_PREREQ) |
| 195 | #if !defined(MALLINFO2_FOUND_IN_LIBC) |
| 196 | struct mallinfo info = mallinfo(); |
| 197 | #endif |
| 198 | #undef MALLINFO2_FOUND_IN_LIBC |
| 199 | // In case of Android's jemalloc |arena| is 0 and the outer pages size is |
| 200 | // reported by |hblkhd|. In case of dlmalloc the total is given by |
| 201 | // |arena| + |hblkhd|. For more details see link: http://goo.gl/fMR8lF. |
Peter Kasting | a0b914dc | 2022-07-14 18:43:19 | [diff] [blame] | 202 | *total_virtual_size += checked_cast<size_t>(info.arena + info.hblkhd); |
| 203 | size_t total_allocated_size = checked_cast<size_t>(info.uordblks); |
| 204 | *resident_size += total_allocated_size; |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 205 | |
| 206 | // Total allocated space is given by |uordblks|. |
Peter Kasting | a0b914dc | 2022-07-14 18:43:19 | [diff] [blame] | 207 | *allocated_objects_size += total_allocated_size; |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 208 | |
| 209 | if (pmd) { |
| 210 | MemoryAllocatorDump* sys_alloc_dump = |
| 211 | pmd->CreateAllocatorDump("malloc/sys_malloc"); |
| 212 | sys_alloc_dump->AddScalar(MemoryAllocatorDump::kNameSize, |
Peter Kasting | a0b914dc | 2022-07-14 18:43:19 | [diff] [blame] | 213 | MemoryAllocatorDump::kUnitsBytes, |
| 214 | total_allocated_size); |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 215 | } |
| 216 | } |
| 217 | #endif |
| 218 | |
Arthur Sonzogni | 62e877a | 2024-04-30 16:09:43 | [diff] [blame] | 219 | #if PA_BUILDFLAG(USE_PARTITION_ALLOC) |
Kalvin Lee | 01b3850d | 2022-06-15 22:41:55 | [diff] [blame] | 220 | void ReportPartitionAllocThreadCacheStats( |
| 221 | ProcessMemoryDump* pmd, |
| 222 | MemoryAllocatorDump* dump, |
| 223 | const partition_alloc::ThreadCacheStats& stats, |
| 224 | const std::string& metrics_suffix, |
| 225 | bool detailed) { |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 226 | dump->AddScalar("alloc_count", MemoryAllocatorDump::kTypeScalar, |
| 227 | stats.alloc_count); |
| 228 | dump->AddScalar("alloc_hits", MemoryAllocatorDump::kTypeScalar, |
| 229 | stats.alloc_hits); |
| 230 | dump->AddScalar("alloc_misses", MemoryAllocatorDump::kTypeScalar, |
| 231 | stats.alloc_misses); |
| 232 | |
| 233 | dump->AddScalar("alloc_miss_empty", MemoryAllocatorDump::kTypeScalar, |
| 234 | stats.alloc_miss_empty); |
| 235 | dump->AddScalar("alloc_miss_too_large", MemoryAllocatorDump::kTypeScalar, |
| 236 | stats.alloc_miss_too_large); |
| 237 | |
| 238 | dump->AddScalar("cache_fill_count", MemoryAllocatorDump::kTypeScalar, |
| 239 | stats.cache_fill_count); |
| 240 | dump->AddScalar("cache_fill_hits", MemoryAllocatorDump::kTypeScalar, |
| 241 | stats.cache_fill_hits); |
| 242 | dump->AddScalar("cache_fill_misses", MemoryAllocatorDump::kTypeScalar, |
| 243 | stats.cache_fill_misses); |
| 244 | |
| 245 | dump->AddScalar("batch_fill_count", MemoryAllocatorDump::kTypeScalar, |
| 246 | stats.batch_fill_count); |
| 247 | |
| 248 | dump->AddScalar(MemoryAllocatorDump::kNameSize, |
| 249 | MemoryAllocatorDump::kUnitsBytes, stats.bucket_total_memory); |
| 250 | dump->AddScalar("metadata_overhead", MemoryAllocatorDump::kUnitsBytes, |
| 251 | stats.metadata_overhead); |
| 252 | |
Bartek Nowierski | af8d5d2 | 2023-01-11 11:01:02 | [diff] [blame] | 253 | #if PA_CONFIG(THREAD_CACHE_ALLOC_STATS) |
Kalvin Lee | 7800f5c6 | 2024-06-20 11:59:12 | [diff] [blame] | 254 | if (stats.alloc_count && detailed) { |
| 255 | partition_alloc::internal::BucketIndexLookup lookup{}; |
| 256 | std::string name = dump->absolute_name(); |
| 257 | for (size_t i = 0; i < partition_alloc::kNumBuckets; i++) { |
| 258 | size_t bucket_size = lookup.bucket_sizes()[i]; |
| 259 | if (bucket_size == partition_alloc::kInvalidBucketSize) { |
| 260 | continue; |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 261 | } |
Kalvin Lee | 7800f5c6 | 2024-06-20 11:59:12 | [diff] [blame] | 262 | // Covers all normal buckets, that is up to ~1MiB, so 7 digits. |
| 263 | std::string dump_name = base::StringPrintf( |
| 264 | "%s/buckets_alloc/%07d", name.c_str(), static_cast<int>(bucket_size)); |
| 265 | auto* buckets_alloc_dump = pmd->CreateAllocatorDump(dump_name); |
| 266 | buckets_alloc_dump->AddScalar("count", MemoryAllocatorDump::kUnitsObjects, |
| 267 | stats.allocs_per_bucket_[i]); |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 268 | } |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 269 | } |
Kalvin Lee | 7800f5c6 | 2024-06-20 11:59:12 | [diff] [blame] | 270 | #endif // PA_CONFIG(THREAD_CACHE_ALLOC_STATS) |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 271 | } |
mikt | f85547d | 2024-03-13 09:06:20 | [diff] [blame] | 272 | |
| 273 | void ReportPartitionAllocLightweightQuarantineStats( |
| 274 | MemoryAllocatorDump* dump, |
| 275 | const partition_alloc::LightweightQuarantineStats& stats) { |
| 276 | dump->AddScalar("count", MemoryAllocatorDump::kUnitsObjects, stats.count); |
| 277 | dump->AddScalar("size_in_bytes", MemoryAllocatorDump::kUnitsBytes, |
| 278 | stats.size_in_bytes); |
| 279 | dump->AddScalar("cumulative_count", MemoryAllocatorDump::kUnitsObjects, |
| 280 | stats.cumulative_count); |
| 281 | dump->AddScalar("cumulative_size_in_bytes", MemoryAllocatorDump::kUnitsBytes, |
| 282 | stats.cumulative_size_in_bytes); |
| 283 | dump->AddScalar("quarantine_miss_count", MemoryAllocatorDump::kUnitsObjects, |
| 284 | stats.quarantine_miss_count); |
| 285 | } |
Arthur Sonzogni | 62e877a | 2024-04-30 16:09:43 | [diff] [blame] | 286 | #endif // PA_BUILDFLAG(USE_PARTITION_ALLOC) |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 287 | |
siggi | 7bec59a | 2016-08-25 20:22:26 | [diff] [blame] | 288 | } // namespace |
| 289 | |
ssid | 0738685 | 2015-04-14 15:32:37 | [diff] [blame] | 290 | // static |
primiano | fadec05e | 2015-06-03 16:57:32 | [diff] [blame] | 291 | const char MallocDumpProvider::kAllocatedObjects[] = "malloc/allocated_objects"; |
| 292 | |
| 293 | // static |
ssid | 0738685 | 2015-04-14 15:32:37 | [diff] [blame] | 294 | MallocDumpProvider* MallocDumpProvider::GetInstance() { |
| 295 | return Singleton<MallocDumpProvider, |
| 296 | LeakySingletonTraits<MallocDumpProvider>>::get(); |
| 297 | } |
| 298 | |
Arthur Sonzogni | 62e877a | 2024-04-30 16:09:43 | [diff] [blame] | 299 | #if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) |
Yuki Shiino | c56607c8 | 2024-04-22 09:26:40 | [diff] [blame] | 300 | // static |
Yuki Shiino | c56607c8 | 2024-04-22 09:26:40 | [diff] [blame] | 301 | void MallocDumpProvider::SetExtremeLUDGetStatsCallback( |
| 302 | ExtremeLUDGetStatsCallback callback) { |
Yuki Shiino | b94fcd3 | 2024-05-02 10:16:15 | [diff] [blame] | 303 | DCHECK(!callback.is_null()); |
| 304 | auto& extreme_lud_get_stats_callback = GetExtremeLUDGetStatsCallback(); |
| 305 | DCHECK(extreme_lud_get_stats_callback.is_null()); |
| 306 | extreme_lud_get_stats_callback = std::move(callback); |
| 307 | } |
| 308 | |
| 309 | // static |
| 310 | MallocDumpProvider::ExtremeLUDGetStatsCallback& |
| 311 | MallocDumpProvider::GetExtremeLUDGetStatsCallback() { |
| 312 | static NoDestructor<MallocDumpProvider::ExtremeLUDGetStatsCallback> |
| 313 | extreme_lud_get_stats_callback; |
| 314 | return *extreme_lud_get_stats_callback; |
Yuki Shiino | c56607c8 | 2024-04-22 09:26:40 | [diff] [blame] | 315 | } |
Arthur Sonzogni | 62e877a | 2024-04-30 16:09:43 | [diff] [blame] | 316 | #endif // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) |
Yuki Shiino | c56607c8 | 2024-04-22 09:26:40 | [diff] [blame] | 317 | |
erikchen | 37097a9 | 2018-05-22 20:28:47 | [diff] [blame] | 318 | MallocDumpProvider::MallocDumpProvider() = default; |
Chris Watkins | bb7211c | 2017-11-29 07:16:38 | [diff] [blame] | 319 | MallocDumpProvider::~MallocDumpProvider() = default; |
ssid | 0738685 | 2015-04-14 15:32:37 | [diff] [blame] | 320 | |
| 321 | // Called at trace dump point time. Creates a snapshot the memory counters for |
| 322 | // the current process. |
ssid | 90694aeec | 2015-08-06 13:01:30 | [diff] [blame] | 323 | bool MallocDumpProvider::OnMemoryDump(const MemoryDumpArgs& args, |
| 324 | ProcessMemoryDump* pmd) { |
Erik Chen | 4f64989c | 2017-11-10 18:15:53 | [diff] [blame] | 325 | { |
| 326 | base::AutoLock auto_lock(emit_metrics_on_memory_dump_lock_); |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 327 | if (!emit_metrics_on_memory_dump_) { |
Erik Chen | 4f64989c | 2017-11-10 18:15:53 | [diff] [blame] | 328 | return true; |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 329 | } |
Erik Chen | 4f64989c | 2017-11-10 18:15:53 | [diff] [blame] | 330 | } |
| 331 | |
ssid | 0943409 | 2015-10-26 23:05:04 | [diff] [blame] | 332 | size_t total_virtual_size = 0; |
| 333 | size_t resident_size = 0; |
| 334 | size_t allocated_objects_size = 0; |
siggi | 7bec59a | 2016-08-25 20:22:26 | [diff] [blame] | 335 | size_t allocated_objects_count = 0; |
Benoit Lize | 8d380a2 | 2022-01-06 18:51:34 | [diff] [blame] | 336 | uint64_t syscall_count = 0; |
Keishi Hattori | db0566a2 | 2022-06-28 07:25:38 | [diff] [blame] | 337 | size_t cumulative_brp_quarantined_size = 0; |
| 338 | size_t cumulative_brp_quarantined_count = 0; |
Arthur Sonzogni | 62e877a | 2024-04-30 16:09:43 | [diff] [blame] | 339 | #if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) |
Benoit Lize | 2c369084 | 2022-01-14 12:03:57 | [diff] [blame] | 340 | uint64_t pa_only_resident_size; |
| 341 | uint64_t pa_only_allocated_objects_size; |
Benoit Lize | 8d380a2 | 2022-01-06 18:51:34 | [diff] [blame] | 342 | #endif |
Benoit Lize | 097d9ce3 | 2020-10-26 12:33:39 | [diff] [blame] | 343 | |
Arthur Sonzogni | 62e877a | 2024-04-30 16:09:43 | [diff] [blame] | 344 | #if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) |
Keishi Hattori | db0566a2 | 2022-06-28 07:25:38 | [diff] [blame] | 345 | ReportPartitionAllocStats( |
| 346 | pmd, args.level_of_detail, &total_virtual_size, &resident_size, |
| 347 | &allocated_objects_size, &allocated_objects_count, &syscall_count, |
| 348 | &cumulative_brp_quarantined_size, &cumulative_brp_quarantined_count); |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 349 | |
Benoit Lize | 2c369084 | 2022-01-14 12:03:57 | [diff] [blame] | 350 | pa_only_resident_size = resident_size; |
| 351 | pa_only_allocated_objects_size = allocated_objects_size; |
| 352 | |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 353 | // Even when PartitionAlloc is used, WinHeap / System malloc is still used as |
| 354 | // well, report its statistics. |
| 355 | #if BUILDFLAG(IS_ANDROID) |
| 356 | ReportMallinfoStats(pmd, &total_virtual_size, &resident_size, |
| 357 | &allocated_objects_size, &allocated_objects_count); |
| 358 | #elif BUILDFLAG(IS_WIN) |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 359 | ReportWinHeapStats(args.level_of_detail, pmd, &total_virtual_size, |
| 360 | &resident_size, &allocated_objects_size, |
| 361 | &allocated_objects_count); |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 362 | #endif // BUILDFLAG(IS_ANDROID), BUILDFLAG(IS_WIN) |
ssid | 86f78c1 | 2015-12-21 11:45:32 | [diff] [blame] | 363 | |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 364 | #elif BUILDFLAG(IS_APPLE) |
| 365 | ReportAppleAllocStats(&total_virtual_size, &resident_size, |
| 366 | &allocated_objects_size); |
Xiaohan Wang | 38e4ebb | 2022-01-19 06:57:43 | [diff] [blame] | 367 | #elif BUILDFLAG(IS_WIN) |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 368 | ReportWinHeapStats(args.level_of_detail, nullptr, &total_virtual_size, |
| 369 | &resident_size, &allocated_objects_size, |
| 370 | &allocated_objects_count); |
Xiaohan Wang | 38e4ebb | 2022-01-19 06:57:43 | [diff] [blame] | 371 | #elif BUILDFLAG(IS_FUCHSIA) |
scottmg | 6ea9ff3e | 2017-05-19 00:08:16 | [diff] [blame] | 372 | // TODO(fuchsia): Port, see https://crbug.com/706592. |
ssid | 3aa02fe | 2015-11-07 16:15:07 | [diff] [blame] | 373 | #else |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 374 | ReportMallinfoStats(/*pmd=*/nullptr, &total_virtual_size, &resident_size, |
| 375 | &allocated_objects_size, &allocated_objects_count); |
ssid | 3aa02fe | 2015-11-07 16:15:07 | [diff] [blame] | 376 | #endif |
ssid | 0943409 | 2015-10-26 23:05:04 | [diff] [blame] | 377 | |
primiano | fadec05e | 2015-06-03 16:57:32 | [diff] [blame] | 378 | MemoryAllocatorDump* outer_dump = pmd->CreateAllocatorDump("malloc"); |
ssid | 0943409 | 2015-10-26 23:05:04 | [diff] [blame] | 379 | outer_dump->AddScalar("virtual_size", MemoryAllocatorDump::kUnitsBytes, |
| 380 | total_virtual_size); |
| 381 | outer_dump->AddScalar(MemoryAllocatorDump::kNameSize, |
| 382 | MemoryAllocatorDump::kUnitsBytes, resident_size); |
ssid | 0738685 | 2015-04-14 15:32:37 | [diff] [blame] | 383 | |
Keishi Hattori | cae288d | 2022-03-16 04:09:57 | [diff] [blame] | 384 | MemoryAllocatorDump* inner_dump = pmd->CreateAllocatorDump(kAllocatedObjects); |
| 385 | inner_dump->AddScalar(MemoryAllocatorDump::kNameSize, |
ssid | 0943409 | 2015-10-26 23:05:04 | [diff] [blame] | 386 | MemoryAllocatorDump::kUnitsBytes, |
| 387 | allocated_objects_size); |
siggi | 7bec59a | 2016-08-25 20:22:26 | [diff] [blame] | 388 | if (allocated_objects_count != 0) { |
Keishi Hattori | cae288d | 2022-03-16 04:09:57 | [diff] [blame] | 389 | inner_dump->AddScalar(MemoryAllocatorDump::kNameObjectCount, |
siggi | 7bec59a | 2016-08-25 20:22:26 | [diff] [blame] | 390 | MemoryAllocatorDump::kUnitsObjects, |
| 391 | allocated_objects_count); |
| 392 | } |
ssid | 0738685 | 2015-04-14 15:32:37 | [diff] [blame] | 393 | |
Peter Kasting | 9e94821 | 2022-06-16 18:41:11 | [diff] [blame] | 394 | int64_t waste = static_cast<int64_t>(resident_size - allocated_objects_size); |
Benoit Lize | 2c369084 | 2022-01-14 12:03:57 | [diff] [blame] | 395 | |
| 396 | // With PartitionAlloc, reported size under malloc/partitions is the resident |
| 397 | // size, so it already includes fragmentation. Meaning that "malloc/"'s size |
| 398 | // would double-count fragmentation if we report it under |
| 399 | // "malloc/metadata_fragmentation_caches" as well. |
| 400 | // |
| 401 | // Still report waste, as on some platforms, PartitionAlloc doesn't capture |
| 402 | // all of malloc()'s memory footprint. |
Arthur Sonzogni | 62e877a | 2024-04-30 16:09:43 | [diff] [blame] | 403 | #if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) |
Peter Kasting | 2f61c8b | 2022-07-19 23:43:46 | [diff] [blame] | 404 | int64_t pa_waste = static_cast<int64_t>(pa_only_resident_size - |
| 405 | pa_only_allocated_objects_size); |
Benoit Lize | 2c369084 | 2022-01-14 12:03:57 | [diff] [blame] | 406 | waste -= pa_waste; |
| 407 | #endif |
| 408 | |
| 409 | if (waste > 0) { |
Benoit Lize | f4e1472 | 2022-01-12 10:56:52 | [diff] [blame] | 410 | // Explicitly specify why is extra memory resident. In mac and ios it |
| 411 | // accounts for the fragmentation and metadata. |
ssid | 86f78c1 | 2015-12-21 11:45:32 | [diff] [blame] | 412 | MemoryAllocatorDump* other_dump = |
| 413 | pmd->CreateAllocatorDump("malloc/metadata_fragmentation_caches"); |
| 414 | other_dump->AddScalar(MemoryAllocatorDump::kNameSize, |
Peter Kasting | 9e94821 | 2022-06-16 18:41:11 | [diff] [blame] | 415 | MemoryAllocatorDump::kUnitsBytes, |
| 416 | static_cast<uint64_t>(waste)); |
ssid | 86f78c1 | 2015-12-21 11:45:32 | [diff] [blame] | 417 | } |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 418 | |
Yuki Shiino | c56607c8 | 2024-04-22 09:26:40 | [diff] [blame] | 419 | base::trace_event::MemoryAllocatorDump* partitions_dump = nullptr; |
Yuki Shiino | a92092e7 | 2024-09-05 07:11:15 | [diff] [blame] | 420 | base::trace_event::MemoryAllocatorDump* elud_dump_for_small_objects = nullptr; |
| 421 | ExtremeLUDStats elud_stats_for_small_objects; |
| 422 | base::trace_event::MemoryAllocatorDump* elud_dump_for_large_objects = nullptr; |
| 423 | ExtremeLUDStats elud_stats_for_large_objects; |
Arthur Sonzogni | 62e877a | 2024-04-30 16:09:43 | [diff] [blame] | 424 | #if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) |
Yuki Shiino | c56607c8 | 2024-04-22 09:26:40 | [diff] [blame] | 425 | partitions_dump = pmd->CreateAllocatorDump("malloc/partitions"); |
| 426 | pmd->AddOwnershipEdge(inner_dump->guid(), partitions_dump->guid()); |
| 427 | |
Yuki Shiino | b94fcd3 | 2024-05-02 10:16:15 | [diff] [blame] | 428 | auto& extreme_lud_get_stats_callback = GetExtremeLUDGetStatsCallback(); |
| 429 | if (!extreme_lud_get_stats_callback.is_null()) { |
| 430 | // The Extreme LUD is enabled. |
Yuki Shiino | a92092e7 | 2024-09-05 07:11:15 | [diff] [blame] | 431 | elud_dump_for_small_objects = |
| 432 | pmd->CreateAllocatorDump("malloc/extreme_lud/small_objects"); |
| 433 | elud_dump_for_large_objects = |
| 434 | pmd->CreateAllocatorDump("malloc/extreme_lud/large_objects"); |
| 435 | const auto elud_stats_set = extreme_lud_get_stats_callback.Run(); |
| 436 | elud_stats_for_small_objects = elud_stats_set.for_small_objects; |
| 437 | elud_stats_for_large_objects = elud_stats_set.for_large_objects; |
| 438 | ReportPartitionAllocLightweightQuarantineStats( |
| 439 | elud_dump_for_small_objects, elud_stats_for_small_objects.lq_stats); |
| 440 | ReportPartitionAllocLightweightQuarantineStats( |
| 441 | elud_dump_for_large_objects, elud_stats_for_large_objects.lq_stats); |
Yuki Shiino | c56607c8 | 2024-04-22 09:26:40 | [diff] [blame] | 442 | } |
Arthur Sonzogni | 62e877a | 2024-04-30 16:09:43 | [diff] [blame] | 443 | #endif // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) |
Yuki Shiino | c56607c8 | 2024-04-22 09:26:40 | [diff] [blame] | 444 | |
Yuki Shiino | a92092e7 | 2024-09-05 07:11:15 | [diff] [blame] | 445 | ReportPerMinuteStats( |
| 446 | syscall_count, cumulative_brp_quarantined_size, |
| 447 | cumulative_brp_quarantined_count, elud_stats_for_small_objects, |
| 448 | elud_stats_for_large_objects, outer_dump, partitions_dump, |
| 449 | elud_dump_for_small_objects, elud_dump_for_large_objects); |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 450 | |
| 451 | return true; |
| 452 | } |
| 453 | |
Keishi Hattori | db0566a2 | 2022-06-28 07:25:38 | [diff] [blame] | 454 | void MallocDumpProvider::ReportPerMinuteStats( |
| 455 | uint64_t syscall_count, |
| 456 | size_t cumulative_brp_quarantined_bytes, |
| 457 | size_t cumulative_brp_quarantined_count, |
Yuki Shiino | a92092e7 | 2024-09-05 07:11:15 | [diff] [blame] | 458 | const ExtremeLUDStats& elud_stats_for_small_objects, |
| 459 | const ExtremeLUDStats& elud_stats_for_large_objects, |
Keishi Hattori | db0566a2 | 2022-06-28 07:25:38 | [diff] [blame] | 460 | MemoryAllocatorDump* malloc_dump, |
Yuki Shiino | c56607c8 | 2024-04-22 09:26:40 | [diff] [blame] | 461 | MemoryAllocatorDump* partition_alloc_dump, |
Yuki Shiino | a92092e7 | 2024-09-05 07:11:15 | [diff] [blame] | 462 | MemoryAllocatorDump* elud_dump_for_small_objects, |
| 463 | MemoryAllocatorDump* elud_dump_for_large_objects) { |
Arthur Sonzogni | 62e877a | 2024-04-30 16:09:43 | [diff] [blame] | 464 | #if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) |
Benoit Lize | 8d380a2 | 2022-01-06 18:51:34 | [diff] [blame] | 465 | uint64_t new_syscalls = syscall_count - last_syscall_count_; |
Keishi Hattori | db0566a2 | 2022-06-28 07:25:38 | [diff] [blame] | 466 | size_t new_brp_quarantined_bytes = |
| 467 | cumulative_brp_quarantined_bytes - last_cumulative_brp_quarantined_bytes_; |
| 468 | size_t new_brp_quarantined_count = |
| 469 | cumulative_brp_quarantined_count - last_cumulative_brp_quarantined_count_; |
Benoit Lize | 8d380a2 | 2022-01-06 18:51:34 | [diff] [blame] | 470 | base::TimeDelta time_since_last_dump = |
| 471 | base::TimeTicks::Now() - last_memory_dump_time_; |
Yuki Shiino | c56607c8 | 2024-04-22 09:26:40 | [diff] [blame] | 472 | auto seconds_since_last_dump = time_since_last_dump.InSecondsF(); |
| 473 | uint64_t syscalls_per_minute = |
| 474 | static_cast<uint64_t>((60 * new_syscalls) / seconds_since_last_dump); |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 475 | malloc_dump->AddScalar("syscalls_per_minute", "count", syscalls_per_minute); |
Keishi Hattori | db0566a2 | 2022-06-28 07:25:38 | [diff] [blame] | 476 | if (partition_alloc_dump) { |
| 477 | size_t brp_quarantined_bytes_per_minute = |
Yuki Shiino | c56607c8 | 2024-04-22 09:26:40 | [diff] [blame] | 478 | (60 * new_brp_quarantined_bytes) / seconds_since_last_dump; |
Keishi Hattori | db0566a2 | 2022-06-28 07:25:38 | [diff] [blame] | 479 | size_t brp_quarantined_count_per_minute = |
Yuki Shiino | c56607c8 | 2024-04-22 09:26:40 | [diff] [blame] | 480 | (60 * new_brp_quarantined_count) / seconds_since_last_dump; |
Keishi Hattori | db0566a2 | 2022-06-28 07:25:38 | [diff] [blame] | 481 | partition_alloc_dump->AddScalar("brp_quarantined_bytes_per_minute", |
| 482 | MemoryAllocatorDump::kUnitsBytes, |
| 483 | brp_quarantined_bytes_per_minute); |
| 484 | partition_alloc_dump->AddScalar("brp_quarantined_count_per_minute", |
| 485 | MemoryAllocatorDump::kNameObjectCount, |
| 486 | brp_quarantined_count_per_minute); |
| 487 | } |
Yuki Shiino | a92092e7 | 2024-09-05 07:11:15 | [diff] [blame] | 488 | |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 489 | auto report_elud_per_minute_stats = |
| 490 | [time_since_last_dump, seconds_since_last_dump]( |
| 491 | const ExtremeLUDStats& elud_stats, |
| 492 | CumulativeEludStats& last_cumulative_elud_stats, |
| 493 | MemoryAllocatorDump* elud_dump) { |
| 494 | size_t bytes = elud_stats.lq_stats.cumulative_size_in_bytes - |
| 495 | last_cumulative_elud_stats.quarantined_bytes; |
| 496 | size_t count = elud_stats.lq_stats.cumulative_count - |
| 497 | last_cumulative_elud_stats.quarantined_count; |
| 498 | size_t miss_count = elud_stats.lq_stats.quarantine_miss_count - |
| 499 | last_cumulative_elud_stats.miss_count; |
| 500 | elud_dump->AddScalar("bytes_per_minute", |
| 501 | MemoryAllocatorDump::kUnitsBytes, |
| 502 | 60ull * bytes / seconds_since_last_dump); |
| 503 | elud_dump->AddScalar("count_per_minute", |
| 504 | MemoryAllocatorDump::kNameObjectCount, |
| 505 | 60ull * count / seconds_since_last_dump); |
| 506 | elud_dump->AddScalar("miss_count_per_minute", |
| 507 | MemoryAllocatorDump::kNameObjectCount, |
| 508 | 60ull * miss_count / seconds_since_last_dump); |
| 509 | // Given the following three: |
| 510 | // capacity := the quarantine storage space |
| 511 | // time := the elapsed time since the last dump |
| 512 | // bytes := the consumed/used bytes since the last dump |
| 513 | // We can define/calculate the following. |
| 514 | // speed := the consuming speed of the quarantine |
| 515 | // = bytes / time |
| 516 | // quarantined_time |
| 517 | // := the time to use up the capacity |
| 518 | // (near to how long an object may be quarantined) |
| 519 | // = capacity / speed |
| 520 | // = capacity / (bytes / time) |
| 521 | // = time * capacity / bytes |
| 522 | // |
| 523 | // Note that objects in the quarantine are randomly evicted. So objects |
| 524 | // may stay in the qurantine longer or shorter depending on object |
| 525 | // sizes, allocation/deallocation patterns, etc. in addition to pure |
| 526 | // randomness. So, this is just a rough estimation, not necessarily to |
| 527 | // be the average. |
| 528 | if (bytes > 0) { |
| 529 | elud_dump->AddScalar( |
| 530 | "quarantined_time", "msec", |
| 531 | static_cast<uint64_t>(time_since_last_dump.InMilliseconds()) * |
| 532 | elud_stats.capacity_in_bytes / bytes); |
| 533 | } |
| 534 | last_cumulative_elud_stats.quarantined_bytes = |
| 535 | elud_stats.lq_stats.cumulative_size_in_bytes; |
| 536 | last_cumulative_elud_stats.quarantined_count = |
| 537 | elud_stats.lq_stats.cumulative_count; |
| 538 | last_cumulative_elud_stats.miss_count = |
| 539 | elud_stats.lq_stats.quarantine_miss_count; |
| 540 | }; |
Yuki Shiino | a92092e7 | 2024-09-05 07:11:15 | [diff] [blame] | 541 | if (elud_dump_for_small_objects) { |
| 542 | report_elud_per_minute_stats(elud_stats_for_small_objects, |
| 543 | last_cumulative_elud_stats_for_small_objects_, |
| 544 | elud_dump_for_small_objects); |
| 545 | } |
| 546 | if (elud_dump_for_large_objects) { |
| 547 | report_elud_per_minute_stats(elud_stats_for_large_objects, |
| 548 | last_cumulative_elud_stats_for_large_objects_, |
| 549 | elud_dump_for_large_objects); |
Yuki Shiino | c56607c8 | 2024-04-22 09:26:40 | [diff] [blame] | 550 | } |
Benoit Lize | 8d380a2 | 2022-01-06 18:51:34 | [diff] [blame] | 551 | |
| 552 | last_memory_dump_time_ = base::TimeTicks::Now(); |
| 553 | last_syscall_count_ = syscall_count; |
Keishi Hattori | db0566a2 | 2022-06-28 07:25:38 | [diff] [blame] | 554 | last_cumulative_brp_quarantined_bytes_ = cumulative_brp_quarantined_bytes; |
| 555 | last_cumulative_brp_quarantined_count_ = cumulative_brp_quarantined_count; |
Arthur Sonzogni | 62e877a | 2024-04-30 16:09:43 | [diff] [blame] | 556 | #endif // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) |
Erik Chen | 4f64989c | 2017-11-10 18:15:53 | [diff] [blame] | 557 | } |
| 558 | |
Arthur Sonzogni | 62e877a | 2024-04-30 16:09:43 | [diff] [blame] | 559 | #if PA_BUILDFLAG(USE_PARTITION_ALLOC) |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 560 | std::string GetPartitionDumpName(const char* root_name, |
| 561 | const char* partition_name) { |
| 562 | return base::StringPrintf("%s/%s/%s", root_name, |
| 563 | MemoryDumpPartitionStatsDumper::kPartitionsDumpName, |
| 564 | partition_name); |
| 565 | } |
| 566 | |
Keishi Hattori | db0566a2 | 2022-06-28 07:25:38 | [diff] [blame] | 567 | MemoryDumpPartitionStatsDumper::MemoryDumpPartitionStatsDumper( |
| 568 | const char* root_name, |
| 569 | ProcessMemoryDump* memory_dump, |
| 570 | MemoryDumpLevelOfDetail level_of_detail) |
| 571 | : root_name_(root_name), |
| 572 | memory_dump_(memory_dump), |
Ho Cheung | adbf3fb | 2023-09-08 02:01:11 | [diff] [blame] | 573 | detailed_(level_of_detail != MemoryDumpLevelOfDetail::kBackground) {} |
Keishi Hattori | db0566a2 | 2022-06-28 07:25:38 | [diff] [blame] | 574 | |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 575 | void MemoryDumpPartitionStatsDumper::PartitionDumpTotals( |
| 576 | const char* partition_name, |
Kalvin Lee | 01b3850d | 2022-06-15 22:41:55 | [diff] [blame] | 577 | const partition_alloc::PartitionMemoryStats* memory_stats) { |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 578 | total_mmapped_bytes_ += memory_stats->total_mmapped_bytes; |
| 579 | total_resident_bytes_ += memory_stats->total_resident_bytes; |
| 580 | total_active_bytes_ += memory_stats->total_active_bytes; |
Keishi Hattori | e1464c3 | 2022-04-18 19:27:21 | [diff] [blame] | 581 | total_active_count_ += memory_stats->total_active_count; |
Benoit Lize | 8d380a2 | 2022-01-06 18:51:34 | [diff] [blame] | 582 | syscall_count_ += memory_stats->syscall_count; |
Arthur Sonzogni | 62e877a | 2024-04-30 16:09:43 | [diff] [blame] | 583 | #if PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) |
Keishi Hattori | db0566a2 | 2022-06-28 07:25:38 | [diff] [blame] | 584 | cumulative_brp_quarantined_bytes_ += |
| 585 | memory_stats->cumulative_brp_quarantined_bytes; |
| 586 | cumulative_brp_quarantined_count_ += |
| 587 | memory_stats->cumulative_brp_quarantined_count; |
Arthur Sonzogni | 62e877a | 2024-04-30 16:09:43 | [diff] [blame] | 588 | #endif // PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 589 | |
| 590 | std::string dump_name = GetPartitionDumpName(root_name_, partition_name); |
| 591 | MemoryAllocatorDump* allocator_dump = |
| 592 | memory_dump_->CreateAllocatorDump(dump_name); |
Thiabaud Engelbrecht | ff1e107 | 2021-11-13 01:49:41 | [diff] [blame] | 593 | |
| 594 | auto total_committed_bytes = memory_stats->total_committed_bytes; |
| 595 | auto total_active_bytes = memory_stats->total_active_bytes; |
Benoît Lizé | 240f9b7 | 2025-01-27 11:15:28 | [diff] [blame] | 596 | size_t wasted = 0; |
| 597 | // This should always be true, but only if our accounting of committed bytes |
| 598 | // is consistent, which it isn't. Indeed, with |
| 599 | // PartitionAllocFewerMemoryRegions, we may allocate a slot span before the |
| 600 | // feature state is known, in which case we commit less, then decommit it |
| 601 | // after, in which case we subtract the new commit unit, which is larger. |
| 602 | // |
| 603 | // Properly handling this would require remembering how much was committed, |
| 604 | // which complicates bookkeeping, especially as metadata space is |
| 605 | // limited. Since this is only used to report metrics, which are known to |
| 606 | // already be quite flawed, and the feature is meant to be temporary (either |
| 607 | // shipped or abandoned), don't handle this corner case (which should only |
| 608 | // happen for the initial partition, which is tiny anyway). |
| 609 | if (total_committed_bytes >= total_active_bytes) { |
| 610 | wasted = total_committed_bytes - total_active_bytes; |
| 611 | } |
Thiabaud Engelbrecht | ff1e107 | 2021-11-13 01:49:41 | [diff] [blame] | 612 | size_t fragmentation = |
| 613 | total_committed_bytes == 0 ? 0 : 100 * wasted / total_committed_bytes; |
| 614 | |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 615 | allocator_dump->AddScalar(MemoryAllocatorDump::kNameSize, |
| 616 | MemoryAllocatorDump::kUnitsBytes, |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 617 | memory_stats->total_resident_bytes); |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 618 | allocator_dump->AddScalar("allocated_objects_size", |
| 619 | MemoryAllocatorDump::kUnitsBytes, |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 620 | memory_stats->total_active_bytes); |
Keishi Hattori | e1464c3 | 2022-04-18 19:27:21 | [diff] [blame] | 621 | allocator_dump->AddScalar("allocated_objects_count", "count", |
| 622 | memory_stats->total_active_count); |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 623 | allocator_dump->AddScalar("virtual_size", MemoryAllocatorDump::kUnitsBytes, |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 624 | memory_stats->total_mmapped_bytes); |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 625 | allocator_dump->AddScalar("virtual_committed_size", |
| 626 | MemoryAllocatorDump::kUnitsBytes, |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 627 | memory_stats->total_committed_bytes); |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 628 | allocator_dump->AddScalar("max_committed_size", |
| 629 | MemoryAllocatorDump::kUnitsBytes, |
Thiabaud Engelbrecht | d190ee98 | 2021-08-11 16:21:27 | [diff] [blame] | 630 | memory_stats->max_committed_bytes); |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 631 | allocator_dump->AddScalar("allocated_size", MemoryAllocatorDump::kUnitsBytes, |
Thiabaud Engelbrecht | d190ee98 | 2021-08-11 16:21:27 | [diff] [blame] | 632 | memory_stats->total_allocated_bytes); |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 633 | allocator_dump->AddScalar("max_allocated_size", |
| 634 | MemoryAllocatorDump::kUnitsBytes, |
Thiabaud Engelbrecht | d190ee98 | 2021-08-11 16:21:27 | [diff] [blame] | 635 | memory_stats->max_allocated_bytes); |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 636 | allocator_dump->AddScalar("decommittable_size", |
| 637 | MemoryAllocatorDump::kUnitsBytes, |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 638 | memory_stats->total_decommittable_bytes); |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 639 | allocator_dump->AddScalar("discardable_size", |
| 640 | MemoryAllocatorDump::kUnitsBytes, |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 641 | memory_stats->total_discardable_bytes); |
Arthur Sonzogni | 62e877a | 2024-04-30 16:09:43 | [diff] [blame] | 642 | #if PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 643 | allocator_dump->AddScalar("brp_quarantined_size", |
| 644 | MemoryAllocatorDump::kUnitsBytes, |
Keishi Hattori | c713e72 | 2021-09-23 03:09:59 | [diff] [blame] | 645 | memory_stats->total_brp_quarantined_bytes); |
| 646 | allocator_dump->AddScalar("brp_quarantined_count", "count", |
| 647 | memory_stats->total_brp_quarantined_count); |
Arthur Sonzogni | 62e877a | 2024-04-30 16:09:43 | [diff] [blame] | 648 | #endif // PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) |
Benoit Lize | cbd94862 | 2021-09-17 09:23:55 | [diff] [blame] | 649 | allocator_dump->AddScalar("syscall_count", "count", |
| 650 | memory_stats->syscall_count); |
| 651 | allocator_dump->AddScalar("syscall_total_time_ms", "ms", |
| 652 | memory_stats->syscall_total_time_ns / 1e6); |
Thiabaud Engelbrecht | ff1e107 | 2021-11-13 01:49:41 | [diff] [blame] | 653 | allocator_dump->AddScalar("fragmentation", "percent", fragmentation); |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 654 | allocator_dump->AddScalar("wasted", MemoryAllocatorDump::kUnitsBytes, wasted); |
Benoit Lize | cbd94862 | 2021-09-17 09:23:55 | [diff] [blame] | 655 | |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 656 | if (memory_stats->has_thread_cache) { |
| 657 | const auto& thread_cache_stats = memory_stats->current_thread_cache_stats; |
| 658 | auto* thread_cache_dump = memory_dump_->CreateAllocatorDump( |
| 659 | dump_name + "/thread_cache/main_thread"); |
| 660 | ReportPartitionAllocThreadCacheStats(memory_dump_, thread_cache_dump, |
| 661 | thread_cache_stats, ".MainThread", |
| 662 | detailed_); |
| 663 | |
| 664 | const auto& all_thread_caches_stats = memory_stats->all_thread_caches_stats; |
| 665 | auto* all_thread_caches_dump = |
| 666 | memory_dump_->CreateAllocatorDump(dump_name + "/thread_cache"); |
| 667 | ReportPartitionAllocThreadCacheStats(memory_dump_, all_thread_caches_dump, |
| 668 | all_thread_caches_stats, "", |
| 669 | detailed_); |
| 670 | } |
mikt | f85547d | 2024-03-13 09:06:20 | [diff] [blame] | 671 | |
| 672 | if (memory_stats->has_scheduler_loop_quarantine) { |
| 673 | MemoryAllocatorDump* quarantine_dump_total = |
| 674 | memory_dump_->CreateAllocatorDump(dump_name + |
| 675 | "/scheduler_loop_quarantine"); |
| 676 | ReportPartitionAllocLightweightQuarantineStats( |
| 677 | quarantine_dump_total, |
| 678 | memory_stats->scheduler_loop_quarantine_stats_total); |
| 679 | } |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 680 | } |
| 681 | |
| 682 | void MemoryDumpPartitionStatsDumper::PartitionsDumpBucketStats( |
| 683 | const char* partition_name, |
Kalvin Lee | 01b3850d | 2022-06-15 22:41:55 | [diff] [blame] | 684 | const partition_alloc::PartitionBucketMemoryStats* memory_stats) { |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 685 | DCHECK(memory_stats->is_valid); |
| 686 | std::string dump_name = GetPartitionDumpName(root_name_, partition_name); |
| 687 | if (memory_stats->is_direct_map) { |
| 688 | dump_name.append(base::StringPrintf("/buckets/directMap_%" PRIu64, ++uid_)); |
| 689 | } else { |
Benoit Lize | 4c0734c | 2021-09-10 20:14:08 | [diff] [blame] | 690 | // Normal buckets go up to ~1MiB, 7 digits. |
| 691 | dump_name.append(base::StringPrintf("/buckets/bucket_%07" PRIu32, |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 692 | memory_stats->bucket_slot_size)); |
| 693 | } |
| 694 | |
| 695 | MemoryAllocatorDump* allocator_dump = |
| 696 | memory_dump_->CreateAllocatorDump(dump_name); |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 697 | allocator_dump->AddScalar(MemoryAllocatorDump::kNameSize, |
| 698 | MemoryAllocatorDump::kUnitsBytes, |
| 699 | memory_stats->resident_bytes); |
| 700 | allocator_dump->AddScalar("allocated_objects_size", |
| 701 | MemoryAllocatorDump::kUnitsBytes, |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 702 | memory_stats->active_bytes); |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 703 | allocator_dump->AddScalar("slot_size", MemoryAllocatorDump::kUnitsBytes, |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 704 | memory_stats->bucket_slot_size); |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 705 | allocator_dump->AddScalar("decommittable_size", |
| 706 | MemoryAllocatorDump::kUnitsBytes, |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 707 | memory_stats->decommittable_bytes); |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 708 | allocator_dump->AddScalar("discardable_size", |
| 709 | MemoryAllocatorDump::kUnitsBytes, |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 710 | memory_stats->discardable_bytes); |
| 711 | // TODO(bartekn): Rename the scalar names. |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 712 | allocator_dump->AddScalar("total_slot_span_size", |
| 713 | MemoryAllocatorDump::kUnitsBytes, |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 714 | memory_stats->allocated_slot_span_size); |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 715 | allocator_dump->AddScalar("active_slot_spans", |
| 716 | MemoryAllocatorDump::kUnitsObjects, |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 717 | memory_stats->num_active_slot_spans); |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 718 | allocator_dump->AddScalar("full_slot_spans", |
| 719 | MemoryAllocatorDump::kUnitsObjects, |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 720 | memory_stats->num_full_slot_spans); |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 721 | allocator_dump->AddScalar("empty_slot_spans", |
| 722 | MemoryAllocatorDump::kUnitsObjects, |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 723 | memory_stats->num_empty_slot_spans); |
ssid | 9becc20 | 2022-03-25 05:06:20 | [diff] [blame] | 724 | allocator_dump->AddScalar("decommitted_slot_spans", |
| 725 | MemoryAllocatorDump::kUnitsObjects, |
Keishi Hattori | 3fa56dd | 2021-04-15 09:33:02 | [diff] [blame] | 726 | memory_stats->num_decommitted_slot_spans); |
| 727 | } |
Arthur Sonzogni | 62e877a | 2024-04-30 16:09:43 | [diff] [blame] | 728 | #endif // PA_BUILDFLAG(USE_PARTITION_ALLOC) |
Benoit Lize | 097d9ce3 | 2020-10-26 12:33:39 | [diff] [blame] | 729 | |
Peter Kasting | 811504a7 | 2025-01-09 03:18:50 | [diff] [blame] | 730 | } // namespace base::trace_event |