OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "cc/debug/rasterize_and_record_benchmark.h" | |
6 | |
7 #include <algorithm> | |
8 #include <limits> | |
9 #include <string> | |
10 | |
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" | |
25 | |
26 namespace cc { | |
27 | |
28 namespace { | |
29 | |
30 const int kDefaultRecordRepeatCount = 100; | |
31 | |
32 // Parameters for LapTimer. | |
33 const int kTimeLimitMillis = 1; | |
34 const int kWarmupRuns = 0; | |
35 const int kTimeCheckInterval = 1; | |
36 | |
37 const char* kModeSuffixes[RecordingSource::RECORDING_MODE_COUNT] = | |
38 {"", "_sk_null_canvas", "_painting_disabled", "_caching_disabled"}; | |
39 | |
40 } // namespace | |
41 | |
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), | |
49 host_(nullptr), | |
50 weak_ptr_factory_(this) { | |
51 base::DictionaryValue* settings = nullptr; | |
52 settings_->GetAsDictionary(&settings); | |
53 if (!settings) | |
54 return; | |
55 | |
56 if (settings->HasKey("record_repeat_count")) | |
57 settings->GetInteger("record_repeat_count", &record_repeat_count_); | |
58 } | |
59 | |
60 RasterizeAndRecordBenchmark::~RasterizeAndRecordBenchmark() { | |
61 weak_ptr_factory_.InvalidateWeakPtrs(); | |
62 } | |
63 | |
64 void RasterizeAndRecordBenchmark::DidUpdateLayers(LayerTreeHost* host) { | |
65 host_ = host; | |
66 LayerTreeHostCommon::CallFunctionForSubtree( | |
67 host->root_layer(), | |
68 [this](Layer* layer) { layer->RunMicroBenchmark(this); }); | |
69 | |
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); | |
74 | |
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()); | |
79 } | |
80 main_thread_benchmark_done_ = true; | |
81 } | |
82 | |
83 void RasterizeAndRecordBenchmark::RecordRasterResults( | |
84 scoped_ptr<base::Value> results_value) { | |
85 DCHECK(main_thread_benchmark_done_); | |
86 | |
87 base::DictionaryValue* results = nullptr; | |
88 results_value->GetAsDictionary(&results); | |
89 DCHECK(results); | |
90 | |
91 results_->MergeDictionary(results); | |
92 | |
93 NotifyDone(results_.Pass()); | |
94 } | |
95 | |
96 scoped_ptr<MicroBenchmarkImpl> RasterizeAndRecordBenchmark::CreateBenchmarkImpl( | |
97 scoped_refptr<base::MessageLoopProxy> origin_loop) { | |
98 return make_scoped_ptr(new RasterizeAndRecordBenchmarkImpl( | |
99 origin_loop, | |
100 settings_.get(), | |
101 base::Bind(&RasterizeAndRecordBenchmark::RecordRasterResults, | |
102 weak_ptr_factory_.GetWeakPtr()))); | |
103 } | |
104 | |
105 void RasterizeAndRecordBenchmark::RunOnLayer(PictureLayer* layer) { | |
106 DCHECK(host_); | |
107 | |
108 gfx::Rect visible_content_rect = gfx::ScaleToEnclosingRect( | |
109 layer->visible_content_rect(), 1.f / layer->contents_scale_x()); | |
110 if (visible_content_rect.IsEmpty()) | |
111 return; | |
112 | |
113 if (host_->settings().use_display_lists) { | |
114 RunOnDisplayListLayer(layer, visible_content_rect); | |
115 } else { | |
116 RunOnPictureLayer(layer, visible_content_rect); | |
117 } | |
118 } | |
119 | |
120 void RasterizeAndRecordBenchmark::RunOnPictureLayer( | |
121 PictureLayer* layer, | |
122 const gfx::Rect& visible_content_rect) { | |
123 ContentLayerClient* painter = layer->client(); | |
124 | |
125 DCHECK(host_ && !host_->settings().use_display_lists); | |
126 | |
127 gfx::Size tile_grid_size = host_->settings().default_tile_size; | |
128 | |
129 for (int mode_index = 0; mode_index < RecordingSource::RECORDING_MODE_COUNT; | |
130 mode_index++) { | |
131 RecordingSource::RecordingMode mode = | |
132 static_cast<RecordingSource::RecordingMode>(mode_index); | |
133 base::TimeDelta min_time = base::TimeDelta::Max(); | |
134 size_t memory_used = 0; | |
135 | |
136 for (int i = 0; i < record_repeat_count_; ++i) { | |
137 // Run for a minimum amount of time to avoid problems with timer | |
138 // quantization when the layer is very small. | |
139 LapTimer timer(kWarmupRuns, | |
140 base::TimeDelta::FromMilliseconds(kTimeLimitMillis), | |
141 kTimeCheckInterval); | |
142 scoped_refptr<Picture> picture; | |
143 do { | |
144 picture = Picture::Create(visible_content_rect, painter, tile_grid_size, | |
145 false, mode); | |
146 if (memory_used) { | |
147 // Verify we are recording the same thing each time. | |
148 DCHECK(memory_used == picture->ApproximateMemoryUsage()); | |
149 } else { | |
150 memory_used = picture->ApproximateMemoryUsage(); | |
151 } | |
152 | |
153 timer.NextLap(); | |
154 } while (!timer.HasTimeLimitExpired()); | |
155 base::TimeDelta duration = | |
156 base::TimeDelta::FromMillisecondsD(timer.MsPerLap()); | |
157 if (duration < min_time) | |
158 min_time = duration; | |
159 } | |
160 | |
161 if (mode == RecordingSource::RECORD_NORMALLY) { | |
162 record_results_.bytes_used += memory_used; | |
163 record_results_.pixels_recorded += | |
164 visible_content_rect.width() * visible_content_rect.height(); | |
165 } | |
166 record_results_.total_best_time[mode_index] += min_time; | |
167 } | |
168 } | |
169 | |
170 void RasterizeAndRecordBenchmark::RunOnDisplayListLayer( | |
171 PictureLayer* layer, | |
172 const gfx::Rect& visible_content_rect) { | |
173 ContentLayerClient* painter = layer->client(); | |
174 | |
175 DCHECK(host_ && host_->settings().use_display_lists); | |
176 | |
177 for (int mode_index = 0; mode_index < RecordingSource::RECORDING_MODE_COUNT; | |
178 mode_index++) { | |
179 ContentLayerClient::PaintingControlSetting painting_control = | |
180 ContentLayerClient::PAINTING_BEHAVIOR_NORMAL; | |
181 switch (static_cast<RecordingSource::RecordingMode>(mode_index)) { | |
182 case RecordingSource::RECORD_NORMALLY: | |
183 // Already setup for normal recording. | |
184 break; | |
185 case RecordingSource::RECORD_WITH_SK_NULL_CANVAS: | |
186 // TODO(schenney): Remove this when DisplayList recording is the only | |
187 // option. For now, fall through and disable construction. | |
188 case RecordingSource::RECORD_WITH_PAINTING_DISABLED: | |
189 painting_control = | |
190 ContentLayerClient::DISPLAY_LIST_CONSTRUCTION_DISABLED; | |
191 break; | |
192 case RecordingSource::RECORD_WITH_CACHING_DISABLED: | |
193 painting_control = ContentLayerClient::DISPLAY_LIST_CACHING_DISABLED; | |
194 break; | |
195 default: | |
196 NOTREACHED(); | |
197 } | |
198 base::TimeDelta min_time = base::TimeDelta::Max(); | |
199 size_t memory_used = 0; | |
200 | |
201 scoped_refptr<DisplayItemList> display_list; | |
202 for (int i = 0; i < record_repeat_count_; ++i) { | |
203 // Run for a minimum amount of time to avoid problems with timer | |
204 // quantization when the layer is very small. | |
205 LapTimer timer(kWarmupRuns, | |
206 base::TimeDelta::FromMilliseconds(kTimeLimitMillis), | |
207 kTimeCheckInterval); | |
208 | |
209 do { | |
210 display_list = painter->PaintContentsToDisplayList(visible_content_rect, | |
211 painting_control); | |
212 | |
213 if (memory_used) { | |
214 // Verify we are recording the same thing each time. | |
215 DCHECK(memory_used == display_list->PictureMemoryUsage()); | |
216 } else { | |
217 memory_used = display_list->PictureMemoryUsage(); | |
218 } | |
219 | |
220 timer.NextLap(); | |
221 } while (!timer.HasTimeLimitExpired()); | |
222 base::TimeDelta duration = | |
223 base::TimeDelta::FromMillisecondsD(timer.MsPerLap()); | |
224 if (duration < min_time) | |
225 min_time = duration; | |
226 } | |
227 | |
228 if (mode_index == RecordingSource::RECORD_NORMALLY) { | |
229 record_results_.bytes_used += memory_used; | |
230 record_results_.pixels_recorded += | |
231 visible_content_rect.width() * visible_content_rect.height(); | |
232 } | |
233 record_results_.total_best_time[mode_index] += min_time; | |
234 } | |
235 } | |
236 | |
237 RasterizeAndRecordBenchmark::RecordResults::RecordResults() | |
238 : pixels_recorded(0), bytes_used(0) { | |
239 } | |
240 | |
241 RasterizeAndRecordBenchmark::RecordResults::~RecordResults() {} | |
242 | |
243 } // namespace cc | |
OLD | NEW |