OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // The eviction policy is a very simple pure LRU, so the elements at the end of | 5 // The eviction policy is a very simple pure LRU, so the elements at the end of |
6 // the list are evicted until kCleanUpMargin free space is available. There is | 6 // the list are evicted until kCleanUpMargin free space is available. There is |
7 // only one list in use (Rankings::NO_USE), and elements are sent to the front | 7 // only one list in use (Rankings::NO_USE), and elements are sent to the front |
8 // of the list whenever they are accessed. | 8 // of the list whenever they are accessed. |
9 | 9 |
10 // The new (in-development) eviction policy adds re-use as a factor to evict | 10 // The new (in-development) eviction policy adds re-use as a factor to evict |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 #define CACHE_UMA_BACKEND_IMPL_OBJ backend_ | 43 #define CACHE_UMA_BACKEND_IMPL_OBJ backend_ |
44 | 44 |
45 using base::Time; | 45 using base::Time; |
46 using base::TimeTicks; | 46 using base::TimeTicks; |
47 | 47 |
48 namespace { | 48 namespace { |
49 | 49 |
50 const int kCleanUpMargin = 1024 * 1024; | 50 const int kCleanUpMargin = 1024 * 1024; |
51 | 51 |
52 #if defined(V3_NOT_JUST_YET_READY) | 52 #if defined(V3_NOT_JUST_YET_READY) |
53 const int kHighUse = 10; // Reuse count to be on the HIGH_USE list. | 53 const int kHighUse = 10; // Reuse count to be on the HIGH_USE list. |
54 const int kTargetTime = 24 * 7; // Time to be evicted (hours since last use). | 54 const int kTargetTime = 24 * 7; // Time to be evicted (hours since last use). |
55 const int kMaxDelayedTrims = 60; | 55 const int kMaxDelayedTrims = 60; |
56 #endif // defined(V3_NOT_JUST_YET_READY). | 56 #endif // defined(V3_NOT_JUST_YET_READY). |
57 | 57 |
58 int LowWaterAdjust(int high_water) { | 58 int LowWaterAdjust(int high_water) { |
59 if (high_water < kCleanUpMargin) | 59 if (high_water < kCleanUpMargin) |
60 return 0; | 60 return 0; |
61 | 61 |
62 return high_water - kCleanUpMargin; | 62 return high_water - kCleanUpMargin; |
63 } | 63 } |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
261 trim_delays_ = 0; | 261 trim_delays_ = 0; |
262 return true; | 262 return true; |
263 } | 263 } |
264 | 264 |
265 bool EvictionV3::ShouldTrimDeleted() { | 265 bool EvictionV3::ShouldTrimDeleted() { |
266 int index_load = header_->num_entries * 100 / index_size_; | 266 int index_load = header_->num_entries * 100 / index_size_; |
267 | 267 |
268 // If the index is not loaded, the deleted list will tend to double the size | 268 // If the index is not loaded, the deleted list will tend to double the size |
269 // of the other lists 3 lists (40% of the total). Otherwise, all lists will be | 269 // of the other lists 3 lists (40% of the total). Otherwise, all lists will be |
270 // about the same size. | 270 // about the same size. |
271 int max_length = (index_load < 25) ? header_->num_entries * 2 / 5 : | 271 int max_length = (index_load < 25) ? header_->num_entries * 2 / 5 |
272 header_->num_entries / 4; | 272 : header_->num_entries / 4; |
273 return (!test_mode_ && header_->lru.sizes[Rankings::DELETED] > max_length); | 273 return (!test_mode_ && header_->lru.sizes[Rankings::DELETED] > max_length); |
274 } | 274 } |
275 | 275 |
276 bool Eviction::EvictEntry(CacheRankingsBlock* node, bool empty, | 276 bool Eviction::EvictEntry(CacheRankingsBlock* node, |
| 277 bool empty, |
277 Rankings::List list) { | 278 Rankings::List list) { |
278 EntryImplV3* entry = backend_->GetEnumeratedEntry(node, list); | 279 EntryImplV3* entry = backend_->GetEnumeratedEntry(node, list); |
279 if (!entry) { | 280 if (!entry) { |
280 Trace("NewEntry failed on Trim 0x%x", node->address().value()); | 281 Trace("NewEntry failed on Trim 0x%x", node->address().value()); |
281 return false; | 282 return false; |
282 } | 283 } |
283 | 284 |
284 ReportTrimTimes(entry); | 285 ReportTrimTimes(entry); |
285 if (empty || !new_eviction_) { | 286 if (empty || !new_eviction_) { |
286 entry->DoomImpl(); | 287 entry->DoomImpl(); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
335 int deleted_entries = 0; | 336 int deleted_entries = 0; |
336 int target_size = empty ? 0 : max_size_; | 337 int target_size = empty ? 0 : max_size_; |
337 | 338 |
338 for (; list < kListsToSearch; list++) { | 339 for (; list < kListsToSearch; list++) { |
339 while ((header_->num_bytes > target_size || test_mode_) && | 340 while ((header_->num_bytes > target_size || test_mode_) && |
340 next[list].get()) { | 341 next[list].get()) { |
341 // The iterator could be invalidated within EvictEntry(). | 342 // The iterator could be invalidated within EvictEntry(). |
342 if (!next[list]->HasData()) | 343 if (!next[list]->HasData()) |
343 break; | 344 break; |
344 node.reset(next[list].release()); | 345 node.reset(next[list].release()); |
345 next[list].reset(rankings_->GetPrev(node.get(), | 346 next[list].reset( |
346 static_cast<Rankings::List>(list))); | 347 rankings_->GetPrev(node.get(), static_cast<Rankings::List>(list))); |
347 if (node->Data()->dirty != backend_->GetCurrentEntryId() || empty) { | 348 if (node->Data()->dirty != backend_->GetCurrentEntryId() || empty) { |
348 // This entry is not being used by anybody. | 349 // This entry is not being used by anybody. |
349 // Do NOT use node as an iterator after this point. | 350 // Do NOT use node as an iterator after this point. |
350 rankings_->TrackRankingsBlock(node.get(), false); | 351 rankings_->TrackRankingsBlock(node.get(), false); |
351 if (EvictEntry(node.get(), empty, static_cast<Rankings::List>(list))) | 352 if (EvictEntry(node.get(), empty, static_cast<Rankings::List>(list))) |
352 deleted_entries++; | 353 deleted_entries++; |
353 | 354 |
354 if (!empty && test_mode_) | 355 if (!empty && test_mode_) |
355 break; | 356 break; |
356 } | 357 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
389 // This is a minimal implementation that just discards the oldest nodes. | 390 // This is a minimal implementation that just discards the oldest nodes. |
390 // TODO(rvargas): Do something better here. | 391 // TODO(rvargas): Do something better here. |
391 void EvictionV3::TrimDeleted(bool empty) { | 392 void EvictionV3::TrimDeleted(bool empty) { |
392 Trace("*** Trim Deleted ***"); | 393 Trace("*** Trim Deleted ***"); |
393 if (backend_->disabled_) | 394 if (backend_->disabled_) |
394 return; | 395 return; |
395 | 396 |
396 TimeTicks start = TimeTicks::Now(); | 397 TimeTicks start = TimeTicks::Now(); |
397 Rankings::ScopedRankingsBlock node(rankings_); | 398 Rankings::ScopedRankingsBlock node(rankings_); |
398 Rankings::ScopedRankingsBlock next( | 399 Rankings::ScopedRankingsBlock next( |
399 rankings_, rankings_->GetPrev(node.get(), Rankings::DELETED)); | 400 rankings_, rankings_->GetPrev(node.get(), Rankings::DELETED)); |
400 int deleted_entries = 0; | 401 int deleted_entries = 0; |
401 while (next.get() && | 402 while (next.get() && |
402 (empty || (deleted_entries < 20 && | 403 (empty || (deleted_entries < 20 && |
403 (TimeTicks::Now() - start).InMilliseconds() < 20))) { | 404 (TimeTicks::Now() - start).InMilliseconds() < 20))) { |
404 node.reset(next.release()); | 405 node.reset(next.release()); |
405 next.reset(rankings_->GetPrev(node.get(), Rankings::DELETED)); | 406 next.reset(rankings_->GetPrev(node.get(), Rankings::DELETED)); |
406 if (RemoveDeletedNode(node.get())) | 407 if (RemoveDeletedNode(node.get())) |
407 deleted_entries++; | 408 deleted_entries++; |
408 if (test_mode_) | 409 if (test_mode_) |
409 break; | 410 break; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
455 | 456 |
456 // If possible, we want to keep entries on each list at least kTargetTime | 457 // If possible, we want to keep entries on each list at least kTargetTime |
457 // hours. Each successive list on the enumeration has 2x the target time of | 458 // hours. Each successive list on the enumeration has 2x the target time of |
458 // the previous list. | 459 // the previous list. |
459 Time used = Time::FromInternalValue(node->Data()->last_used); | 460 Time used = Time::FromInternalValue(node->Data()->last_used); |
460 int multiplier = 1 << list; | 461 int multiplier = 1 << list; |
461 return (Time::Now() - used).InHours() > kTargetTime * multiplier; | 462 return (Time::Now() - used).InHours() > kTargetTime * multiplier; |
462 } | 463 } |
463 | 464 |
464 int EvictionV3::SelectListByLength(Rankings::ScopedRankingsBlock* next) { | 465 int EvictionV3::SelectListByLength(Rankings::ScopedRankingsBlock* next) { |
465 int data_entries = header_->num_entries - | 466 int data_entries = |
466 header_->lru.sizes[Rankings::DELETED]; | 467 header_->num_entries - header_->lru.sizes[Rankings::DELETED]; |
467 // Start by having each list to be roughly the same size. | 468 // Start by having each list to be roughly the same size. |
468 if (header_->lru.sizes[0] > data_entries / 3) | 469 if (header_->lru.sizes[0] > data_entries / 3) |
469 return 0; | 470 return 0; |
470 | 471 |
471 int list = (header_->lru.sizes[1] > data_entries / 3) ? 1 : 2; | 472 int list = (header_->lru.sizes[1] > data_entries / 3) ? 1 : 2; |
472 | 473 |
473 // Make sure that frequently used items are kept for a minimum time; we know | 474 // Make sure that frequently used items are kept for a minimum time; we know |
474 // that this entry is not older than its current target, but it must be at | 475 // that this entry is not older than its current target, but it must be at |
475 // least older than the target for list 0 (kTargetTime), as long as we don't | 476 // least older than the target for list 0 (kTargetTime), as long as we don't |
476 // exhaust list 0. | 477 // exhaust list 0. |
477 if (!NodeIsOldEnough(next[list].get(), 0) && | 478 if (!NodeIsOldEnough(next[list].get(), 0) && |
478 header_->lru.sizes[0] > data_entries / 10) | 479 header_->lru.sizes[0] > data_entries / 10) |
479 list = 0; | 480 list = 0; |
480 | 481 |
481 return list; | 482 return list; |
482 } | 483 } |
483 | 484 |
484 void EvictionV3::ReportListStats() { | 485 void EvictionV3::ReportListStats() { |
485 if (!new_eviction_) | 486 if (!new_eviction_) |
486 return; | 487 return; |
487 | 488 |
488 Rankings::ScopedRankingsBlock last1(rankings_, | 489 Rankings::ScopedRankingsBlock last1( |
489 rankings_->GetPrev(NULL, Rankings::NO_USE)); | 490 rankings_, rankings_->GetPrev(NULL, Rankings::NO_USE)); |
490 Rankings::ScopedRankingsBlock last2(rankings_, | 491 Rankings::ScopedRankingsBlock last2( |
491 rankings_->GetPrev(NULL, Rankings::LOW_USE)); | 492 rankings_, rankings_->GetPrev(NULL, Rankings::LOW_USE)); |
492 Rankings::ScopedRankingsBlock last3(rankings_, | 493 Rankings::ScopedRankingsBlock last3( |
493 rankings_->GetPrev(NULL, Rankings::HIGH_USE)); | 494 rankings_, rankings_->GetPrev(NULL, Rankings::HIGH_USE)); |
494 Rankings::ScopedRankingsBlock last4(rankings_, | 495 Rankings::ScopedRankingsBlock last4( |
495 rankings_->GetPrev(NULL, Rankings::DELETED)); | 496 rankings_, rankings_->GetPrev(NULL, Rankings::DELETED)); |
496 | 497 |
497 if (last1.get()) | 498 if (last1.get()) |
498 CACHE_UMA(AGE, "NoUseAge", 0, | 499 CACHE_UMA(AGE, |
| 500 "NoUseAge", |
| 501 0, |
499 Time::FromInternalValue(last1.get()->Data()->last_used)); | 502 Time::FromInternalValue(last1.get()->Data()->last_used)); |
500 if (last2.get()) | 503 if (last2.get()) |
501 CACHE_UMA(AGE, "LowUseAge", 0, | 504 CACHE_UMA(AGE, |
| 505 "LowUseAge", |
| 506 0, |
502 Time::FromInternalValue(last2.get()->Data()->last_used)); | 507 Time::FromInternalValue(last2.get()->Data()->last_used)); |
503 if (last3.get()) | 508 if (last3.get()) |
504 CACHE_UMA(AGE, "HighUseAge", 0, | 509 CACHE_UMA(AGE, |
| 510 "HighUseAge", |
| 511 0, |
505 Time::FromInternalValue(last3.get()->Data()->last_used)); | 512 Time::FromInternalValue(last3.get()->Data()->last_used)); |
506 if (last4.get()) | 513 if (last4.get()) |
507 CACHE_UMA(AGE, "DeletedAge", 0, | 514 CACHE_UMA(AGE, |
| 515 "DeletedAge", |
| 516 0, |
508 Time::FromInternalValue(last4.get()->Data()->last_used)); | 517 Time::FromInternalValue(last4.get()->Data()->last_used)); |
509 } | 518 } |
510 #endif // defined(V3_NOT_JUST_YET_READY). | 519 #endif // defined(V3_NOT_JUST_YET_READY). |
511 | 520 |
512 } // namespace disk_cache | 521 } // namespace disk_cache |
OLD | NEW |