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

Side by Side Diff: runtime/vm/freelist.cc

Issue 2872883003: Avoid scanning huge freelists for large enough free blocks. (Closed)
Patch Set: Rename test file Created 3 years, 7 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
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/freelist.h" 5 #include "vm/freelist.h"
6 6
7 #include "vm/bit_set.h" 7 #include "vm/bit_set.h"
8 #include "vm/hash_map.h" 8 #include "vm/hash_map.h"
9 #include "vm/lockers.h" 9 #include "vm/lockers.h"
10 #include "vm/object.h" 10 #include "vm/object.h"
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 ASSERT(OFFSET_OF(FreeListElement, tags_) == Object::tags_offset()); 44 ASSERT(OFFSET_OF(FreeListElement, tags_) == Object::tags_offset());
45 } 45 }
46 46
47 47
48 intptr_t FreeListElement::HeaderSizeFor(intptr_t size) { 48 intptr_t FreeListElement::HeaderSizeFor(intptr_t size) {
49 if (size == 0) return 0; 49 if (size == 0) return 0;
50 return ((size > RawObject::SizeTag::kMaxSizeTag) ? 3 : 2) * kWordSize; 50 return ((size > RawObject::SizeTag::kMaxSizeTag) ? 3 : 2) * kWordSize;
51 } 51 }
52 52
53 53
54 FreeList::FreeList() : mutex_(new Mutex()) { 54 FreeList::FreeList()
55 : mutex_(new Mutex()), freelist_health_(kMaxFreelistHealth) {
55 Reset(); 56 Reset();
56 } 57 }
57 58
58 59
59 FreeList::~FreeList() { 60 FreeList::~FreeList() {
60 delete mutex_; 61 delete mutex_;
61 } 62 }
62 63
63 64
64 uword FreeList::TryAllocate(intptr_t size, bool is_protected) { 65 uword FreeList::TryAllocate(intptr_t size, bool is_protected) {
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
104 region_size, VirtualMemory::kReadWrite); 105 region_size, VirtualMemory::kReadWrite);
105 ASSERT(status); 106 ASSERT(status);
106 } 107 }
107 SplitElementAfterAndEnqueue(element, size, is_protected); 108 SplitElementAfterAndEnqueue(element, size, is_protected);
108 return reinterpret_cast<uword>(element); 109 return reinterpret_cast<uword>(element);
109 } 110 }
110 } 111 }
111 112
112 FreeListElement* previous = NULL; 113 FreeListElement* previous = NULL;
113 FreeListElement* current = free_lists_[kNumLists]; 114 FreeListElement* current = free_lists_[kNumLists];
115 // We are willing to search the freelist further for a big block.
116 intptr_t tries_left = freelist_health_ + (size >> kWordSizeLog2);
kustermann 2017/05/10 21:39:40 Maybe add a more elaborate comment explaining what
114 while (current != NULL) { 117 while (current != NULL) {
115 if (current->Size() >= size) { 118 if (current->Size() >= size) {
116 // Found an element large enough to hold the requested size. Dequeue, 119 // Found an element large enough to hold the requested size. Dequeue,
117 // split and enqueue the remainder. 120 // split and enqueue the remainder.
118 intptr_t remainder_size = current->Size() - size; 121 intptr_t remainder_size = current->Size() - size;
119 intptr_t region_size = 122 intptr_t region_size =
120 size + FreeListElement::HeaderSizeFor(remainder_size); 123 size + FreeListElement::HeaderSizeFor(remainder_size);
121 if (is_protected) { 124 if (is_protected) {
122 // Make the allocated block and the header of the remainder element 125 // Make the allocated block and the header of the remainder element
123 // writable. The remainder will be non-writable if necessary after 126 // writable. The remainder will be non-writable if necessary after
(...skipping 28 matching lines...) Expand all
152 } 155 }
153 previous->set_next(current->next()); 156 previous->set_next(current->next());
154 if (target_is_protected) { 157 if (target_is_protected) {
155 bool status = 158 bool status =
156 VirtualMemory::Protect(reinterpret_cast<void*>(target_address), 159 VirtualMemory::Protect(reinterpret_cast<void*>(target_address),
157 kWordSize, VirtualMemory::kReadExecute); 160 kWordSize, VirtualMemory::kReadExecute);
158 ASSERT(status); 161 ASSERT(status);
159 } 162 }
160 } 163 }
161 SplitElementAfterAndEnqueue(current, size, is_protected); 164 SplitElementAfterAndEnqueue(current, size, is_protected);
165 freelist_health_ = Utils::Minimum(tries_left, kMaxFreelistHealth);
kustermann 2017/05/10 21:39:40 The Utils::Minimum is only for reducing allocation
162 return reinterpret_cast<uword>(current); 166 return reinterpret_cast<uword>(current);
167 } else if (tries_left-- < 0) {
168 freelist_health_ = kMaxFreelistHealth;
169 return 0; // Trigger allocation of new page.
163 } 170 }
164 previous = current; 171 previous = current;
165 current = current->next(); 172 current = current->next();
166 } 173 }
167 return 0; 174 return 0;
168 } 175 }
169 176
170 177
171 void FreeList::Free(uword addr, intptr_t size) { 178 void FreeList::Free(uword addr, intptr_t size) {
172 MutexLocker ml(mutex_); 179 MutexLocker ml(mutex_);
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after
375 MutexLocker ml(mutex_); 382 MutexLocker ml(mutex_);
376 return TryAllocateLargeLocked(minimum_size); 383 return TryAllocateLargeLocked(minimum_size);
377 } 384 }
378 385
379 386
380 FreeListElement* FreeList::TryAllocateLargeLocked(intptr_t minimum_size) { 387 FreeListElement* FreeList::TryAllocateLargeLocked(intptr_t minimum_size) {
381 DEBUG_ASSERT(mutex_->IsOwnedByCurrentThread()); 388 DEBUG_ASSERT(mutex_->IsOwnedByCurrentThread());
382 FreeListElement* previous = NULL; 389 FreeListElement* previous = NULL;
383 FreeListElement* current = free_lists_[kNumLists]; 390 FreeListElement* current = free_lists_[kNumLists];
384 // TODO(koda): Find largest. 391 // TODO(koda): Find largest.
392 // We are willing to search the freelist further for a big block.
393 intptr_t tries_left = freelist_health_ + (minimum_size >> kWordSizeLog2);
385 while (current != NULL) { 394 while (current != NULL) {
386 FreeListElement* next = current->next(); 395 FreeListElement* next = current->next();
387 if (current->Size() >= minimum_size) { 396 if (current->Size() >= minimum_size) {
388 if (previous == NULL) { 397 if (previous == NULL) {
389 free_lists_[kNumLists] = next; 398 free_lists_[kNumLists] = next;
390 } else { 399 } else {
391 previous->set_next(next); 400 previous->set_next(next);
392 } 401 }
402 freelist_health_ = Utils::Minimum(tries_left, kMaxFreelistHealth);
393 return current; 403 return current;
404 } else if (tries_left-- < 0) {
405 freelist_health_ = kMaxFreelistHealth;
406 return 0; // Trigger allocation of new page.
394 } 407 }
395 previous = current; 408 previous = current;
396 current = next; 409 current = next;
397 } 410 }
398 return NULL; 411 return NULL;
399 } 412 }
400 413
401 414
402 uword FreeList::TryAllocateSmallLocked(intptr_t size) { 415 uword FreeList::TryAllocateSmallLocked(intptr_t size) {
403 DEBUG_ASSERT(mutex_->IsOwnedByCurrentThread()); 416 DEBUG_ASSERT(mutex_->IsOwnedByCurrentThread());
404 if (size > last_free_small_size_) { 417 if (size > last_free_small_size_) {
405 return 0; 418 return 0;
406 } 419 }
407 int index = IndexForSize(size); 420 int index = IndexForSize(size);
408 if (index != kNumLists && free_map_.Test(index)) { 421 if (index != kNumLists && free_map_.Test(index)) {
409 return reinterpret_cast<uword>(DequeueElement(index)); 422 return reinterpret_cast<uword>(DequeueElement(index));
410 } 423 }
411 if ((index + 1) < kNumLists) { 424 if ((index + 1) < kNumLists) {
412 intptr_t next_index = free_map_.Next(index + 1); 425 intptr_t next_index = free_map_.Next(index + 1);
413 if (next_index != -1) { 426 if (next_index != -1) {
414 FreeListElement* element = DequeueElement(next_index); 427 FreeListElement* element = DequeueElement(next_index);
415 SplitElementAfterAndEnqueue(element, size, false); 428 SplitElementAfterAndEnqueue(element, size, false);
416 return reinterpret_cast<uword>(element); 429 return reinterpret_cast<uword>(element);
417 } 430 }
418 } 431 }
419 return 0; 432 return 0;
420 } 433 }
421 434
422 } // namespace dart 435 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698