Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 467 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 478 PartitionPage* secondaryPage = reinterpret_cast<PartitionPage*>(pageChar Ptr); | 478 PartitionPage* secondaryPage = reinterpret_cast<PartitionPage*>(pageChar Ptr); |
| 479 secondaryPage->pageOffset = i; | 479 secondaryPage->pageOffset = i; |
| 480 } | 480 } |
| 481 } | 481 } |
| 482 | 482 |
| 483 static ALWAYS_INLINE size_t partitionRoundUpToSystemPage(size_t size) | 483 static ALWAYS_INLINE size_t partitionRoundUpToSystemPage(size_t size) |
| 484 { | 484 { |
| 485 return (size + kSystemPageOffsetMask) & kSystemPageBaseMask; | 485 return (size + kSystemPageOffsetMask) & kSystemPageBaseMask; |
| 486 } | 486 } |
| 487 | 487 |
| 488 static ALWAYS_INLINE size_t partitionRoundDownToSystemPage(size_t size) | |
| 489 { | |
| 490 return size & kSystemPageBaseMask; | |
| 491 } | |
| 492 | |
| 488 static ALWAYS_INLINE char* partitionPageAllocAndFillFreelist(PartitionPage* page ) | 493 static ALWAYS_INLINE char* partitionPageAllocAndFillFreelist(PartitionPage* page ) |
| 489 { | 494 { |
| 490 ASSERT(page != &PartitionRootGeneric::gSeedPage); | 495 ASSERT(page != &PartitionRootGeneric::gSeedPage); |
| 491 uint16_t numSlots = page->numUnprovisionedSlots; | 496 uint16_t numSlots = page->numUnprovisionedSlots; |
| 492 ASSERT(numSlots); | 497 ASSERT(numSlots); |
| 493 PartitionBucket* bucket = page->bucket; | 498 PartitionBucket* bucket = page->bucket; |
| 494 // We should only get here when _every_ slot is either used or unprovisioned . | 499 // We should only get here when _every_ slot is either used or unprovisioned . |
| 495 // (The third state is "on the freelist". If we have a non-empty freelist, w e should not get here.) | 500 // (The third state is "on the freelist". If we have a non-empty freelist, w e should not get here.) |
| 496 ASSERT(numSlots + page->numAllocatedSlots == partitionBucketSlots(bucket)); | 501 ASSERT(numSlots + page->numAllocatedSlots == partitionBucketSlots(bucket)); |
| 497 // Similarly, make explicitly sure that the freelist is empty. | 502 // Similarly, make explicitly sure that the freelist is empty. |
| (...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 870 static void partitionDecommitEmptyPages(PartitionRootBase* root) | 875 static void partitionDecommitEmptyPages(PartitionRootBase* root) |
| 871 { | 876 { |
| 872 for (size_t i = 0; i < kMaxFreeableSpans; ++i) { | 877 for (size_t i = 0; i < kMaxFreeableSpans; ++i) { |
| 873 PartitionPage* page = root->globalEmptyPageRing[i]; | 878 PartitionPage* page = root->globalEmptyPageRing[i]; |
| 874 if (page) | 879 if (page) |
| 875 partitionDecommitPageIfPossible(root, page); | 880 partitionDecommitPageIfPossible(root, page); |
| 876 root->globalEmptyPageRing[i] = nullptr; | 881 root->globalEmptyPageRing[i] = nullptr; |
| 877 } | 882 } |
| 878 } | 883 } |
| 879 | 884 |
| 880 void partitionPurgeMemory(PartitionRoot* root, int flags) | |
| 881 { | |
| 882 if (flags & PartitionPurgeDecommitEmptyPages) | |
| 883 partitionDecommitEmptyPages(root); | |
| 884 } | |
| 885 | |
| 886 void partitionPurgeMemoryGeneric(PartitionRootGeneric* root, int flags) | |
| 887 { | |
| 888 spinLockLock(&root->lock); | |
| 889 if (flags & PartitionPurgeDecommitEmptyPages) | |
| 890 partitionDecommitEmptyPages(root); | |
| 891 spinLockUnlock(&root->lock); | |
| 892 } | |
| 893 | |
| 894 void partitionFreeSlowPath(PartitionPage* page) | 885 void partitionFreeSlowPath(PartitionPage* page) |
| 895 { | 886 { |
| 896 PartitionBucket* bucket = page->bucket; | 887 PartitionBucket* bucket = page->bucket; |
| 897 ASSERT(page != &PartitionRootGeneric::gSeedPage); | 888 ASSERT(page != &PartitionRootGeneric::gSeedPage); |
| 898 if (LIKELY(page->numAllocatedSlots == 0)) { | 889 if (LIKELY(page->numAllocatedSlots == 0)) { |
| 899 // Page became fully unused. | 890 // Page became fully unused. |
| 900 if (UNLIKELY(partitionBucketIsDirectMapped(bucket))) { | 891 if (UNLIKELY(partitionBucketIsDirectMapped(bucket))) { |
| 901 partitionDirectUnmap(page); | 892 partitionDirectUnmap(page); |
| 902 return; | 893 return; |
| 903 } | 894 } |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1064 size_t copySize = actualOldSize; | 1055 size_t copySize = actualOldSize; |
| 1065 if (newSize < copySize) | 1056 if (newSize < copySize) |
| 1066 copySize = newSize; | 1057 copySize = newSize; |
| 1067 | 1058 |
| 1068 memcpy(ret, ptr, copySize); | 1059 memcpy(ret, ptr, copySize); |
| 1069 partitionFreeGeneric(root, ptr); | 1060 partitionFreeGeneric(root, ptr); |
| 1070 return ret; | 1061 return ret; |
| 1071 #endif | 1062 #endif |
| 1072 } | 1063 } |
| 1073 | 1064 |
| 1074 static void partitionDumpPageStats(PartitionBucketMemoryStats* statsOut, const P artitionPage* page) | 1065 static void partitionPageWalk(PartitionBucketMemoryStats* statsOut, const Partit ionPage* page, bool discardMemory) |
|
haraken
2015/06/22 03:36:58
Maybe you can return the discardableBytes from thi
| |
| 1066 { | |
| 1067 const PartitionBucket* bucket = page->bucket; | |
| 1068 if (bucket->slotSize < kSystemPageSize) | |
| 1069 return; | |
| 1070 | |
| 1071 size_t bucketNumSlots = partitionBucketSlots(bucket); | |
| 1072 char slotUsage[(kPartitionPageSize * kMaxPartitionPagesPerSlotSpan) / kSyste mPageSize]; | |
| 1073 size_t lastSlot = -1; | |
| 1074 memset(slotUsage, 1, sizeof(slotUsage)); | |
| 1075 char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page)); | |
| 1076 PartitionFreelistEntry* fl = page->freelistHead; | |
| 1077 // First, walk the freelist for this page and make a bitmap of which slots | |
| 1078 // are not in use. | |
| 1079 while (fl) { | |
| 1080 size_t slotIndex = (reinterpret_cast<char*>(fl) - ptr) / bucket->slotSiz e; | |
| 1081 ASSERT(slotIndex < bucketNumSlots); | |
| 1082 slotUsage[slotIndex] = 0; | |
| 1083 fl = partitionFreelistMask(fl->next); | |
| 1084 if (!fl && !partitionFreelistMask(fl)) | |
| 1085 lastSlot = slotIndex; | |
| 1086 } | |
| 1087 // Next, walk the slots and for any not in use, consider where the system | |
| 1088 // page boundaries occur. We can release any system pages back to the | |
| 1089 // system as long as we don't interfere with a freelist pointer or an | |
| 1090 // adjacent slot. | |
| 1091 // TODO(cevans): I think we can "truncate" the page, i.e. increase the | |
| 1092 // value of page->numUnprovisionedSlots and rewrite(!) the freelist, if | |
| 1093 // we find that to be a win too. | |
| 1094 for (size_t i = 0; i < bucketNumSlots; ++i) { | |
| 1095 if (slotUsage[i]) | |
| 1096 continue; | |
| 1097 // The first address we can safely discard is just after the freelist | |
| 1098 // pointer. There's one quirk: if the freelist pointer is actually a | |
| 1099 // null, we can discard that pointer value too. | |
| 1100 char* beginPtr = ptr + (i * bucket->slotSize); | |
| 1101 char* endPtr = beginPtr + bucket->slotSize; | |
| 1102 if (i != lastSlot) | |
| 1103 beginPtr += sizeof(PartitionFreelistEntry); | |
| 1104 beginPtr = reinterpret_cast<char*>(partitionRoundUpToSystemPage(reinterp ret_cast<size_t>(beginPtr))); | |
| 1105 endPtr = reinterpret_cast<char*>(partitionRoundDownToSystemPage(reinterp ret_cast<size_t>(endPtr))); | |
| 1106 if (beginPtr < endPtr) { | |
| 1107 size_t discardable = endPtr - beginPtr; | |
| 1108 statsOut->discardableBytes += discardable; | |
| 1109 if (discardMemory) | |
| 1110 discardSystemPages(beginPtr, discardable); | |
| 1111 } | |
| 1112 } | |
| 1113 } | |
| 1114 | |
| 1115 static void partitionDumpPageStats(PartitionBucketMemoryStats* statsOut, const P artitionPage* page, bool discardMemory) | |
| 1075 { | 1116 { |
| 1076 uint16_t bucketNumSlots = partitionBucketSlots(page->bucket); | 1117 uint16_t bucketNumSlots = partitionBucketSlots(page->bucket); |
| 1077 | 1118 |
| 1078 if (!page->freelistHead && page->numAllocatedSlots == 0) { | 1119 if (!page->freelistHead && page->numAllocatedSlots == 0) { |
| 1079 ASSERT(!page->numUnprovisionedSlots); | 1120 ASSERT(!page->numUnprovisionedSlots); |
| 1080 ++statsOut->numDecommittedPages; | 1121 ++statsOut->numDecommittedPages; |
| 1122 return; | |
| 1123 } | |
| 1124 | |
| 1125 size_t pageBytesResident = partitionRoundUpToSystemPage((bucketNumSlots - pa ge->numUnprovisionedSlots) * statsOut->bucketSlotSize); | |
| 1126 | |
| 1127 size_t rawSize = partitionPageGetRawSize(const_cast<PartitionPage*>(page)); | |
| 1128 if (rawSize) { | |
| 1129 uint32_t activeBytes = static_cast<uint32_t>(partitionRoundUpToSystemPag e(rawSize)); | |
| 1130 statsOut->activeBytes += activeBytes; | |
| 1131 if (activeBytes < pageBytesResident) { | |
| 1132 ASSERT(((pageBytesResident - activeBytes) % kSystemPageSize) == 0); | |
|
haraken
2015/06/22 03:36:58
Just help me understand: How is it guaranteed that
| |
| 1133 size_t discardable = pageBytesResident - activeBytes; | |
| 1134 char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page)); | |
| 1135 ptr += activeBytes; | |
| 1136 statsOut->discardableBytes += discardable; | |
| 1137 if (discardMemory) | |
| 1138 discardSystemPages(ptr, discardable); | |
|
haraken
2015/06/22 03:36:58
I'm a bit afraid that if we have a bug in the disc
| |
| 1139 } | |
| 1081 } else { | 1140 } else { |
| 1082 size_t rawSize = partitionPageGetRawSize(const_cast<PartitionPage*>(page )); | 1141 statsOut->activeBytes += (page->numAllocatedSlots * statsOut->bucketSlot Size); |
| 1083 if (rawSize) | 1142 } |
| 1084 statsOut->activeBytes += static_cast<uint32_t>(partitionRoundUpToSys temPage(rawSize)); | 1143 statsOut->residentBytes += pageBytesResident; |
| 1085 else | 1144 if (!page->numAllocatedSlots) { |
| 1086 statsOut->activeBytes += (page->numAllocatedSlots * statsOut->bucket SlotSize); | 1145 statsOut->decommittableBytes += pageBytesResident; |
| 1087 size_t pageBytesResident = (bucketNumSlots - page->numUnprovisionedSlots ) * statsOut->bucketSlotSize; | 1146 ++statsOut->numEmptyPages; |
|
haraken
2015/06/22 03:36:58
Shall we call discardSystemPages here? Given that
| |
| 1088 // Round up to system page size. | 1147 } else if (page->numAllocatedSlots == bucketNumSlots) { |
| 1089 size_t pageBytesResidentRounded = partitionRoundUpToSystemPage(pageBytes Resident); | 1148 ++statsOut->numFullPages; |
| 1090 statsOut->residentBytes += pageBytesResidentRounded; | 1149 } else { |
| 1091 if (!page->numAllocatedSlots) { | 1150 ++statsOut->numActivePages; |
| 1092 statsOut->decommittableBytes += pageBytesResidentRounded; | 1151 partitionPageWalk(statsOut, page, discardMemory); |
| 1093 ++statsOut->numEmptyPages; | |
| 1094 } else if (page->numAllocatedSlots == bucketNumSlots) { | |
| 1095 ++statsOut->numFullPages; | |
| 1096 } else { | |
| 1097 ++statsOut->numActivePages; | |
| 1098 } | |
| 1099 } | 1152 } |
| 1100 } | 1153 } |
| 1101 | 1154 |
| 1102 static void partitionDumpBucketStats(PartitionBucketMemoryStats* statsOut, const PartitionBucket* bucket) | 1155 static void partitionDumpBucketStats(PartitionBucketMemoryStats* statsOut, const PartitionBucket* bucket, bool discardMemory) |
| 1103 { | 1156 { |
| 1104 ASSERT(!partitionBucketIsDirectMapped(bucket)); | 1157 ASSERT(!partitionBucketIsDirectMapped(bucket)); |
| 1105 statsOut->isValid = false; | 1158 statsOut->isValid = false; |
| 1106 // If the active page list is empty (== &PartitionRootGeneric::gSeedPage), | 1159 // If the active page list is empty (== &PartitionRootGeneric::gSeedPage), |
| 1107 // the bucket might still need to be reported if it has an empty page list, | 1160 // the bucket might still need to be reported if it has an empty page list, |
| 1108 // or full pages. | 1161 // or full pages. |
| 1109 if (bucket->activePagesHead == &PartitionRootGeneric::gSeedPage && !bucket-> emptyPagesHead && !bucket->numFullPages) | 1162 if (bucket->activePagesHead == &PartitionRootGeneric::gSeedPage && !bucket-> emptyPagesHead && !bucket->numFullPages) |
| 1110 return; | 1163 return; |
| 1111 | 1164 |
| 1112 memset(statsOut, '\0', sizeof(*statsOut)); | 1165 memset(statsOut, '\0', sizeof(*statsOut)); |
| 1113 statsOut->isValid = true; | 1166 statsOut->isValid = true; |
| 1114 statsOut->isDirectMap = false; | 1167 statsOut->isDirectMap = false; |
| 1115 statsOut->numFullPages = static_cast<size_t>(bucket->numFullPages); | 1168 statsOut->numFullPages = static_cast<size_t>(bucket->numFullPages); |
| 1116 statsOut->bucketSlotSize = bucket->slotSize; | 1169 statsOut->bucketSlotSize = bucket->slotSize; |
| 1117 uint16_t bucketNumSlots = partitionBucketSlots(bucket); | 1170 uint16_t bucketNumSlots = partitionBucketSlots(bucket); |
| 1118 size_t bucketUsefulStorage = statsOut->bucketSlotSize * bucketNumSlots; | 1171 size_t bucketUsefulStorage = statsOut->bucketSlotSize * bucketNumSlots; |
| 1119 statsOut->allocatedPageSize = partitionBucketBytes(bucket); | 1172 statsOut->allocatedPageSize = partitionBucketBytes(bucket); |
| 1120 statsOut->activeBytes = bucket->numFullPages * bucketUsefulStorage; | 1173 statsOut->activeBytes = bucket->numFullPages * bucketUsefulStorage; |
| 1121 statsOut->residentBytes = bucket->numFullPages * statsOut->allocatedPageSize ; | 1174 statsOut->residentBytes = bucket->numFullPages * statsOut->allocatedPageSize ; |
| 1122 | 1175 |
| 1123 for (const PartitionPage* page = bucket->emptyPagesHead; page; page = page-> nextPage) { | 1176 for (const PartitionPage* page = bucket->emptyPagesHead; page; page = page-> nextPage) { |
| 1124 // Currently, only decommitted pages appear in the empty pages list. | 1177 // Currently, only decommitted pages appear in the empty pages list. |
| 1125 // This may change. | 1178 // This may change. |
| 1126 ASSERT(page != &PartitionRootGeneric::gSeedPage); | 1179 ASSERT(page != &PartitionRootGeneric::gSeedPage); |
| 1127 ASSERT(!page->freelistHead); | 1180 ASSERT(!page->freelistHead); |
| 1128 ASSERT(!page->numAllocatedSlots); | 1181 ASSERT(!page->numAllocatedSlots); |
| 1129 ASSERT(!page->numUnprovisionedSlots); | 1182 ASSERT(!page->numUnprovisionedSlots); |
| 1130 partitionDumpPageStats(statsOut, page); | 1183 partitionDumpPageStats(statsOut, page, discardMemory); |
| 1131 } | 1184 } |
| 1132 | 1185 |
| 1133 if (bucket->activePagesHead != &PartitionRootGeneric::gSeedPage) { | 1186 if (bucket->activePagesHead != &PartitionRootGeneric::gSeedPage) { |
| 1134 for (const PartitionPage* page = bucket->activePagesHead; page; page = p age->nextPage) { | 1187 for (const PartitionPage* page = bucket->activePagesHead; page; page = p age->nextPage) { |
| 1135 ASSERT(page != &PartitionRootGeneric::gSeedPage); | 1188 ASSERT(page != &PartitionRootGeneric::gSeedPage); |
| 1136 partitionDumpPageStats(statsOut, page); | 1189 partitionDumpPageStats(statsOut, page, discardMemory); |
| 1137 } | 1190 } |
| 1138 } | 1191 } |
| 1139 } | 1192 } |
| 1140 | 1193 |
| 1141 void partitionDumpStatsGeneric(PartitionRootGeneric* partition, const char* part itionName, PartitionStatsDumper* partitionStatsDumper) | 1194 static void partitionGenericBucketWalk(PartitionBucketMemoryStats* statsOut, Par titionRootGeneric* partition, bool discardMemory) |
| 1142 { | 1195 { |
| 1143 PartitionBucketMemoryStats bucketStats[kGenericNumBuckets]; | |
| 1144 spinLockLock(&partition->lock); | |
| 1145 for (size_t i = 0; i < kGenericNumBuckets; ++i) { | 1196 for (size_t i = 0; i < kGenericNumBuckets; ++i) { |
| 1146 const PartitionBucket* bucket = &partition->buckets[i]; | 1197 const PartitionBucket* bucket = &partition->buckets[i]; |
| 1147 // Don't report the pseudo buckets that the generic allocator sets up in | 1198 // Don't report the pseudo buckets that the generic allocator sets up in |
| 1148 // order to preserve a fast size->bucket map (see | 1199 // order to preserve a fast size->bucket map (see |
| 1149 // partitionAllocGenericInit for details). | 1200 // partitionAllocGenericInit for details). |
| 1150 if (!bucket->activePagesHead) | 1201 if (!bucket->activePagesHead) |
| 1151 bucketStats[i].isValid = false; | 1202 statsOut[i].isValid = false; |
| 1152 else | 1203 else |
| 1153 partitionDumpBucketStats(&bucketStats[i], bucket); | 1204 partitionDumpBucketStats(&statsOut[i], bucket, discardMemory); |
| 1154 } | 1205 } |
| 1206 } | |
| 1155 | 1207 |
| 1208 void partitionPurgeMemory(PartitionRoot* root, int flags) | |
| 1209 { | |
| 1210 if (flags & PartitionPurgeDecommitEmptyPages) | |
| 1211 partitionDecommitEmptyPages(root); | |
|
haraken
2015/06/22 03:36:59
The reason you don't call partitionGenericBucketWa
| |
| 1212 } | |
| 1213 | |
| 1214 void partitionPurgeMemoryGeneric(PartitionRootGeneric* root, int flags) | |
| 1215 { | |
| 1216 spinLockLock(&root->lock); | |
| 1217 if (flags & PartitionPurgeDecommitEmptyPages) | |
| 1218 partitionDecommitEmptyPages(root); | |
| 1219 if (flags & PartitionPurgeDiscardUnusedSystemPages) { | |
| 1220 PartitionBucketMemoryStats bucketStats[kGenericNumBuckets]; | |
|
haraken
2015/06/22 03:36:58
It is redundant to prepare an array of dummy bucke
| |
| 1221 partitionGenericBucketWalk(bucketStats, root, true); | |
|
haraken
2015/06/22 03:36:58
Or you can pass a nullptr to statsOut and remove t
| |
| 1222 } | |
| 1223 spinLockUnlock(&root->lock); | |
| 1224 } | |
| 1225 | |
| 1226 void partitionDumpStatsGeneric(PartitionRootGeneric* partition, const char* part itionName, PartitionStatsDumper* partitionStatsDumper) | |
| 1227 { | |
| 1228 PartitionBucketMemoryStats bucketStats[kGenericNumBuckets]; | |
| 1156 static const size_t kMaxReportableDirectMaps = 4096; | 1229 static const size_t kMaxReportableDirectMaps = 4096; |
| 1157 uint32_t directMapLengths[kMaxReportableDirectMaps]; | 1230 uint32_t directMapLengths[kMaxReportableDirectMaps]; |
| 1158 size_t numDirectMappedAllocations = 0; | 1231 size_t numDirectMappedAllocations = 0; |
| 1232 | |
| 1233 spinLockLock(&partition->lock); | |
| 1234 | |
| 1235 partitionGenericBucketWalk(bucketStats, partition, false); | |
| 1236 | |
| 1159 for (PartitionDirectMapExtent* extent = partition->directMapList; extent; ex tent = extent->nextExtent) { | 1237 for (PartitionDirectMapExtent* extent = partition->directMapList; extent; ex tent = extent->nextExtent) { |
| 1160 ASSERT(!extent->nextExtent || extent->nextExtent->prevExtent == extent); | 1238 ASSERT(!extent->nextExtent || extent->nextExtent->prevExtent == extent); |
| 1161 directMapLengths[numDirectMappedAllocations] = extent->bucket->slotSize; | 1239 directMapLengths[numDirectMappedAllocations] = extent->bucket->slotSize; |
| 1162 ++numDirectMappedAllocations; | 1240 ++numDirectMappedAllocations; |
| 1163 if (numDirectMappedAllocations == kMaxReportableDirectMaps) | 1241 if (numDirectMappedAllocations == kMaxReportableDirectMaps) |
| 1164 break; | 1242 break; |
| 1165 } | 1243 } |
| 1166 | 1244 |
| 1167 spinLockUnlock(&partition->lock); | 1245 spinLockUnlock(&partition->lock); |
| 1168 | 1246 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 1189 } | 1267 } |
| 1190 | 1268 |
| 1191 void partitionDumpStats(PartitionRoot* partition, const char* partitionName, Par titionStatsDumper* partitionStatsDumper) | 1269 void partitionDumpStats(PartitionRoot* partition, const char* partitionName, Par titionStatsDumper* partitionStatsDumper) |
| 1192 { | 1270 { |
| 1193 static const size_t kMaxReportableBuckets = 4096 / sizeof(void*); | 1271 static const size_t kMaxReportableBuckets = 4096 / sizeof(void*); |
| 1194 PartitionBucketMemoryStats memoryStats[kMaxReportableBuckets]; | 1272 PartitionBucketMemoryStats memoryStats[kMaxReportableBuckets]; |
| 1195 const size_t partitionNumBuckets = partition->numBuckets; | 1273 const size_t partitionNumBuckets = partition->numBuckets; |
| 1196 ASSERT(partitionNumBuckets <= kMaxReportableBuckets); | 1274 ASSERT(partitionNumBuckets <= kMaxReportableBuckets); |
| 1197 | 1275 |
| 1198 for (size_t i = 0; i < partitionNumBuckets; ++i) | 1276 for (size_t i = 0; i < partitionNumBuckets; ++i) |
| 1199 partitionDumpBucketStats(&memoryStats[i], &partition->buckets()[i]); | 1277 partitionDumpBucketStats(&memoryStats[i], &partition->buckets()[i], fals e); |
| 1200 | 1278 |
| 1201 // partitionsDumpBucketStats is called after collecting stats because it | 1279 // partitionsDumpBucketStats is called after collecting stats because it |
| 1202 // can use PartitionAlloc to allocate and this can affect the statistics. | 1280 // can use PartitionAlloc to allocate and this can affect the statistics. |
| 1203 for (size_t i = 0; i < partitionNumBuckets; ++i) { | 1281 for (size_t i = 0; i < partitionNumBuckets; ++i) { |
| 1204 if (memoryStats[i].isValid) | 1282 if (memoryStats[i].isValid) |
| 1205 partitionStatsDumper->partitionsDumpBucketStats(partitionName, &memo ryStats[i]); | 1283 partitionStatsDumper->partitionsDumpBucketStats(partitionName, &memo ryStats[i]); |
| 1206 } | 1284 } |
| 1207 } | 1285 } |
| 1208 | 1286 |
| 1209 } // namespace WTF | 1287 } // namespace WTF |
| 1210 | 1288 |
| OLD | NEW |