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/resources/display_item_list.h"
20 #include "cc/resources/picture_pile.h"
21 #include "cc/trees/layer_tree_host.h"
22 #include "cc/trees/layer_tree_host_common.h"
23 #include "third_party/skia/include/utils/SkPictureUtils.h"
24 #include "ui/gfx/geometry/rect.h"
30 const int kDefaultRecordRepeatCount
= 100;
32 // Parameters for LapTimer.
33 const int kTimeLimitMillis
= 1;
34 const int kWarmupRuns
= 0;
35 const int kTimeCheckInterval
= 1;
37 const char* kModeSuffixes
[RecordingSource::RECORDING_MODE_COUNT
] =
38 {"", "_sk_null_canvas", "_painting_disabled", "_caching_disabled"};
42 RasterizeAndRecordBenchmark::RasterizeAndRecordBenchmark(
43 scoped_ptr
<base::Value
> value
,
44 const MicroBenchmark::DoneCallback
& callback
)
45 : MicroBenchmark(callback
),
46 record_repeat_count_(kDefaultRecordRepeatCount
),
47 settings_(value
.Pass()),
48 main_thread_benchmark_done_(false),
50 weak_ptr_factory_(this) {
51 base::DictionaryValue
* settings
= nullptr;
52 settings_
->GetAsDictionary(&settings
);
56 if (settings
->HasKey("record_repeat_count"))
57 settings
->GetInteger("record_repeat_count", &record_repeat_count_
);
60 RasterizeAndRecordBenchmark::~RasterizeAndRecordBenchmark() {
61 weak_ptr_factory_
.InvalidateWeakPtrs();
64 void RasterizeAndRecordBenchmark::DidUpdateLayers(LayerTreeHost
* host
) {
66 LayerTreeHostCommon::CallFunctionForSubtree(
68 [this](Layer
* layer
) { layer
->RunMicroBenchmark(this); });
70 DCHECK(!results_
.get());
71 results_
= make_scoped_ptr(new base::DictionaryValue
);
72 results_
->SetInteger("pixels_recorded", record_results_
.pixels_recorded
);
73 results_
->SetInteger("picture_memory_usage", record_results_
.bytes_used
);
75 for (int i
= 0; i
< RecordingSource::RECORDING_MODE_COUNT
; i
++) {
76 std::string name
= base::StringPrintf("record_time%s_ms", kModeSuffixes
[i
]);
77 results_
->SetDouble(name
,
78 record_results_
.total_best_time
[i
].InMillisecondsF());
80 main_thread_benchmark_done_
= true;
83 void RasterizeAndRecordBenchmark::RecordRasterResults(
84 scoped_ptr
<base::Value
> results_value
) {
85 DCHECK(main_thread_benchmark_done_
);
87 base::DictionaryValue
* results
= nullptr;
88 results_value
->GetAsDictionary(&results
);
91 results_
->MergeDictionary(results
);
93 NotifyDone(results_
.Pass());
96 scoped_ptr
<MicroBenchmarkImpl
> RasterizeAndRecordBenchmark::CreateBenchmarkImpl(
97 scoped_refptr
<base::SingleThreadTaskRunner
> origin_task_runner
) {
98 return make_scoped_ptr(new RasterizeAndRecordBenchmarkImpl(
99 origin_task_runner
, settings_
.get(),
100 base::Bind(&RasterizeAndRecordBenchmark::RecordRasterResults
,
101 weak_ptr_factory_
.GetWeakPtr())));
104 void RasterizeAndRecordBenchmark::RunOnLayer(PictureLayer
* layer
) {
107 gfx::Rect visible_layer_rect
= gfx::ScaleToEnclosingRect(
108 layer
->visible_content_rect(), 1.f
/ layer
->contents_scale_x());
109 if (visible_layer_rect
.IsEmpty())
112 if (host_
->settings().use_display_lists
) {
113 RunOnDisplayListLayer(layer
, visible_layer_rect
);
115 RunOnPictureLayer(layer
, visible_layer_rect
);
119 void RasterizeAndRecordBenchmark::RunOnPictureLayer(
121 const gfx::Rect
& visible_layer_rect
) {
122 ContentLayerClient
* painter
= layer
->client();
124 DCHECK(host_
&& !host_
->settings().use_display_lists
);
126 gfx::Size tile_grid_size
= host_
->settings().default_tile_size
;
128 for (int mode_index
= 0; mode_index
< RecordingSource::RECORDING_MODE_COUNT
;
130 RecordingSource::RecordingMode mode
=
131 static_cast<RecordingSource::RecordingMode
>(mode_index
);
132 base::TimeDelta min_time
= base::TimeDelta::Max();
133 size_t memory_used
= 0;
135 for (int i
= 0; i
< record_repeat_count_
; ++i
) {
136 // Run for a minimum amount of time to avoid problems with timer
137 // quantization when the layer is very small.
138 LapTimer
timer(kWarmupRuns
,
139 base::TimeDelta::FromMilliseconds(kTimeLimitMillis
),
141 scoped_refptr
<Picture
> picture
;
143 picture
= Picture::Create(visible_layer_rect
, painter
, tile_grid_size
,
146 // Verify we are recording the same thing each time.
147 DCHECK(memory_used
== picture
->ApproximateMemoryUsage());
149 memory_used
= picture
->ApproximateMemoryUsage();
153 } while (!timer
.HasTimeLimitExpired());
154 base::TimeDelta duration
=
155 base::TimeDelta::FromMillisecondsD(timer
.MsPerLap());
156 if (duration
< min_time
)
160 if (mode
== RecordingSource::RECORD_NORMALLY
) {
161 record_results_
.bytes_used
+= memory_used
;
162 record_results_
.pixels_recorded
+=
163 visible_layer_rect
.width() * visible_layer_rect
.height();
165 record_results_
.total_best_time
[mode_index
] += min_time
;
169 void RasterizeAndRecordBenchmark::RunOnDisplayListLayer(
171 const gfx::Rect
& visible_layer_rect
) {
172 ContentLayerClient
* painter
= layer
->client();
174 DCHECK(host_
&& host_
->settings().use_display_lists
);
176 for (int mode_index
= 0; mode_index
< RecordingSource::RECORDING_MODE_COUNT
;
178 ContentLayerClient::PaintingControlSetting painting_control
=
179 ContentLayerClient::PAINTING_BEHAVIOR_NORMAL
;
180 switch (static_cast<RecordingSource::RecordingMode
>(mode_index
)) {
181 case RecordingSource::RECORD_NORMALLY
:
182 // Already setup for normal recording.
184 case RecordingSource::RECORD_WITH_SK_NULL_CANVAS
:
185 // TODO(schenney): Remove this when DisplayList recording is the only
186 // option. For now, fall through and disable construction.
187 case RecordingSource::RECORD_WITH_PAINTING_DISABLED
:
189 ContentLayerClient::DISPLAY_LIST_CONSTRUCTION_DISABLED
;
191 case RecordingSource::RECORD_WITH_CACHING_DISABLED
:
192 painting_control
= ContentLayerClient::DISPLAY_LIST_CACHING_DISABLED
;
197 base::TimeDelta min_time
= base::TimeDelta::Max();
198 size_t memory_used
= 0;
200 scoped_refptr
<DisplayItemList
> display_list
;
201 for (int i
= 0; i
< record_repeat_count_
; ++i
) {
202 // Run for a minimum amount of time to avoid problems with timer
203 // quantization when the layer is very small.
204 LapTimer
timer(kWarmupRuns
,
205 base::TimeDelta::FromMilliseconds(kTimeLimitMillis
),
209 const bool use_cached_picture
= true;
211 DisplayItemList::Create(visible_layer_rect
, use_cached_picture
);
212 painter
->PaintContentsToDisplayList(
213 display_list
.get(), visible_layer_rect
, painting_control
);
214 display_list
->CreateAndCacheSkPicture();
217 // Verify we are recording the same thing each time.
218 DCHECK(memory_used
== display_list
->PictureMemoryUsage());
220 memory_used
= display_list
->PictureMemoryUsage();
224 } while (!timer
.HasTimeLimitExpired());
225 base::TimeDelta duration
=
226 base::TimeDelta::FromMillisecondsD(timer
.MsPerLap());
227 if (duration
< min_time
)
231 if (mode_index
== RecordingSource::RECORD_NORMALLY
) {
232 record_results_
.bytes_used
+= memory_used
;
233 record_results_
.pixels_recorded
+=
234 visible_layer_rect
.width() * visible_layer_rect
.height();
236 record_results_
.total_best_time
[mode_index
] += min_time
;
240 RasterizeAndRecordBenchmark::RecordResults::RecordResults()
241 : pixels_recorded(0), bytes_used(0) {
244 RasterizeAndRecordBenchmark::RecordResults::~RecordResults() {}