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

Side by Side Diff: Source/core/loader/cache/MemoryCache.cpp

Issue 19393004: Allow eviction of ImageBitmaps that are created from ImageElements. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Use CachedImage as the backing store for ImageBitmap. Implement O(1) decode cache. Created 7 years, 5 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
OLDNEW
1 /* 1 /*
2 Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de) 2 Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
3 Copyright (C) 2001 Dirk Mueller (mueller@kde.org) 3 Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
4 Copyright (C) 2002 Waldo Bastian (bastian@kde.org) 4 Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
5 Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. 5 Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
6 6
7 This library is free software; you can redistribute it and/or 7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public 8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either 9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version. 10 version 2 of the License, or (at your option) any later version.
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 #include "wtf/TemporaryChange.h" 45 #include "wtf/TemporaryChange.h"
46 #include "wtf/text/CString.h" 46 #include "wtf/text/CString.h"
47 47
48 using namespace std; 48 using namespace std;
49 49
50 namespace WebCore { 50 namespace WebCore {
51 51
52 static MemoryCache* gMemoryCache; 52 static MemoryCache* gMemoryCache;
53 53
54 static const int cDefaultCacheCapacity = 8192 * 1024; 54 static const int cDefaultCacheCapacity = 8192 * 1024;
55 static const double cMinDelayBeforeLiveDecodedPrune = 1; // Seconds.
Justin Novosad 2013/07/23 16:55:12 This variable should still exist, but it should be
56 static const float cTargetPrunePercentage = .95f; // Percentage of capacity towa rd which we prune, to avoid immediately pruning again. 55 static const float cTargetPrunePercentage = .95f; // Percentage of capacity towa rd which we prune, to avoid immediately pruning again.
57 static const double cDefaultDecodedDataDeletionInterval = 0; 56 static const double cDefaultDecodedDataDeletionInterval = 0;
58 57
59 MemoryCache* memoryCache() 58 MemoryCache* memoryCache()
60 { 59 {
61 ASSERT(WTF::isMainThread()); 60 ASSERT(WTF::isMainThread());
62 if (!gMemoryCache) 61 if (!gMemoryCache)
63 gMemoryCache = new MemoryCache(); 62 gMemoryCache = new MemoryCache();
64 return gMemoryCache; 63 return gMemoryCache;
65 } 64 }
66 65
67 void setMemoryCacheForTesting(MemoryCache* memoryCache) 66 void setMemoryCacheForTesting(MemoryCache* memoryCache)
68 { 67 {
69 gMemoryCache = memoryCache; 68 gMemoryCache = memoryCache;
70 } 69 }
71 70
72 MemoryCache::MemoryCache() 71 MemoryCache::MemoryCache()
73 : m_inPruneResources(false) 72 : m_inPruneResources(false)
74 , m_capacity(cDefaultCacheCapacity) 73 , m_capacity(cDefaultCacheCapacity)
75 , m_minDeadCapacity(0) 74 , m_minDeadCapacity(0)
76 , m_maxDeadCapacity(cDefaultCacheCapacity) 75 , m_maxDeadCapacity(cDefaultCacheCapacity)
77 , m_deadDecodedDataDeletionInterval(cDefaultDecodedDataDeletionInterval) 76 , m_deadDecodedDataDeletionInterval(cDefaultDecodedDataDeletionInterval)
78 , m_liveSize(0) 77 , m_liveSize(0)
79 , m_deadSize(0) 78 , m_deadSize(0)
79 , m_delayBeforeLiveDecodedPrune(1) // Seconds.
80 #ifdef MEMORY_CACHE_STATS 80 #ifdef MEMORY_CACHE_STATS
81 , m_statsTimer(this, &MemoryCache::dumpStats) 81 , m_statsTimer(this, &MemoryCache::dumpStats)
82 #endif 82 #endif
83 { 83 {
84 #ifdef MEMORY_CACHE_STATS 84 #ifdef MEMORY_CACHE_STATS
85 const double statsIntervalInSeconds = 15; 85 const double statsIntervalInSeconds = 15;
86 m_statsTimer.startRepeating(statsIntervalInSeconds); 86 m_statsTimer.startRepeating(statsIntervalInSeconds);
87 #endif 87 #endif
88 } 88 }
89 89
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
179 { 179 {
180 if (m_inPruneResources) 180 if (m_inPruneResources)
181 return; 181 return;
182 TemporaryChange<bool> reentrancyProtector(m_inPruneResources, true); 182 TemporaryChange<bool> reentrancyProtector(m_inPruneResources, true);
183 183
184 double currentTime = FrameView::currentPaintTimeStamp(); 184 double currentTime = FrameView::currentPaintTimeStamp();
185 if (!currentTime) // In case prune is called directly, outside of a Frame pa int. 185 if (!currentTime) // In case prune is called directly, outside of a Frame pa int.
186 currentTime = WTF::currentTime(); 186 currentTime = WTF::currentTime();
187 187
188 // Destroy any decoded data in live objects that we can. 188 // Destroy any decoded data in live objects that we can.
189 // Start from the tail, since this is the least recently accessed of the obj ects. 189 // Start from the tail, since this is the lowest priority
190 // and least recently accessed of the objects.
190 191
191 // The list might not be sorted by the m_lastDecodedAccessTime. The impact 192 // The list might not be sorted by the m_lastDecodedAccessTime. The impact
192 // of this weaker invariant is minor as the below if statement to check the 193 // of this weaker invariant is minor as the below if statement to check the
193 // elapsedTime will evaluate to false as the currentTime will be a lot 194 // elapsedTime will evaluate to false as the currentTime will be a lot
194 // greater than the current->m_lastDecodedAccessTime. 195 // greater than the current->m_lastDecodedAccessTime.
195 // For more details see: https://bugs.webkit.org/show_bug.cgi?id=30209 196 // For more details see: https://bugs.webkit.org/show_bug.cgi?id=30209
196 CachedResource* current = m_liveDecodedResources.m_tail;
197 while (current) {
198 CachedResource* prev = current->m_prevInLiveResourcesList;
199 ASSERT(current->hasClients());
200 if (current->isLoaded() && current->decodedSize()) {
201 // Check to see if the remaining resources are too new to prune.
202 double elapsedTime = currentTime - current->m_lastDecodedAccessTime;
203 if (elapsedTime < cMinDelayBeforeLiveDecodedPrune)
204 return;
205 197
206 // Destroy our decoded data. This will remove us from 198 // Start pruning from the lowest priority list.
207 // m_liveDecodedResources, and possibly move us to a different LRU 199 for (int i = 0; i < 3; i++) {
208 // list in m_allResources. 200 CachedResource* current = m_liveDecodedResources[i].m_tail;
209 current->destroyDecodedData(); 201 while (current) {
202 CachedResource* prev = current->m_prevInLiveResourcesList;
203 ASSERT(current->hasClients());
204 if (current->isLoaded() && current->decodedSize()) {
205 // Check to see if the remaining resources are too new to prune.
206 double elapsedTime = currentTime - current->m_lastDecodedAccessT ime;
207 if (elapsedTime < m_delayBeforeLiveDecodedPrune)
208 return;
210 209
211 if (targetSize && m_liveSize <= targetSize) 210 // Destroy our decoded data. This will remove us from
212 return; 211 // m_liveDecodedResources, and possibly move us to a different L RU
212 // list in m_allResources.
213 current->destroyDecodedData();
214
215 if (targetSize && m_liveSize <= targetSize)
216 return;
217 }
218 current = prev;
213 } 219 }
214 current = prev;
215 } 220 }
216 } 221 }
217 222
218 void MemoryCache::pruneDeadResources() 223 void MemoryCache::pruneDeadResources()
219 { 224 {
220 unsigned capacity = deadCapacity(); 225 unsigned capacity = deadCapacity();
221 if (capacity && m_deadSize <= capacity) 226 if (capacity && m_deadSize <= capacity)
222 return; 227 return;
223 228
224 unsigned targetSize = static_cast<unsigned>(capacity * cTargetPrunePercentag e); // Cut by a percentage to avoid immediately pruning again. 229 unsigned targetSize = static_cast<unsigned>(capacity * cTargetPrunePercentag e); // Cut by a percentage to avoid immediately pruning again.
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after
432 437
433 } 438 }
434 439
435 void MemoryCache::removeFromLiveDecodedResourcesList(CachedResource* resource) 440 void MemoryCache::removeFromLiveDecodedResourcesList(CachedResource* resource)
436 { 441 {
437 // If we've never been accessed, then we're brand new and not in any list. 442 // If we've never been accessed, then we're brand new and not in any list.
438 if (!resource->m_inLiveDecodedResourcesList) 443 if (!resource->m_inLiveDecodedResourcesList)
439 return; 444 return;
440 resource->m_inLiveDecodedResourcesList = false; 445 resource->m_inLiveDecodedResourcesList = false;
441 446
447 LRUList* list = &m_liveDecodedResources[resource->decodePriority()];
448
442 #if !ASSERT_DISABLED 449 #if !ASSERT_DISABLED
443 // Verify that we are in fact in this list. 450 // Verify that we are in fact in this list.
444 bool found = false; 451 bool found = false;
445 for (CachedResource* current = m_liveDecodedResources.m_head; current; curre nt = current->m_nextInLiveResourcesList) { 452 for (CachedResource* current = list->m_head; current; current = current->m_n extInLiveResourcesList) {
446 if (current == resource) { 453 if (current == resource) {
447 found = true; 454 found = true;
448 break; 455 break;
449 } 456 }
450 } 457 }
451 ASSERT(found); 458 ASSERT(found);
452 #endif 459 #endif
453 460
454 CachedResource* next = resource->m_nextInLiveResourcesList; 461 CachedResource* next = resource->m_nextInLiveResourcesList;
455 CachedResource* prev = resource->m_prevInLiveResourcesList; 462 CachedResource* prev = resource->m_prevInLiveResourcesList;
456 463
457 if (next == 0 && prev == 0 && m_liveDecodedResources.m_head != resource) 464 if (!next && !prev && list->m_head != resource)
458 return; 465 return;
459 466
460 resource->m_nextInLiveResourcesList = 0; 467 resource->m_nextInLiveResourcesList = 0;
461 resource->m_prevInLiveResourcesList = 0; 468 resource->m_prevInLiveResourcesList = 0;
462 469
463 if (next) 470 if (next)
464 next->m_prevInLiveResourcesList = prev; 471 next->m_prevInLiveResourcesList = prev;
465 else if (m_liveDecodedResources.m_tail == resource) 472 else if (list->m_tail == resource)
466 m_liveDecodedResources.m_tail = prev; 473 list->m_tail = prev;
467 474
468 if (prev) 475 if (prev)
469 prev->m_nextInLiveResourcesList = next; 476 prev->m_nextInLiveResourcesList = next;
470 else if (m_liveDecodedResources.m_head == resource) 477 else if (list->m_head == resource)
471 m_liveDecodedResources.m_head = next; 478 list->m_head = next;
472 } 479 }
473 480
474 void MemoryCache::insertInLiveDecodedResourcesList(CachedResource* resource) 481 void MemoryCache::insertInLiveDecodedResourcesList(CachedResource* resource)
475 { 482 {
476 // Make sure we aren't in the list already. 483 // Make sure we aren't in the list already.
477 ASSERT(!resource->m_nextInLiveResourcesList && !resource->m_prevInLiveResour cesList && !resource->m_inLiveDecodedResourcesList); 484 ASSERT(!resource->m_nextInLiveResourcesList && !resource->m_prevInLiveResour cesList && !resource->m_inLiveDecodedResourcesList);
478 resource->m_inLiveDecodedResourcesList = true; 485 resource->m_inLiveDecodedResourcesList = true;
479 486
480 resource->m_nextInLiveResourcesList = m_liveDecodedResources.m_head; 487 LRUList* list = &m_liveDecodedResources[resource->decodePriority()];
481 if (m_liveDecodedResources.m_head) 488 resource->m_nextInLiveResourcesList = list->m_head;
482 m_liveDecodedResources.m_head->m_prevInLiveResourcesList = resource; 489 if (list->m_head)
483 m_liveDecodedResources.m_head = resource; 490 list->m_head->m_prevInLiveResourcesList = resource;
484 491 list->m_head = resource;
492
485 if (!resource->m_nextInLiveResourcesList) 493 if (!resource->m_nextInLiveResourcesList)
486 m_liveDecodedResources.m_tail = resource; 494 list->m_tail = resource;
487 495
488 #if !ASSERT_DISABLED 496 #if !ASSERT_DISABLED
489 // Verify that we are in now in the list like we should be. 497 // Verify that we are in now in the list like we should be.
490 bool found = false; 498 bool found = false;
491 for (CachedResource* current = m_liveDecodedResources.m_head; current; curre nt = current->m_nextInLiveResourcesList) { 499 for (CachedResource* current = list->m_head; current; current = current->m_n extInLiveResourcesList) {
492 if (current == resource) { 500 if (current == resource) {
493 found = true; 501 found = true;
494 break; 502 break;
495 } 503 }
496 } 504 }
497 ASSERT(found); 505 ASSERT(found);
498 #endif 506 #endif
499 507
500 } 508 }
501 509
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
582 } 590 }
583 return stats; 591 return stats;
584 } 592 }
585 593
586 void MemoryCache::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const 594 void MemoryCache::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
587 { 595 {
588 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::MemoryCache Structures); 596 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::MemoryCache Structures);
589 memoryObjectInfo->setClassName("MemoryCache"); 597 memoryObjectInfo->setClassName("MemoryCache");
590 info.addMember(m_resources, "resources"); 598 info.addMember(m_resources, "resources");
591 info.addMember(m_allResources, "allResources"); 599 info.addMember(m_allResources, "allResources");
592 info.addMember(m_liveDecodedResources, "liveDecodedResources"); 600 for (int i = 0; i < 3; ++i)
601 info.addMember(m_liveDecodedResources[i], "liveDecodedResources");
593 for (CachedResourceMap::const_iterator i = m_resources.begin(); i != m_resou rces.end(); ++i) 602 for (CachedResourceMap::const_iterator i = m_resources.begin(); i != m_resou rces.end(); ++i)
594 info.addMember(i->value, "cachedResourceItem", WTF::RetainingPointer); 603 info.addMember(i->value, "cachedResourceItem", WTF::RetainingPointer);
595 } 604 }
596 605
597 void MemoryCache::evictResources() 606 void MemoryCache::evictResources()
598 { 607 {
599 for (;;) { 608 for (;;) {
600 CachedResourceMap::iterator i = m_resources.begin(); 609 CachedResourceMap::iterator i = m_resources.begin();
601 if (i == m_resources.end()) 610 if (i == m_resources.end())
602 break; 611 break;
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
658 printf("(%.1fK, %.1fK, %uA, %dR, %d, %d); ", current->decodedSiz e() / 1024.0f, (current->encodedSize() + current->overheadSize()) / 1024.0f, cur rent->accessCount(), current->hasClients(), current->isPurgeable(), current->was Purged()); 667 printf("(%.1fK, %.1fK, %uA, %dR, %d, %d); ", current->decodedSiz e() / 1024.0f, (current->encodedSize() + current->overheadSize()) / 1024.0f, cur rent->accessCount(), current->hasClients(), current->isPurgeable(), current->was Purged());
659 668
660 current = prev; 669 current = prev;
661 } 670 }
662 } 671 }
663 } 672 }
664 673
665 #endif // MEMORY_CACHE_STATS 674 #endif // MEMORY_CACHE_STATS
666 675
667 } // namespace WebCore 676 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698