Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(290)

Side by Side Diff: Source/wtf/PartitionAlloc.cpp

Issue 26196002: Improve partitionAlloc's resistance to fragmentation. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | Source/wtf/PartitionAllocTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 13 matching lines...) Expand all
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */ 29 */
30 30
31 #include "config.h" 31 #include "config.h"
32 #include "wtf/PartitionAlloc.h" 32 #include "wtf/PartitionAlloc.h"
33 33
34 #include "wtf/PageAllocator.h"
35 #include <string.h> 34 #include <string.h>
36 35
37 #ifndef NDEBUG 36 #ifndef NDEBUG
38 #include <stdio.h> 37 #include <stdio.h>
39 #endif 38 #endif
40 39
41 // A super page is at least 4 partition pages in order to make re-entrancy consi derations simpler in partitionAllocPage(). 40 // A super page is at least 4 partition pages in order to make re-entrancy consi derations simpler in partitionAllocPage().
42 COMPILE_ASSERT(WTF::kPartitionPageSize * 4 <= WTF::kSuperPageSize, ok_partition_ page_size); 41 COMPILE_ASSERT(WTF::kPartitionPageSize * 4 <= WTF::kSuperPageSize, ok_partition_ page_size);
43 COMPILE_ASSERT(!(WTF::kSuperPageSize % WTF::kPartitionPageSize), ok_partition_pa ge_multiple); 42 COMPILE_ASSERT(!(WTF::kSuperPageSize % WTF::kPartitionPageSize), ok_partition_pa ge_multiple);
44 COMPILE_ASSERT(!(WTF::kPartitionPageSize % WTF::kSubPartitionPageSize), ok_sub_p artition_page_multiple); 43 COMPILE_ASSERT(!(WTF::kPartitionPageSize % WTF::kSubPartitionPageSize), ok_sub_p artition_page_multiple);
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after
278 277
279 static ALWAYS_INLINE void partitionUnlinkPage(PartitionPageHeader* page) 278 static ALWAYS_INLINE void partitionUnlinkPage(PartitionPageHeader* page)
280 { 279 {
281 ASSERT(page->prev->next == page); 280 ASSERT(page->prev->next == page);
282 ASSERT(page->next->prev == page); 281 ASSERT(page->next->prev == page);
283 282
284 page->next->prev = page->prev; 283 page->next->prev = page->prev;
285 page->prev->next = page->next; 284 page->prev->next = page->next;
286 } 285 }
287 286
288 static ALWAYS_INLINE void partitionLinkPage(PartitionPageHeader* newPage, Partit ionPageHeader* prevPage) 287 static ALWAYS_INLINE void partitionLinkPageBefore(PartitionPageHeader* newPage, PartitionPageHeader* nextPage)
289 { 288 {
290 ASSERT(prevPage->prev->next == prevPage); 289 ASSERT(nextPage->prev->next == nextPage);
291 ASSERT(prevPage->next->prev == prevPage); 290 ASSERT(nextPage->next->prev == nextPage);
292 291
293 newPage->prev = prevPage; 292 newPage->next = nextPage;
294 newPage->next = prevPage->next; 293 newPage->prev = nextPage->prev;
295 294
296 prevPage->next->prev = newPage; 295 nextPage->prev->next = newPage;
297 prevPage->next = newPage; 296 nextPage->prev = newPage;
298 } 297 }
299 298
300 void* partitionAllocSlowPath(PartitionBucket* bucket) 299 void* partitionAllocSlowPath(PartitionBucket* bucket)
301 { 300 {
302 // The slow path is called when the freelist is empty. 301 // The slow path is called when the freelist is empty.
303 PartitionPageHeader* page = bucket->currPage; 302 PartitionPageHeader* page = bucket->currPage;
304 PartitionPageHeader* next = page->next; 303 PartitionPageHeader* next = page->next;
305 ASSERT(page == &bucket->root->seedPage || (page->bucket == bucket && next->b ucket == bucket)); 304 ASSERT(page == &bucket->root->seedPage || (page->bucket == bucket && next->b ucket == bucket));
306 305
307 // First, see if the partition page still has capacity and if so, fill out 306 // First, see if the current partition page still has capacity and if so,
308 // the freelist a little more. 307 // fill out the freelist a little more.
309 if (LIKELY(page->numUnprovisionedSlots)) 308 if (LIKELY(page->numUnprovisionedSlots))
310 return partitionPageAllocAndFillFreelist(page); 309 return partitionPageAllocAndFillFreelist(page);
311 310
312 // Second, look for a page in our linked ring list of non-full pages. 311 // Second, look for a page in our linked ring list of non-full pages.
313 while (LIKELY(next != page)) { 312 while (LIKELY(next != page)) {
314 ASSERT(next->bucket == bucket); 313 ASSERT(next->bucket == bucket);
315 ASSERT(next->next->prev == next); 314 ASSERT(next->next->prev == next);
316 ASSERT(next->prev->next == next); 315 ASSERT(next->prev->next == next);
317 ASSERT(next != &bucket->root->seedPage); 316 ASSERT(next != &bucket->root->seedPage);
318 if (LIKELY(next->freelistHead != 0)) { 317 if (LIKELY(next->freelistHead != 0)) {
319 bucket->currPage = next; 318 bucket->currPage = next;
320 PartitionFreelistEntry* ret = next->freelistHead; 319 PartitionFreelistEntry* ret = next->freelistHead;
321 next->freelistHead = partitionFreelistMask(ret->next); 320 next->freelistHead = partitionFreelistMask(ret->next);
322 next->numAllocatedSlots++; 321 next->numAllocatedSlots++;
323 return ret; 322 return ret;
324 } 323 }
324 if (LIKELY(next->numUnprovisionedSlots)) {
325 bucket->currPage = next;
326 return partitionPageAllocAndFillFreelist(next);
327 }
325 // Pull this page out of the non-full page list, since it has no free 328 // Pull this page out of the non-full page list, since it has no free
326 // slots. 329 // slots.
327 // This tags the page as full so that free'ing can tell, and move 330 // This tags the page as full so that free'ing can tell, and move
328 // the page back into the non-full page list when appropriate. 331 // the page back into the non-full page list when appropriate.
329 ASSERT(next->numAllocatedSlots == partitionBucketSlots(bucket)); 332 ASSERT(next->numAllocatedSlots == partitionBucketSlots(bucket));
330 next->numAllocatedSlots = -next->numAllocatedSlots; 333 next->numAllocatedSlots = -next->numAllocatedSlots;
331 partitionUnlinkPage(next); 334 partitionUnlinkPage(next);
332 ++bucket->numFullPages; 335 ++bucket->numFullPages;
333 336
334 next = next->next; 337 next = next->next;
335 } 338 }
336 339
337 // Second, look in our list of freed but reserved pages. 340 // After we've considered and rejected every partition page in the list,
341 // we should by definition have a single self-linked page left. We will
342 // replace this single page with the new page we choose.
343 ASSERT(page == page->next);
344 ASSERT(page == page->prev);
345 ASSERT(page == &bucket->root->seedPage || page->numAllocatedSlots == partiti onBucketSlots(bucket));
346 if (LIKELY(page != &bucket->root->seedPage)) {
347 page->numAllocatedSlots = -page->numAllocatedSlots;
348 ++bucket->numFullPages;
349 }
350
351 // Third, look in our list of freed but reserved pages.
338 PartitionPageHeader* newPage; 352 PartitionPageHeader* newPage;
339 PartitionFreepagelistEntry* pagelist = bucket->freePages; 353 PartitionFreepagelistEntry* pagelist = bucket->freePages;
340 if (LIKELY(pagelist != 0)) { 354 if (LIKELY(pagelist != 0)) {
341 newPage = pagelist->page; 355 newPage = pagelist->page;
342 bucket->freePages = pagelist->next; 356 bucket->freePages = pagelist->next;
343 partitionFree(pagelist); 357 partitionFree(pagelist);
344 ASSERT(page != &bucket->root->seedPage); 358 ASSERT(page != &bucket->root->seedPage);
345 partitionLinkPage(newPage, page);
346 } else { 359 } else {
347 // Third. If we get here, we need a brand new page. 360 // Fourth. If we get here, we need a brand new page.
348 newPage = partitionAllocPage(bucket->root); 361 newPage = partitionAllocPage(bucket->root);
349 if (UNLIKELY(page == &bucket->root->seedPage)) {
350 // If this is the first page allocation to this bucket, then
351 // fully replace the seed page. This avoids pointlessly iterating
352 // over it.
353 newPage->prev = newPage;
354 newPage->next = newPage;
355 } else {
356 partitionLinkPage(newPage, page);
357 }
358 } 362 }
359 363
364 newPage->prev = newPage;
365 newPage->next = newPage;
360 bucket->currPage = newPage; 366 bucket->currPage = newPage;
361 partitionPageReset(newPage, bucket); 367 partitionPageReset(newPage, bucket);
362 return partitionPageAllocAndFillFreelist(newPage); 368 return partitionPageAllocAndFillFreelist(newPage);
363 } 369 }
364 370
365 void partitionFreeSlowPath(PartitionPageHeader* page) 371 void partitionFreeSlowPath(PartitionPageHeader* page)
366 { 372 {
367 PartitionBucket* bucket = page->bucket; 373 PartitionBucket* bucket = page->bucket;
368 if (LIKELY(page->numAllocatedSlots == 0)) { 374 if (LIKELY(page->numAllocatedSlots == 0)) {
369 // Page became fully unused. 375 // Page became fully unused.
370 // If it's the current page, leave it be so that we don't bounce a page 376 // If it's the current page, change it!
371 // onto the free page list and immediately back out again. 377 if (LIKELY(page == bucket->currPage)) {
372 if (LIKELY(page == bucket->currPage)) 378 if (UNLIKELY(page->next == page)) {
373 return; 379 // For now, we do not free the last partition page in a bucket.
380 return;
381 }
382 bucket->currPage = page->next;
383 }
374 384
375 partitionUnlinkPage(page); 385 partitionUnlinkPage(page);
376 partitionUnusePage(page); 386 partitionUnusePage(page);
377 PartitionFreepagelistEntry* entry = static_cast<PartitionFreepagelistEnt ry*>(partitionBucketAlloc(&bucket->root->buckets()[kInternalMetadataBucket])); 387 PartitionFreepagelistEntry* entry = static_cast<PartitionFreepagelistEnt ry*>(partitionBucketAlloc(&bucket->root->buckets()[kInternalMetadataBucket]));
378 entry->page = page; 388 entry->page = page;
379 entry->next = bucket->freePages; 389 entry->next = bucket->freePages;
380 bucket->freePages = entry; 390 bucket->freePages = entry;
381 } else { 391 } else {
382 // Fully used page became partially used. It must be put back on the 392 // Fully used page became partially used. It must be put back on the
383 // non-full page list. 393 // non-full page list. Also make it the current page to increase the
384 partitionLinkPage(page, bucket->currPage); 394 // chances of it being filled up again. The old current page will be
395 // the next page.
396 partitionLinkPageBefore(page, bucket->currPage);
397 bucket->currPage = page;
385 page->numAllocatedSlots = -page->numAllocatedSlots - 2; 398 page->numAllocatedSlots = -page->numAllocatedSlots - 2;
386 ASSERT(page->numAllocatedSlots == partitionBucketSlots(bucket) - 1); 399 ASSERT(page->numAllocatedSlots == partitionBucketSlots(bucket) - 1);
387 --bucket->numFullPages; 400 --bucket->numFullPages;
388 } 401 }
389 } 402 }
390 403
391 void* partitionReallocGeneric(PartitionRoot* root, void* ptr, size_t newSize) 404 void* partitionReallocGeneric(PartitionRoot* root, void* ptr, size_t newSize)
392 { 405 {
393 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) 406 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
394 return realloc(ptr, newSize); 407 return realloc(ptr, newSize);
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
472 printf("total live: %ld bytes\n", totalLive); 485 printf("total live: %ld bytes\n", totalLive);
473 printf("total resident: %ld bytes\n", totalResident); 486 printf("total resident: %ld bytes\n", totalResident);
474 printf("total freeable: %ld bytes\n", totalFreeable); 487 printf("total freeable: %ld bytes\n", totalFreeable);
475 fflush(stdout); 488 fflush(stdout);
476 } 489 }
477 490
478 #endif // !NDEBUG 491 #endif // !NDEBUG
479 492
480 } // namespace WTF 493 } // namespace WTF
481 494
OLDNEW
« no previous file with comments | « no previous file | Source/wtf/PartitionAllocTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698