Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Evicting unused cache entries before RasterCache actions #34627

Merged
merged 7 commits into from
Jul 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions flow/frame_timings_recorder_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ TEST(FrameTimingsRecorderTest, RecordRasterTimesWithCache) {
using namespace std::chrono_literals;

MockRasterCache cache(1, 10);
cache.PrepareNewFrame();
cache.BeginFrame();

const auto raster_start = fml::TimePoint::Now();
recorder->RecordRasterStart(raster_start);
Expand All @@ -102,8 +102,9 @@ TEST(FrameTimingsRecorderTest, RecordRasterTimesWithCache) {
cache.AddMockPicture(100, 100);
size_t picture_bytes = cache.EstimatePictureCacheByteSize();
EXPECT_GT(picture_bytes, 0u);
cache.EvictUnusedCacheEntries();

cache.CleanupAfterFrame();
cache.EndFrame();

const auto before_raster_end_wall_time = fml::TimePoint::CurrentWallTime();
std::this_thread::sleep_for(1ms);
Expand Down Expand Up @@ -252,7 +253,7 @@ TEST(FrameTimingsRecorderTest, ClonedHasSameRasterEnd) {
TEST(FrameTimingsRecorderTest, ClonedHasSameRasterEndWithCache) {
auto recorder = std::make_unique<FrameTimingsRecorder>();
MockRasterCache cache(1, 10);
cache.PrepareNewFrame();
cache.BeginFrame();

const auto now = fml::TimePoint::Now();
recorder->RecordVsync(now, now + fml::TimeDelta::FromMilliseconds(16));
Expand All @@ -266,8 +267,8 @@ TEST(FrameTimingsRecorderTest, ClonedHasSameRasterEndWithCache) {
cache.AddMockPicture(100, 100);
size_t picture_bytes = cache.EstimatePictureCacheByteSize();
EXPECT_GT(picture_bytes, 0u);

cache.CleanupAfterFrame();
cache.EvictUnusedCacheEntries();
cache.EndFrame();
recorder->RecordRasterEnd(&cache);

auto cloned = recorder->CloneUntil(FrameTimingsRecorder::State::kRasterEnd);
Expand Down
29 changes: 16 additions & 13 deletions flow/layers/container_layer_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,9 @@ TEST_F(ContainerLayerTest, RasterCacheTest) {
{
// frame1
use_mock_raster_cache();
preroll_context()->raster_cache->PrepareNewFrame();
preroll_context()->raster_cache->BeginFrame();
layer->Preroll(preroll_context(), SkMatrix::I());
preroll_context()->raster_cache->EvictUnusedCacheEntries();
// Cache the cacheable entries
LayerTree::TryToRasterCache(*(preroll_context()->raster_cached_entries),
&paint_context());
Expand Down Expand Up @@ -299,16 +300,17 @@ TEST_F(ContainerLayerTest, RasterCacheTest) {
// render count < 2 don't cache it
EXPECT_EQ(cacheable_container_layer2->raster_cache_item()->cache_state(),
RasterCacheItem::CacheState::kNone);
preroll_context()->raster_cache->CleanupAfterFrame();
preroll_context()->raster_cache->EndFrame();
}

{
// frame2
// new frame the layer tree will create new PrerollContext, so in here we
// clear the cached_entries
preroll_context()->raster_cached_entries->clear();
preroll_context()->raster_cache->PrepareNewFrame();
preroll_context()->raster_cache->BeginFrame();
layer->Preroll(preroll_context(), SkMatrix::I());
preroll_context()->raster_cache->EvictUnusedCacheEntries();

// Cache the cacheable entries
LayerTree::TryToRasterCache(*(preroll_context()->raster_cached_entries),
Expand Down Expand Up @@ -342,17 +344,17 @@ TEST_F(ContainerLayerTest, RasterCacheTest) {
EXPECT_TRUE(raster_cache()->Draw(
cacheable_layer21->raster_cache_item()->GetId().value(), cache_canvas,
&paint));
preroll_context()->raster_cache->CleanupAfterFrame();
preroll_context()->raster_cache->EndFrame();
}

{
// frame3
// new frame the layer tree will create new PrerollContext, so in here we
// clear the cached_entries
preroll_context()->raster_cache->PrepareNewFrame();
preroll_context()->raster_cache->BeginFrame();
preroll_context()->raster_cached_entries->clear();
layer->Preroll(preroll_context(), SkMatrix::I());

preroll_context()->raster_cache->EvictUnusedCacheEntries();
// Cache the cacheable entries
LayerTree::TryToRasterCache(*(preroll_context()->raster_cached_entries),
&paint_context());
Expand Down Expand Up @@ -385,33 +387,34 @@ TEST_F(ContainerLayerTest, RasterCacheTest) {
EXPECT_TRUE(raster_cache()->HasEntry(
cacheable_layer21->raster_cache_item()->GetId().value(),
SkMatrix::I()));
preroll_context()->raster_cache->CleanupAfterFrame();
preroll_context()->raster_cache->EndFrame();
}

{
preroll_context()->raster_cache->PrepareNewFrame();
preroll_context()->raster_cache->BeginFrame();
// frame4
preroll_context()->raster_cached_entries->clear();
layer->Preroll(preroll_context(), SkMatrix::I());
preroll_context()->raster_cache->EvictUnusedCacheEntries();
LayerTree::TryToRasterCache(*(preroll_context()->raster_cached_entries),
&paint_context());
preroll_context()->raster_cache->CleanupAfterFrame();
preroll_context()->raster_cache->EndFrame();

// frame5
preroll_context()->raster_cache->PrepareNewFrame();
preroll_context()->raster_cache->BeginFrame();
preroll_context()->raster_cached_entries->clear();
layer->Preroll(preroll_context(), SkMatrix::I());
LayerTree::TryToRasterCache(*(preroll_context()->raster_cached_entries),
&paint_context());
preroll_context()->raster_cache->CleanupAfterFrame();
preroll_context()->raster_cache->EndFrame();

// frame6
preroll_context()->raster_cache->PrepareNewFrame();
preroll_context()->raster_cache->BeginFrame();
preroll_context()->raster_cached_entries->clear();
layer->Preroll(preroll_context(), SkMatrix::I());
LayerTree::TryToRasterCache(*(preroll_context()->raster_cached_entries),
&paint_context());
preroll_context()->raster_cache->CleanupAfterFrame();
preroll_context()->raster_cache->EndFrame();
}
}

Expand Down
1 change: 1 addition & 0 deletions flow/layers/layer_tree.cc
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ void LayerTree::Paint(CompositorContext::ScopedFrame& frame,
};

if (cache) {
cache->EvictUnusedCacheEntries();
TryToRasterCache(raster_cache_items_, &context, ignore_raster_cache);
}

Expand Down
68 changes: 33 additions & 35 deletions flow/raster_cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -162,58 +162,47 @@ bool RasterCache::Draw(const RasterCacheKeyID& id,
return false;
}

void RasterCache::PrepareNewFrame() {
void RasterCache::BeginFrame() {
display_list_cached_this_frame_ = 0;
picture_metrics_ = {};
layer_metrics_ = {};
}

void RasterCache::SweepOneCacheAfterFrame(RasterCacheKey::Map<Entry>& cache,
RasterCacheMetrics& picture_metrics,
RasterCacheMetrics& layer_metrics) {
void RasterCache::UpdateMetrics() {
for (auto it = cache_.begin(); it != cache_.end(); ++it) {
Entry& entry = it->second;
FML_DCHECK(entry.encountered_this_frame);
if (entry.image) {
RasterCacheMetrics& metrics = GetMetricsForKind(it->first.kind());
metrics.in_use_count++;
metrics.in_use_bytes += entry.image->image_bytes();
}
entry.encountered_this_frame = false;
}
}

void RasterCache::EvictUnusedCacheEntries() {
std::vector<RasterCacheKey::Map<Entry>::iterator> dead;

for (auto it = cache.begin(); it != cache.end(); ++it) {
for (auto it = cache_.begin(); it != cache_.end(); ++it) {
Entry& entry = it->second;

if (!entry.encountered_this_frame) {
dead.push_back(it);
} else if (entry.image) {
RasterCacheKeyKind kind = it->first.kind();
switch (kind) {
case RasterCacheKeyKind::kDisplayListMetrics:
picture_metrics.in_use_count++;
picture_metrics.in_use_bytes += entry.image->image_bytes();
break;
case RasterCacheKeyKind::kLayerMetrics:
layer_metrics.in_use_count++;
layer_metrics.in_use_bytes += entry.image->image_bytes();
break;
}
}
entry.encountered_this_frame = false;
}

for (auto it : dead) {
if (it->second.image) {
RasterCacheKeyKind kind = it->first.kind();
switch (kind) {
case RasterCacheKeyKind::kDisplayListMetrics:
picture_metrics.eviction_count++;
picture_metrics.eviction_bytes += it->second.image->image_bytes();
break;
case RasterCacheKeyKind::kLayerMetrics:
layer_metrics.eviction_count++;
layer_metrics.eviction_bytes += it->second.image->image_bytes();
break;
}
RasterCacheMetrics& metrics = GetMetricsForKind(it->first.kind());
metrics.eviction_count++;
metrics.eviction_bytes += it->second.image->image_bytes();
}
cache.erase(it);
cache_.erase(it);
}
}

void RasterCache::CleanupAfterFrame() {
picture_metrics_ = {};
layer_metrics_ = {};
SweepOneCacheAfterFrame(cache_, picture_metrics_, layer_metrics_);
void RasterCache::EndFrame() {
UpdateMetrics();
TraceStatsToTimeline();
}

Expand Down Expand Up @@ -294,4 +283,13 @@ size_t RasterCache::EstimatePictureCacheByteSize() const {
return picture_cache_bytes;
}

RasterCacheMetrics& RasterCache::GetMetricsForKind(RasterCacheKeyKind kind) {
switch (kind) {
case RasterCacheKeyKind::kDisplayListMetrics:
return picture_metrics_;
case RasterCacheKeyKind::kLayerMetrics:
return layer_metrics_;
}
}

} // namespace flutter
48 changes: 35 additions & 13 deletions flow/raster_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,20 +78,40 @@ struct RasterCacheMetrics {
size_t in_use_bytes = 0;

/**
* The total cache entries that had images during this frame whether
* they were used in the frame or held memory during the frame and then
* were evicted after it ended.
* The total cache entries that had images during this frame.
*/
size_t total_count() const { return in_use_count + eviction_count; }
size_t total_count() const { return in_use_count; }

/**
* The size of all of the cached images during this frame whether
* they were used in the frame or held memory during the frame and then
* were evicted after it ended.
* The size of all of the cached images during this frame.
*/
size_t total_bytes() const { return in_use_bytes + eviction_bytes; }
size_t total_bytes() const { return in_use_bytes; }
};

/**
* RasterCache is used to cache rasterized layers or display lists to improve
* performance.
*
* Life cycle of RasterCache methods:
* - Preroll stage
* - LayerTree::Preroll - for each Layer in the tree:
* - RasterCacheItem::PrerollSetup
* At the start of each layer's preroll, add cache items to
* `PrerollContext::raster_cached_entries`.
* - RasterCacheItem::PrerollFinalize
* At the end of each layer's preroll, may mark cache entris as
* encountered by the current frame.
* - Paint stage
* - RasterCache::EvictUnusedCacheEntries
* Evit cached images that are no longer used.
* - LayerTree::TryToPrepareRasterCache
* Create cache image for each cache entry if it does not exist.
* - LayerTree::Paint - for each layer in the tree:
* If layers or display lists are cached as cached images, the method
* `RasterCache::Draw` will be used to draw those cache images.
* - RasterCache::EndFrame:
* Computes used counts and memory then reports cache metrics.
*/
class RasterCache {
public:
struct Context {
Expand Down Expand Up @@ -126,9 +146,11 @@ class RasterCache {

bool HasEntry(const RasterCacheKeyID& id, const SkMatrix&) const;

void PrepareNewFrame();
void BeginFrame();

void CleanupAfterFrame();
void EvictUnusedCacheEntries();

void EndFrame();

void Clear();

Expand Down Expand Up @@ -222,9 +244,9 @@ class RasterCache {
std::unique_ptr<RasterCacheResult> image;
};

void SweepOneCacheAfterFrame(RasterCacheKey::Map<Entry>& cache,
RasterCacheMetrics& picture_metrics,
RasterCacheMetrics& layer_metrics);
void UpdateMetrics();

RasterCacheMetrics& GetMetricsForKind(RasterCacheKeyKind kind);

const size_t access_threshold_;
const size_t display_list_cache_limit_per_frame_;
Expand Down
Loading