// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "cc/debug/rasterize_and_record_benchmark.h" #include #include #include #include "base/basictypes.h" #include "base/strings/stringprintf.h" #include "base/values.h" #include "cc/debug/lap_timer.h" #include "cc/debug/rasterize_and_record_benchmark_impl.h" #include "cc/layers/content_layer_client.h" #include "cc/layers/layer.h" #include "cc/layers/picture_layer.h" #include "cc/resources/display_item_list.h" #include "cc/resources/picture_pile.h" #include "cc/trees/layer_tree_host.h" #include "cc/trees/layer_tree_host_common.h" #include "third_party/skia/include/utils/SkPictureUtils.h" #include "ui/gfx/geometry/rect.h" namespace cc { namespace { const int kDefaultRecordRepeatCount = 100; // Parameters for LapTimer. const int kTimeLimitMillis = 1; const int kWarmupRuns = 0; const int kTimeCheckInterval = 1; const char* kModeSuffixes[RecordingSource::RECORDING_MODE_COUNT] = { "", "_sk_null_canvas", "_painting_disabled", "_caching_disabled", "_construction_disabled"}; } // namespace RasterizeAndRecordBenchmark::RasterizeAndRecordBenchmark( scoped_ptr value, const MicroBenchmark::DoneCallback& callback) : MicroBenchmark(callback), record_repeat_count_(kDefaultRecordRepeatCount), settings_(value.Pass()), main_thread_benchmark_done_(false), host_(nullptr), weak_ptr_factory_(this) { base::DictionaryValue* settings = nullptr; settings_->GetAsDictionary(&settings); if (!settings) return; if (settings->HasKey("record_repeat_count")) settings->GetInteger("record_repeat_count", &record_repeat_count_); } RasterizeAndRecordBenchmark::~RasterizeAndRecordBenchmark() { weak_ptr_factory_.InvalidateWeakPtrs(); } void RasterizeAndRecordBenchmark::DidUpdateLayers(LayerTreeHost* host) { host_ = host; LayerTreeHostCommon::CallFunctionForSubtree( host->root_layer(), [this](Layer* layer) { layer->RunMicroBenchmark(this); }); DCHECK(!results_.get()); results_ = make_scoped_ptr(new base::DictionaryValue); results_->SetInteger("pixels_recorded", record_results_.pixels_recorded); results_->SetInteger("picture_memory_usage", record_results_.bytes_used); for (int i = 0; i < RecordingSource::RECORDING_MODE_COUNT; i++) { std::string name = base::StringPrintf("record_time%s_ms", kModeSuffixes[i]); results_->SetDouble(name, record_results_.total_best_time[i].InMillisecondsF()); } main_thread_benchmark_done_ = true; } void RasterizeAndRecordBenchmark::RecordRasterResults( scoped_ptr results_value) { DCHECK(main_thread_benchmark_done_); base::DictionaryValue* results = nullptr; results_value->GetAsDictionary(&results); DCHECK(results); results_->MergeDictionary(results); NotifyDone(results_.Pass()); } scoped_ptr RasterizeAndRecordBenchmark::CreateBenchmarkImpl( scoped_refptr origin_task_runner) { return make_scoped_ptr(new RasterizeAndRecordBenchmarkImpl( origin_task_runner, settings_.get(), base::Bind(&RasterizeAndRecordBenchmark::RecordRasterResults, weak_ptr_factory_.GetWeakPtr()))); } void RasterizeAndRecordBenchmark::RunOnLayer(PictureLayer* layer) { DCHECK(host_); gfx::Rect visible_layer_rect = gfx::ScaleToEnclosingRect( layer->visible_content_rect(), 1.f / layer->contents_scale_x()); if (visible_layer_rect.IsEmpty()) return; if (host_->settings().use_display_lists) { RunOnDisplayListLayer(layer, visible_layer_rect); } else { RunOnPictureLayer(layer, visible_layer_rect); } } void RasterizeAndRecordBenchmark::RunOnPictureLayer( PictureLayer* layer, const gfx::Rect& visible_layer_rect) { ContentLayerClient* painter = layer->client(); DCHECK(host_ && !host_->settings().use_display_lists); gfx::Size tile_grid_size = host_->settings().default_tile_size; for (int mode_index = 0; mode_index < RecordingSource::RECORDING_MODE_COUNT; mode_index++) { RecordingSource::RecordingMode mode = static_cast(mode_index); // Not supported for SkPicture recording. if (mode == RecordingSource::RECORD_WITH_CONSTRUCTION_DISABLED) continue; base::TimeDelta min_time = base::TimeDelta::Max(); size_t memory_used = 0; for (int i = 0; i < record_repeat_count_; ++i) { // Run for a minimum amount of time to avoid problems with timer // quantization when the layer is very small. LapTimer timer(kWarmupRuns, base::TimeDelta::FromMilliseconds(kTimeLimitMillis), kTimeCheckInterval); scoped_refptr picture; do { picture = Picture::Create(visible_layer_rect, painter, tile_grid_size, false, mode); if (memory_used) { // Verify we are recording the same thing each time. DCHECK(memory_used == picture->ApproximateMemoryUsage()); } else { memory_used = picture->ApproximateMemoryUsage(); } timer.NextLap(); } while (!timer.HasTimeLimitExpired()); base::TimeDelta duration = base::TimeDelta::FromMillisecondsD(timer.MsPerLap()); if (duration < min_time) min_time = duration; } if (mode == RecordingSource::RECORD_NORMALLY) { record_results_.bytes_used += memory_used; record_results_.pixels_recorded += visible_layer_rect.width() * visible_layer_rect.height(); } record_results_.total_best_time[mode_index] += min_time; } } void RasterizeAndRecordBenchmark::RunOnDisplayListLayer( PictureLayer* layer, const gfx::Rect& visible_layer_rect) { ContentLayerClient* painter = layer->client(); DCHECK(host_ && host_->settings().use_display_lists); for (int mode_index = 0; mode_index < RecordingSource::RECORDING_MODE_COUNT; mode_index++) { ContentLayerClient::PaintingControlSetting painting_control = ContentLayerClient::PAINTING_BEHAVIOR_NORMAL; switch (static_cast(mode_index)) { case RecordingSource::RECORD_NORMALLY: // Already setup for normal recording. break; case RecordingSource::RECORD_WITH_SK_NULL_CANVAS: // Not supported for Display List recording. continue; case RecordingSource::RECORD_WITH_PAINTING_DISABLED: painting_control = ContentLayerClient::DISPLAY_LIST_PAINTING_DISABLED; break; case RecordingSource::RECORD_WITH_CACHING_DISABLED: painting_control = ContentLayerClient::DISPLAY_LIST_CACHING_DISABLED; break; case RecordingSource::RECORD_WITH_CONSTRUCTION_DISABLED: painting_control = ContentLayerClient::DISPLAY_LIST_CONSTRUCTION_DISABLED; break; default: NOTREACHED(); } base::TimeDelta min_time = base::TimeDelta::Max(); size_t memory_used = 0; scoped_refptr display_list; for (int i = 0; i < record_repeat_count_; ++i) { // Run for a minimum amount of time to avoid problems with timer // quantization when the layer is very small. LapTimer timer(kWarmupRuns, base::TimeDelta::FromMilliseconds(kTimeLimitMillis), kTimeCheckInterval); do { const bool use_cached_picture = true; display_list = DisplayItemList::Create(visible_layer_rect, use_cached_picture); painter->PaintContentsToDisplayList( display_list.get(), visible_layer_rect, painting_control); display_list->CreateAndCacheSkPicture(); if (memory_used) { // Verify we are recording the same thing each time. DCHECK(memory_used == display_list->PictureMemoryUsage()); } else { memory_used = display_list->PictureMemoryUsage(); } timer.NextLap(); } while (!timer.HasTimeLimitExpired()); base::TimeDelta duration = base::TimeDelta::FromMillisecondsD(timer.MsPerLap()); if (duration < min_time) min_time = duration; } if (mode_index == RecordingSource::RECORD_NORMALLY) { record_results_.bytes_used += memory_used; record_results_.pixels_recorded += visible_layer_rect.width() * visible_layer_rect.height(); } record_results_.total_best_time[mode_index] += min_time; } } RasterizeAndRecordBenchmark::RecordResults::RecordResults() : pixels_recorded(0), bytes_used(0) { } RasterizeAndRecordBenchmark::RecordResults::~RecordResults() {} } // namespace cc