1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/debug/rasterize_and_record_benchmark.h"
11 #include "base/basictypes.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/values.h"
14 #include "cc/debug/lap_timer.h"
15 #include "cc/debug/rasterize_and_record_benchmark_impl.h"
16 #include "cc/layers/content_layer_client.h"
17 #include "cc/layers/layer.h"
18 #include "cc/layers/picture_layer.h"
19 #include "cc/playback/display_item_list.h"
20 #include "cc/playback/picture_pile.h"
21 #include "cc/trees/layer_tree_host.h"
22 #include "cc/trees/layer_tree_host_common.h"
23 #include "skia/ext/analysis_canvas.h"
24 #include "third_party/skia/include/utils/SkPictureUtils.h"
25 #include "ui/gfx/geometry/rect.h"
31 const int kDefaultRecordRepeatCount
= 100;
33 // Parameters for LapTimer.
34 const int kTimeLimitMillis
= 1;
35 const int kWarmupRuns
= 0;
36 const int kTimeCheckInterval
= 1;
38 const char* kModeSuffixes
[RecordingSource::RECORDING_MODE_COUNT
] = {
43 "_construction_disabled"};
47 RasterizeAndRecordBenchmark::RasterizeAndRecordBenchmark(
48 scoped_ptr
<base::Value
> value
,
49 const MicroBenchmark::DoneCallback
& callback
)
50 : MicroBenchmark(callback
),
51 record_repeat_count_(kDefaultRecordRepeatCount
),
52 settings_(value
.Pass()),
53 main_thread_benchmark_done_(false),
55 weak_ptr_factory_(this) {
56 base::DictionaryValue
* settings
= nullptr;
57 settings_
->GetAsDictionary(&settings
);
61 if (settings
->HasKey("record_repeat_count"))
62 settings
->GetInteger("record_repeat_count", &record_repeat_count_
);
65 RasterizeAndRecordBenchmark::~RasterizeAndRecordBenchmark() {
66 weak_ptr_factory_
.InvalidateWeakPtrs();
69 void RasterizeAndRecordBenchmark::DidUpdateLayers(LayerTreeHost
* host
) {
71 LayerTreeHostCommon::CallFunctionForSubtree(
73 [this](Layer
* layer
) { layer
->RunMicroBenchmark(this); });
75 DCHECK(!results_
.get());
76 results_
= make_scoped_ptr(new base::DictionaryValue
);
77 results_
->SetInteger("pixels_recorded", record_results_
.pixels_recorded
);
78 results_
->SetInteger("picture_memory_usage",
79 static_cast<int>(record_results_
.bytes_used
));
81 for (int i
= 0; i
< RecordingSource::RECORDING_MODE_COUNT
; i
++) {
82 std::string name
= base::StringPrintf("record_time%s_ms", kModeSuffixes
[i
]);
83 results_
->SetDouble(name
,
84 record_results_
.total_best_time
[i
].InMillisecondsF());
86 main_thread_benchmark_done_
= true;
89 void RasterizeAndRecordBenchmark::RecordRasterResults(
90 scoped_ptr
<base::Value
> results_value
) {
91 DCHECK(main_thread_benchmark_done_
);
93 base::DictionaryValue
* results
= nullptr;
94 results_value
->GetAsDictionary(&results
);
97 results_
->MergeDictionary(results
);
99 NotifyDone(results_
.Pass());
102 scoped_ptr
<MicroBenchmarkImpl
> RasterizeAndRecordBenchmark::CreateBenchmarkImpl(
103 scoped_refptr
<base::SingleThreadTaskRunner
> origin_task_runner
) {
104 return make_scoped_ptr(new RasterizeAndRecordBenchmarkImpl(
105 origin_task_runner
, settings_
.get(),
106 base::Bind(&RasterizeAndRecordBenchmark::RecordRasterResults
,
107 weak_ptr_factory_
.GetWeakPtr())));
110 void RasterizeAndRecordBenchmark::RunOnLayer(PictureLayer
* layer
) {
113 gfx::Rect visible_layer_rect
= layer
->visible_layer_rect();
114 if (visible_layer_rect
.IsEmpty())
117 if (host_
->settings().use_display_lists
) {
118 RunOnDisplayListLayer(layer
, visible_layer_rect
);
120 RunOnPictureLayer(layer
, visible_layer_rect
);
124 void RasterizeAndRecordBenchmark::RunOnPictureLayer(
126 const gfx::Rect
& visible_layer_rect
) {
127 ContentLayerClient
* painter
= layer
->client();
129 DCHECK(host_
&& !host_
->settings().use_display_lists
);
131 gfx::Size tile_grid_size
= host_
->settings().default_tile_size
;
133 for (int mode_index
= 0; mode_index
< RecordingSource::RECORDING_MODE_COUNT
;
135 RecordingSource::RecordingMode mode
=
136 static_cast<RecordingSource::RecordingMode
>(mode_index
);
138 // Not supported for SkPicture recording.
139 if (mode
== RecordingSource::RECORD_WITH_CONSTRUCTION_DISABLED
)
142 base::TimeDelta min_time
= base::TimeDelta::Max();
143 size_t memory_used
= 0;
145 for (int i
= 0; i
< record_repeat_count_
; ++i
) {
146 // Run for a minimum amount of time to avoid problems with timer
147 // quantization when the layer is very small.
148 LapTimer
timer(kWarmupRuns
,
149 base::TimeDelta::FromMilliseconds(kTimeLimitMillis
),
151 scoped_refptr
<Picture
> picture
;
153 picture
= Picture::Create(visible_layer_rect
, painter
, tile_grid_size
,
155 if (picture
->ShouldBeAnalyzedForSolidColor()) {
156 gfx::Size layer_size
= layer
->paint_properties().bounds
;
157 skia::AnalysisCanvas
canvas(layer_size
.width(), layer_size
.height());
158 picture
->Raster(&canvas
, nullptr, gfx::Rect(), 1.f
);
161 // Verify we are recording the same thing each time.
162 DCHECK(memory_used
== picture
->ApproximateMemoryUsage());
164 memory_used
= picture
->ApproximateMemoryUsage();
168 } while (!timer
.HasTimeLimitExpired());
169 base::TimeDelta duration
=
170 base::TimeDelta::FromMillisecondsD(timer
.MsPerLap());
171 if (duration
< min_time
)
175 if (mode
== RecordingSource::RECORD_NORMALLY
) {
176 record_results_
.bytes_used
+= memory_used
;
177 record_results_
.pixels_recorded
+=
178 visible_layer_rect
.width() * visible_layer_rect
.height();
180 record_results_
.total_best_time
[mode_index
] += min_time
;
184 void RasterizeAndRecordBenchmark::RunOnDisplayListLayer(
186 const gfx::Rect
& visible_layer_rect
) {
187 ContentLayerClient
* painter
= layer
->client();
189 DCHECK(host_
&& host_
->settings().use_display_lists
);
191 for (int mode_index
= 0; mode_index
< RecordingSource::RECORDING_MODE_COUNT
;
193 ContentLayerClient::PaintingControlSetting painting_control
=
194 ContentLayerClient::PAINTING_BEHAVIOR_NORMAL
;
195 switch (static_cast<RecordingSource::RecordingMode
>(mode_index
)) {
196 case RecordingSource::RECORD_NORMALLY
:
197 // Already setup for normal recording.
199 case RecordingSource::RECORD_WITH_SK_NULL_CANVAS
:
200 // Not supported for Display List recording.
202 case RecordingSource::RECORD_WITH_PAINTING_DISABLED
:
203 painting_control
= ContentLayerClient::DISPLAY_LIST_PAINTING_DISABLED
;
205 case RecordingSource::RECORD_WITH_CACHING_DISABLED
:
206 painting_control
= ContentLayerClient::DISPLAY_LIST_CACHING_DISABLED
;
208 case RecordingSource::RECORD_WITH_CONSTRUCTION_DISABLED
:
210 ContentLayerClient::DISPLAY_LIST_CONSTRUCTION_DISABLED
;
215 base::TimeDelta min_time
= base::TimeDelta::Max();
216 size_t memory_used
= 0;
218 scoped_refptr
<DisplayItemList
> display_list
;
219 for (int i
= 0; i
< record_repeat_count_
; ++i
) {
220 // Run for a minimum amount of time to avoid problems with timer
221 // quantization when the layer is very small.
222 LapTimer
timer(kWarmupRuns
,
223 base::TimeDelta::FromMilliseconds(kTimeLimitMillis
),
227 display_list
= painter
->PaintContentsToDisplayList(visible_layer_rect
,
229 if (display_list
->ShouldBeAnalyzedForSolidColor()) {
230 gfx::Size layer_size
= layer
->paint_properties().bounds
;
231 skia::AnalysisCanvas
canvas(layer_size
.width(), layer_size
.height());
232 display_list
->Raster(&canvas
, nullptr, gfx::Rect(), 1.f
);
236 // Verify we are recording the same thing each time.
237 DCHECK_EQ(memory_used
, display_list
->ApproximateMemoryUsage());
239 memory_used
= display_list
->ApproximateMemoryUsage();
243 } while (!timer
.HasTimeLimitExpired());
244 base::TimeDelta duration
=
245 base::TimeDelta::FromMillisecondsD(timer
.MsPerLap());
246 if (duration
< min_time
)
250 if (mode_index
== RecordingSource::RECORD_NORMALLY
) {
251 record_results_
.bytes_used
+=
252 memory_used
+ painter
->GetApproximateUnsharedMemoryUsage();
253 record_results_
.pixels_recorded
+=
254 visible_layer_rect
.width() * visible_layer_rect
.height();
256 record_results_
.total_best_time
[mode_index
] += min_time
;
260 RasterizeAndRecordBenchmark::RecordResults::RecordResults()
261 : pixels_recorded(0), bytes_used(0) {
264 RasterizeAndRecordBenchmark::RecordResults::~RecordResults() {}