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/layer.h"
17#include "cc/layers/picture_layer.h"
18#include "cc/trees/layer_tree_host.h"
19#include "cc/trees/layer_tree_host_common.h"
20#include "ui/gfx/rect.h"
21
22namespace cc {
23
24namespace {
25
26const int kDefaultRecordRepeatCount = 100;
27
28const char* kModeSuffixes[Picture::RECORDING_MODE_COUNT] = {
29    "", "_sk_null_canvas", "_painting_disabled", "_skrecord"};
30
31}  // namespace
32
33RasterizeAndRecordBenchmark::RasterizeAndRecordBenchmark(
34    scoped_ptr<base::Value> value,
35    const MicroBenchmark::DoneCallback& callback)
36    : MicroBenchmark(callback),
37      record_repeat_count_(kDefaultRecordRepeatCount),
38      settings_(value.Pass()),
39      main_thread_benchmark_done_(false),
40      host_(NULL),
41      weak_ptr_factory_(this) {
42  base::DictionaryValue* settings = NULL;
43  settings_->GetAsDictionary(&settings);
44  if (!settings)
45    return;
46
47  if (settings->HasKey("record_repeat_count"))
48    settings->GetInteger("record_repeat_count", &record_repeat_count_);
49}
50
51RasterizeAndRecordBenchmark::~RasterizeAndRecordBenchmark() {
52  weak_ptr_factory_.InvalidateWeakPtrs();
53}
54
55void RasterizeAndRecordBenchmark::DidUpdateLayers(LayerTreeHost* host) {
56  host_ = host;
57  LayerTreeHostCommon::CallFunctionForSubtree(
58      host->root_layer(),
59      base::Bind(&RasterizeAndRecordBenchmark::Run, base::Unretained(this)));
60
61  DCHECK(!results_.get());
62  results_ = make_scoped_ptr(new base::DictionaryValue);
63  results_->SetInteger("pixels_recorded", record_results_.pixels_recorded);
64
65  for (int i = 0; i < Picture::RECORDING_MODE_COUNT; i++) {
66    std::string name = base::StringPrintf("record_time%s_ms", kModeSuffixes[i]);
67    results_->SetDouble(name,
68                        record_results_.total_best_time[i].InMillisecondsF());
69  }
70  main_thread_benchmark_done_ = true;
71}
72
73void RasterizeAndRecordBenchmark::RecordRasterResults(
74    scoped_ptr<base::Value> results_value) {
75  DCHECK(main_thread_benchmark_done_);
76
77  base::DictionaryValue* results = NULL;
78  results_value->GetAsDictionary(&results);
79  DCHECK(results);
80
81  results_->MergeDictionary(results);
82
83  NotifyDone(results_.PassAs<base::Value>());
84}
85
86scoped_ptr<MicroBenchmarkImpl> RasterizeAndRecordBenchmark::CreateBenchmarkImpl(
87    scoped_refptr<base::MessageLoopProxy> origin_loop) {
88  return scoped_ptr<MicroBenchmarkImpl>(new RasterizeAndRecordBenchmarkImpl(
89      origin_loop,
90      settings_.get(),
91      base::Bind(&RasterizeAndRecordBenchmark::RecordRasterResults,
92                 weak_ptr_factory_.GetWeakPtr())));
93}
94
95void RasterizeAndRecordBenchmark::Run(Layer* layer) {
96  layer->RunMicroBenchmark(this);
97}
98
99void RasterizeAndRecordBenchmark::RunOnLayer(PictureLayer* layer) {
100  ContentLayerClient* painter = layer->client();
101  gfx::Size content_bounds = layer->content_bounds();
102
103  DCHECK(host_);
104  gfx::Size tile_grid_size = host_->settings().default_tile_size;
105
106  SkTileGridFactory::TileGridInfo tile_grid_info;
107  PicturePileBase::ComputeTileGridInfo(tile_grid_size, &tile_grid_info);
108
109  gfx::Rect visible_content_rect = gfx::ScaleToEnclosingRect(
110      layer->visible_content_rect(), 1.f / layer->contents_scale_x());
111  if (visible_content_rect.IsEmpty())
112    return;
113
114  for (int mode_index = 0; mode_index < Picture::RECORDING_MODE_COUNT;
115       mode_index++) {
116    Picture::RecordingMode mode =
117        static_cast<Picture::RecordingMode>(mode_index);
118    base::TimeDelta min_time = base::TimeDelta::Max();
119
120    // Parameters for LapTimer.
121    const int kTimeLimitMillis = 1;
122    const int kWarmupRuns = 0;
123    const int kTimeCheckInterval = 1;
124
125    for (int i = 0; i < record_repeat_count_; ++i) {
126      // Run for a minimum amount of time to avoid problems with timer
127      // quantization when the layer is very small.
128      LapTimer timer(kWarmupRuns,
129                     base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
130                     kTimeCheckInterval);
131      do {
132        scoped_refptr<Picture> picture = Picture::Create(
133            visible_content_rect, painter, tile_grid_info, false, mode);
134        timer.NextLap();
135      } while (!timer.HasTimeLimitExpired());
136      base::TimeDelta duration =
137          base::TimeDelta::FromMillisecondsD(timer.MsPerLap());
138      if (duration < min_time)
139        min_time = duration;
140    }
141
142    if (mode == Picture::RECORD_NORMALLY) {
143      record_results_.pixels_recorded +=
144          visible_content_rect.width() * visible_content_rect.height();
145    }
146    record_results_.total_best_time[mode_index] += min_time;
147  }
148}
149
150RasterizeAndRecordBenchmark::RecordResults::RecordResults()
151    : pixels_recorded(0) {}
152
153RasterizeAndRecordBenchmark::RecordResults::~RecordResults() {}
154
155}  // namespace cc
156