blob: 41d62100fb26d15204cc279e8c5af81c85926cde [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cc/debug/rasterize_and_record_benchmark.h"
#include <algorithm>
#include <limits>
#include <string>
#include "base/basictypes.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "cc/debug/lap_timer.h"
#include "cc/debug/rasterize_and_record_benchmark_impl.h"
#include "cc/layers/layer.h"
#include "cc/layers/picture_layer.h"
#include "cc/resources/picture_pile.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_host_common.h"
#include "third_party/skia/include/utils/SkPictureUtils.h"
#include "ui/gfx/geometry/rect.h"
namespace cc {
namespace {
const int kDefaultRecordRepeatCount = 100;
const char* kModeSuffixes[Picture::RECORDING_MODE_COUNT] = {
"",
"_sk_null_canvas",
"_painting_disabled"};
} // namespace
RasterizeAndRecordBenchmark::RasterizeAndRecordBenchmark(
scoped_ptr<base::Value> value,
const MicroBenchmark::DoneCallback& callback)
: MicroBenchmark(callback),
record_repeat_count_(kDefaultRecordRepeatCount),
settings_(value.Pass()),
main_thread_benchmark_done_(false),
host_(nullptr),
weak_ptr_factory_(this) {
base::DictionaryValue* settings = nullptr;
settings_->GetAsDictionary(&settings);
if (!settings)
return;
if (settings->HasKey("record_repeat_count"))
settings->GetInteger("record_repeat_count", &record_repeat_count_);
}
RasterizeAndRecordBenchmark::~RasterizeAndRecordBenchmark() {
weak_ptr_factory_.InvalidateWeakPtrs();
}
void RasterizeAndRecordBenchmark::DidUpdateLayers(LayerTreeHost* host) {
host_ = host;
LayerTreeHostCommon::CallFunctionForSubtree(
host->root_layer(),
base::Bind(&RasterizeAndRecordBenchmark::Run, base::Unretained(this)));
DCHECK(!results_.get());
results_ = make_scoped_ptr(new base::DictionaryValue);
results_->SetInteger("pixels_recorded", record_results_.pixels_recorded);
results_->SetInteger("picture_memory_usage", record_results_.bytes_used);
for (int i = 0; i < Picture::RECORDING_MODE_COUNT; i++) {
std::string name = base::StringPrintf("record_time%s_ms", kModeSuffixes[i]);
results_->SetDouble(name,
record_results_.total_best_time[i].InMillisecondsF());
}
main_thread_benchmark_done_ = true;
}
void RasterizeAndRecordBenchmark::RecordRasterResults(
scoped_ptr<base::Value> results_value) {
DCHECK(main_thread_benchmark_done_);
base::DictionaryValue* results = nullptr;
results_value->GetAsDictionary(&results);
DCHECK(results);
results_->MergeDictionary(results);
NotifyDone(results_.Pass());
}
scoped_ptr<MicroBenchmarkImpl> RasterizeAndRecordBenchmark::CreateBenchmarkImpl(
scoped_refptr<base::MessageLoopProxy> origin_loop) {
return make_scoped_ptr(new RasterizeAndRecordBenchmarkImpl(
origin_loop,
settings_.get(),
base::Bind(&RasterizeAndRecordBenchmark::RecordRasterResults,
weak_ptr_factory_.GetWeakPtr())));
}
void RasterizeAndRecordBenchmark::Run(Layer* layer) {
layer->RunMicroBenchmark(this);
}
void RasterizeAndRecordBenchmark::RunOnLayer(PictureLayer* layer) {
ContentLayerClient* painter = layer->client();
gfx::Size content_bounds = layer->content_bounds();
DCHECK(host_);
gfx::Size tile_grid_size = host_->settings().default_tile_size;
SkTileGridFactory::TileGridInfo tile_grid_info;
PicturePile::ComputeTileGridInfo(tile_grid_size, &tile_grid_info);
gfx::Rect visible_content_rect = gfx::ScaleToEnclosingRect(
layer->visible_content_rect(), 1.f / layer->contents_scale_x());
if (visible_content_rect.IsEmpty())
return;
for (int mode_index = 0; mode_index < Picture::RECORDING_MODE_COUNT;
mode_index++) {
Picture::RecordingMode mode =
static_cast<Picture::RecordingMode>(mode_index);
base::TimeDelta min_time = base::TimeDelta::Max();
size_t memory_used = 0;
// Parameters for LapTimer.
const int kTimeLimitMillis = 1;
const int kWarmupRuns = 0;
const int kTimeCheckInterval = 1;
for (int i = 0; i < record_repeat_count_; ++i) {
// Run for a minimum amount of time to avoid problems with timer
// quantization when the layer is very small.
LapTimer timer(kWarmupRuns,
base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
kTimeCheckInterval);
scoped_refptr<Picture> picture;
do {
picture = Picture::Create(visible_content_rect, painter, tile_grid_info,
false, mode);
timer.NextLap();
} while (!timer.HasTimeLimitExpired());
base::TimeDelta duration =
base::TimeDelta::FromMillisecondsD(timer.MsPerLap());
if (duration < min_time)
min_time = duration;
memory_used = picture->ApproximateMemoryUsage();
}
if (mode == Picture::RECORD_NORMALLY) {
record_results_.bytes_used += memory_used;
record_results_.pixels_recorded +=
visible_content_rect.width() * visible_content_rect.height();
}
record_results_.total_best_time[mode_index] += min_time;
}
}
RasterizeAndRecordBenchmark::RecordResults::RecordResults()
: pixels_recorded(0), bytes_used(0) {
}
RasterizeAndRecordBenchmark::RecordResults::~RecordResults() {}
} // namespace cc