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
[Picture::RECORDING_MODE_COUNT
] = {
40 "_painting_disabled"};
44 RasterizeAndRecordBenchmark::RasterizeAndRecordBenchmark(
45 scoped_ptr
<base::Value
> value
,
46 const MicroBenchmark::DoneCallback
& callback
)
47 : MicroBenchmark(callback
),
48 record_repeat_count_(kDefaultRecordRepeatCount
),
49 settings_(value
.Pass()),
50 main_thread_benchmark_done_(false),
52 weak_ptr_factory_(this) {
53 base::DictionaryValue
* settings
= nullptr;
54 settings_
->GetAsDictionary(&settings
);
58 if (settings
->HasKey("record_repeat_count"))
59 settings
->GetInteger("record_repeat_count", &record_repeat_count_
);
62 RasterizeAndRecordBenchmark::~RasterizeAndRecordBenchmark() {
63 weak_ptr_factory_
.InvalidateWeakPtrs();
66 void RasterizeAndRecordBenchmark::DidUpdateLayers(LayerTreeHost
* host
) {
68 LayerTreeHostCommon::CallFunctionForSubtree(
70 base::Bind(&RasterizeAndRecordBenchmark::Run
, base::Unretained(this)));
72 DCHECK(!results_
.get());
73 results_
= make_scoped_ptr(new base::DictionaryValue
);
74 results_
->SetInteger("pixels_recorded", record_results_
.pixels_recorded
);
75 results_
->SetInteger("picture_memory_usage", record_results_
.bytes_used
);
77 for (int i
= 0; i
< Picture::RECORDING_MODE_COUNT
; i
++) {
78 std::string name
= base::StringPrintf("record_time%s_ms", kModeSuffixes
[i
]);
79 results_
->SetDouble(name
,
80 record_results_
.total_best_time
[i
].InMillisecondsF());
82 main_thread_benchmark_done_
= true;
85 void RasterizeAndRecordBenchmark::RecordRasterResults(
86 scoped_ptr
<base::Value
> results_value
) {
87 DCHECK(main_thread_benchmark_done_
);
89 base::DictionaryValue
* results
= nullptr;
90 results_value
->GetAsDictionary(&results
);
93 results_
->MergeDictionary(results
);
95 NotifyDone(results_
.Pass());
98 scoped_ptr
<MicroBenchmarkImpl
> RasterizeAndRecordBenchmark::CreateBenchmarkImpl(
99 scoped_refptr
<base::MessageLoopProxy
> origin_loop
) {
100 return make_scoped_ptr(new RasterizeAndRecordBenchmarkImpl(
103 base::Bind(&RasterizeAndRecordBenchmark::RecordRasterResults
,
104 weak_ptr_factory_
.GetWeakPtr())));
107 void RasterizeAndRecordBenchmark::Run(Layer
* layer
) {
108 layer
->RunMicroBenchmark(this);
111 void RasterizeAndRecordBenchmark::RunOnLayer(PictureLayer
* layer
) {
114 gfx::Rect visible_content_rect
= gfx::ScaleToEnclosingRect(
115 layer
->visible_content_rect(), 1.f
/ layer
->contents_scale_x());
116 if (visible_content_rect
.IsEmpty())
119 if (host_
->settings().use_display_lists
) {
120 RunOnDisplayListLayer(layer
, visible_content_rect
);
122 RunOnPictureLayer(layer
, visible_content_rect
);
126 void RasterizeAndRecordBenchmark::RunOnPictureLayer(
128 const gfx::Rect
& visible_content_rect
) {
129 ContentLayerClient
* painter
= layer
->client();
131 DCHECK(host_
&& !host_
->settings().use_display_lists
);
133 gfx::Size tile_grid_size
= host_
->settings().default_tile_size
;
135 for (int mode_index
= 0; mode_index
< Picture::RECORDING_MODE_COUNT
;
137 Picture::RecordingMode mode
=
138 static_cast<Picture::RecordingMode
>(mode_index
);
139 base::TimeDelta min_time
= base::TimeDelta::Max();
140 size_t memory_used
= 0;
142 for (int i
= 0; i
< record_repeat_count_
; ++i
) {
143 // Run for a minimum amount of time to avoid problems with timer
144 // quantization when the layer is very small.
145 LapTimer
timer(kWarmupRuns
,
146 base::TimeDelta::FromMilliseconds(kTimeLimitMillis
),
148 scoped_refptr
<Picture
> picture
;
150 picture
= Picture::Create(visible_content_rect
, painter
, tile_grid_size
,
153 // Verify we are recording the same thing each time.
154 DCHECK(memory_used
== picture
->ApproximateMemoryUsage());
156 memory_used
= picture
->ApproximateMemoryUsage();
160 } while (!timer
.HasTimeLimitExpired());
161 base::TimeDelta duration
=
162 base::TimeDelta::FromMillisecondsD(timer
.MsPerLap());
163 if (duration
< min_time
)
167 if (mode
== Picture::RECORD_NORMALLY
) {
168 record_results_
.bytes_used
+= memory_used
;
169 record_results_
.pixels_recorded
+=
170 visible_content_rect
.width() * visible_content_rect
.height();
172 record_results_
.total_best_time
[mode_index
] += min_time
;
176 void RasterizeAndRecordBenchmark::RunOnDisplayListLayer(
178 const gfx::Rect
& visible_content_rect
) {
179 ContentLayerClient
* painter
= layer
->client();
181 DCHECK(host_
&& host_
->settings().use_display_lists
);
183 base::TimeDelta min_time
= base::TimeDelta::Max();
184 size_t memory_used
= 0;
186 // TODO(schenney): What are the corresponding Picture::RecordingMode modes
187 // for Slimming Paint. We could disable SkPicture creation in
188 // DrawingDisplayItems, or we could only generate the display list and not
189 // do any work on it in the compositor, or something else, or all of the
191 scoped_refptr
<DisplayItemList
> display_list
;
192 for (int i
= 0; i
< record_repeat_count_
; ++i
) {
193 // Run for a minimum amount of time to avoid problems with timer
194 // quantization when the layer is very small.
195 LapTimer
timer(kWarmupRuns
,
196 base::TimeDelta::FromMilliseconds(kTimeLimitMillis
),
200 // TODO(schenney): Cached content will not be regenerated, which skews
201 // the results significantly in favor of Slimming Paint (or should).
202 // Add a flag or API call to disable caching, and maybe run the test
203 // twice, without and with caching.
204 display_list
= painter
->PaintContentsToDisplayList(
205 visible_content_rect
, ContentLayerClient::GRAPHICS_CONTEXT_ENABLED
);
208 // Verify we are recording the same thing each time.
209 DCHECK(memory_used
== display_list
->PictureMemoryUsage());
211 memory_used
= display_list
->PictureMemoryUsage();
215 } while (!timer
.HasTimeLimitExpired());
216 base::TimeDelta duration
=
217 base::TimeDelta::FromMillisecondsD(timer
.MsPerLap());
218 if (duration
< min_time
)
222 record_results_
.bytes_used
+= memory_used
;
223 record_results_
.pixels_recorded
+=
224 visible_content_rect
.width() * visible_content_rect
.height();
225 record_results_
.total_best_time
[Picture::RECORD_NORMALLY
] += min_time
;
228 RasterizeAndRecordBenchmark::RecordResults::RecordResults()
229 : pixels_recorded(0), bytes_used(0) {
232 RasterizeAndRecordBenchmark::RecordResults::~RecordResults() {}