Commit 8cac9fe3 authored by vmpstr@chromium.org's avatar vmpstr@chromium.org

cc: Add rasterize and record micro benchmark.

This patch adds a rasterize and record micro benchmark.
It depends on

https://codereview.chromium.org/67563002/

R=enne@chromium.org, nduca@chromium.org, ernstm@chromium.org

Review URL: https://codereview.chromium.org/66213007

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@235805 0039d316-1c4b-4281-b951-d872f2087c98
parent 7b06b28a
...@@ -94,6 +94,10 @@ ...@@ -94,6 +94,10 @@
'debug/paint_time_counter.h', 'debug/paint_time_counter.h',
'debug/picture_record_benchmark.cc', 'debug/picture_record_benchmark.cc',
'debug/picture_record_benchmark.h', 'debug/picture_record_benchmark.h',
'debug/rasterize_and_record_benchmark.cc',
'debug/rasterize_and_record_benchmark.h',
'debug/rasterize_and_record_benchmark_impl.cc',
'debug/rasterize_and_record_benchmark_impl.h',
'debug/rendering_stats.cc', 'debug/rendering_stats.cc',
'debug/rendering_stats.h', 'debug/rendering_stats.h',
'debug/rendering_stats_instrumentation.cc', 'debug/rendering_stats_instrumentation.cc',
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/message_loop/message_loop_proxy.h" #include "base/message_loop/message_loop_proxy.h"
#include "base/values.h" #include "base/values.h"
#include "cc/debug/picture_record_benchmark.h" #include "cc/debug/picture_record_benchmark.h"
#include "cc/debug/rasterize_and_record_benchmark.h"
#include "cc/debug/unittest_only_benchmark.h" #include "cc/debug/unittest_only_benchmark.h"
#include "cc/trees/layer_tree_host.h" #include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_host_impl.h" #include "cc/trees/layer_tree_host_impl.h"
...@@ -25,6 +26,9 @@ scoped_ptr<MicroBenchmark> CreateBenchmark( ...@@ -25,6 +26,9 @@ scoped_ptr<MicroBenchmark> CreateBenchmark(
if (name == "picture_record_benchmark") { if (name == "picture_record_benchmark") {
return scoped_ptr<MicroBenchmark>( return scoped_ptr<MicroBenchmark>(
new PictureRecordBenchmark(value.Pass(), callback)); new PictureRecordBenchmark(value.Pass(), callback));
} else if (name == "rasterize_and_record_benchmark") {
return scoped_ptr<MicroBenchmark>(
new RasterizeAndRecordBenchmark(value.Pass(), callback));
} else if (name == "unittest_only_benchmark") { } else if (name == "unittest_only_benchmark") {
return scoped_ptr<MicroBenchmark>( return scoped_ptr<MicroBenchmark>(
new UnittestOnlyBenchmark(value.Pass(), callback)); new UnittestOnlyBenchmark(value.Pass(), callback));
......
// 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 "base/basictypes.h"
#include "base/values.h"
#include "cc/debug/rasterize_and_record_benchmark_impl.h"
#include "cc/layers/layer.h"
#include "cc/layers/picture_layer.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_host_common.h"
#include "ui/gfx/rect.h"
namespace cc {
namespace {
const int kDefaultRecordRepeatCount = 100;
base::TimeTicks Now() {
return base::TimeTicks::IsThreadNowSupported()
? base::TimeTicks::ThreadNow()
: base::TimeTicks::HighResNow();
}
} // 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_(NULL),
weak_ptr_factory_(this) {
base::DictionaryValue* settings = NULL;
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_->SetDouble("record_time_ms",
record_results_.total_best_time.InMillisecondsF());
main_thread_benchmark_done_ = true;
}
void RasterizeAndRecordBenchmark::RecordRasterResults(
scoped_ptr<base::Value> results_value) {
DCHECK(main_thread_benchmark_done_);
base::DictionaryValue* results = NULL;
results_value->GetAsDictionary(&results);
DCHECK(results);
DCHECK(results->HasKey("pixels_rasterized"));
DCHECK(results->HasKey("rasterize_time_ms"));
int pixels_rasterized;
results->GetInteger("pixels_rasterized", &pixels_rasterized);
double rasterize_time_ms;
results->GetDouble("rasterize_time_ms", &rasterize_time_ms);
results_->SetInteger("pixels_rasterized", pixels_rasterized);
results_->SetDouble("rasterize_time_ms", rasterize_time_ms);
NotifyDone(results_.PassAs<base::Value>());
}
scoped_ptr<MicroBenchmarkImpl> RasterizeAndRecordBenchmark::CreateBenchmarkImpl(
scoped_refptr<base::MessageLoopProxy> origin_loop) {
return scoped_ptr<MicroBenchmarkImpl>(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;
SkTileGridPicture::TileGridInfo tile_grid_info;
PicturePileBase::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;
scoped_refptr<Picture> picture = Picture::Create(visible_content_rect);
base::TimeDelta min_time =
base::TimeDelta::FromInternalValue(std::numeric_limits<int64>::max());
for (int i = 0; i < record_repeat_count_; ++i) {
base::TimeTicks start = Now();
picture->Record(painter, tile_grid_info);
base::TimeTicks end = Now();
base::TimeDelta duration = end - start;
if (duration < min_time)
min_time = duration;
}
record_results_.pixels_recorded +=
visible_content_rect.width() * visible_content_rect.height();
record_results_.total_best_time += min_time;
}
RasterizeAndRecordBenchmark::RecordResults::RecordResults()
: pixels_recorded(0) {}
RasterizeAndRecordBenchmark::RecordResults::~RecordResults() {}
} // namespace cc
// 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.
#ifndef CC_DEBUG_RASTERIZE_AND_RECORD_BENCHMARK_H_
#define CC_DEBUG_RASTERIZE_AND_RECORD_BENCHMARK_H_
#include <map>
#include <utility>
#include <vector>
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "cc/debug/micro_benchmark_controller.h"
namespace base {
class DictionaryValue;
}
namespace cc {
class LayerTreeHost;
class Layer;
class RasterizeAndRecordBenchmark : public MicroBenchmark {
public:
explicit RasterizeAndRecordBenchmark(
scoped_ptr<base::Value> value,
const MicroBenchmark::DoneCallback& callback);
virtual ~RasterizeAndRecordBenchmark();
// Implements MicroBenchmark interface.
virtual void DidUpdateLayers(LayerTreeHost* host) OVERRIDE;
virtual void RunOnLayer(PictureLayer* layer) OVERRIDE;
virtual scoped_ptr<MicroBenchmarkImpl> CreateBenchmarkImpl(
scoped_refptr<base::MessageLoopProxy> origin_loop) OVERRIDE;
private:
void Run(Layer* layer);
void RecordRasterResults(scoped_ptr<base::Value> results);
struct RecordResults {
RecordResults();
~RecordResults();
int pixels_recorded;
base::TimeDelta total_best_time;
};
RecordResults record_results_;
int record_repeat_count_;
scoped_ptr<base::Value> settings_;
scoped_ptr<base::DictionaryValue> results_;
// The following is used in DCHECKs.
bool main_thread_benchmark_done_;
LayerTreeHost* host_;
base::WeakPtrFactory<RasterizeAndRecordBenchmark> weak_ptr_factory_;
};
} // namespace cc
#endif // CC_DEBUG_RASTERIZE_AND_RECORD_BENCHMARK_H_
// 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_impl.h"
#include <algorithm>
#include <limits>
#include "base/basictypes.h"
#include "base/values.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/picture_layer_impl.h"
#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/layer_tree_host_impl.h"
#include "ui/gfx/rect.h"
namespace cc {
namespace {
const int kDefaultRasterizeRepeatCount = 100;
base::TimeTicks Now() {
return base::TimeTicks::IsThreadNowSupported()
? base::TimeTicks::ThreadNow()
: base::TimeTicks::HighResNow();
}
} // namespace
RasterizeAndRecordBenchmarkImpl::RasterizeAndRecordBenchmarkImpl(
scoped_refptr<base::MessageLoopProxy> origin_loop,
base::Value* value,
const MicroBenchmarkImpl::DoneCallback& callback)
: MicroBenchmarkImpl(callback, origin_loop),
rasterize_repeat_count_(kDefaultRasterizeRepeatCount) {
base::DictionaryValue* settings = NULL;
value->GetAsDictionary(&settings);
if (!settings)
return;
if (settings->HasKey("rasterize_repeat_count"))
settings->GetInteger("rasterize_repeat_count", &rasterize_repeat_count_);
}
RasterizeAndRecordBenchmarkImpl::~RasterizeAndRecordBenchmarkImpl() {}
void RasterizeAndRecordBenchmarkImpl::DidCompleteCommit(
LayerTreeHostImpl* host) {
LayerTreeHostCommon::CallFunctionForSubtree(
host->RootLayer(),
base::Bind(&RasterizeAndRecordBenchmarkImpl::Run,
base::Unretained(this)));
scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
result->SetInteger("pixels_rasterized", rasterize_results_.pixels_rasterized);
result->SetDouble("rasterize_time_ms",
rasterize_results_.total_best_time.InMillisecondsF());
NotifyDone(result.PassAs<base::Value>());
}
void RasterizeAndRecordBenchmarkImpl::Run(LayerImpl* layer) {
layer->RunMicroBenchmark(this);
}
void RasterizeAndRecordBenchmarkImpl::RunOnLayer(PictureLayerImpl* layer) {
if (layer->visible_content_rect().IsEmpty())
return;
PictureLayerTilingSet tiling_set(layer, layer->content_bounds());
PictureLayerTiling* tiling = tiling_set.AddTiling(layer->contents_scale_x());
tiling->CreateAllTilesForTesting();
for (PictureLayerTiling::CoverageIterator it(
tiling, layer->contents_scale_x(), layer->visible_content_rect());
it;
++it) {
DCHECK(*it);
PicturePileImpl* picture_pile = (*it)->picture_pile();
gfx::Rect content_rect = (*it)->content_rect();
float contents_scale = (*it)->contents_scale();
base::TimeDelta min_time =
base::TimeDelta::FromInternalValue(std::numeric_limits<int64>::max());
for (int i = 0; i < rasterize_repeat_count_; ++i) {
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config,
content_rect.width(),
content_rect.height());
bitmap.allocPixels();
SkBitmapDevice device(bitmap);
SkCanvas canvas(&device);
base::TimeTicks start = Now();
picture_pile->RasterToBitmap(&canvas, content_rect, contents_scale, NULL);
base::TimeTicks end = Now();
base::TimeDelta duration = end - start;
if (duration < min_time)
min_time = duration;
}
rasterize_results_.pixels_rasterized +=
content_rect.width() * content_rect.height();
rasterize_results_.total_best_time += min_time;
}
}
RasterizeAndRecordBenchmarkImpl::RasterizeResults::RasterizeResults()
: pixels_rasterized(0) {}
RasterizeAndRecordBenchmarkImpl::RasterizeResults::~RasterizeResults() {}
} // namespace cc
// 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.
#ifndef CC_DEBUG_RASTERIZE_AND_RECORD_BENCHMARK_IMPL_H_
#define CC_DEBUG_RASTERIZE_AND_RECORD_BENCHMARK_IMPL_H_
#include <map>
#include <utility>
#include <vector>
#include "base/time/time.h"
#include "cc/debug/micro_benchmark_impl.h"
namespace cc {
class LayerTreeHostImpl;
class PictureLayerImpl;
class LayerImpl;
class RasterizeAndRecordBenchmarkImpl : public MicroBenchmarkImpl {
public:
explicit RasterizeAndRecordBenchmarkImpl(
scoped_refptr<base::MessageLoopProxy> origin_loop,
base::Value* value,
const MicroBenchmarkImpl::DoneCallback& callback);
virtual ~RasterizeAndRecordBenchmarkImpl();
// Implements MicroBenchmark interface.
virtual void DidCompleteCommit(LayerTreeHostImpl* host) OVERRIDE;
virtual void RunOnLayer(PictureLayerImpl* layer) OVERRIDE;
private:
void Run(LayerImpl* layer);
struct RasterizeResults {
RasterizeResults();
~RasterizeResults();
int pixels_rasterized;
base::TimeDelta total_best_time;
};
RasterizeResults rasterize_results_;
int rasterize_repeat_count_;
};
} // namespace cc
#endif // CC_DEBUG_RASTERIZE_AND_RECORD_BENCHMARK_IMPL_H_
...@@ -128,19 +128,24 @@ void PicturePileBase::SetMinContentsScale(float min_contents_scale) { ...@@ -128,19 +128,24 @@ void PicturePileBase::SetMinContentsScale(float min_contents_scale) {
min_contents_scale_ = min_contents_scale; min_contents_scale_ = min_contents_scale;
} }
void PicturePileBase::SetTileGridSize(gfx::Size tile_grid_size) { // static
tile_grid_info_.fTileInterval.set( void PicturePileBase::ComputeTileGridInfo(
tile_grid_size.width() - 2 * kTileGridBorderPixels, gfx::Size tile_grid_size,
tile_grid_size.height() - 2 * kTileGridBorderPixels); SkTileGridPicture::TileGridInfo* info) {
DCHECK_GT(tile_grid_info_.fTileInterval.width(), 0); DCHECK(info);
DCHECK_GT(tile_grid_info_.fTileInterval.height(), 0); info->fTileInterval.set(tile_grid_size.width() - 2 * kTileGridBorderPixels,
tile_grid_info_.fMargin.set(kTileGridBorderPixels, tile_grid_size.height() - 2 * kTileGridBorderPixels);
kTileGridBorderPixels); DCHECK_GT(info->fTileInterval.width(), 0);
DCHECK_GT(info->fTileInterval.height(), 0);
info->fMargin.set(kTileGridBorderPixels, kTileGridBorderPixels);
// Offset the tile grid coordinate space to take into account the fact // Offset the tile grid coordinate space to take into account the fact
// that the top-most and left-most tiles do not have top and left borders // that the top-most and left-most tiles do not have top and left borders
// respectively. // respectively.
tile_grid_info_.fOffset.set(-kTileGridBorderPixels, info->fOffset.set(-kTileGridBorderPixels, -kTileGridBorderPixels);
-kTileGridBorderPixels); }
void PicturePileBase::SetTileGridSize(gfx::Size tile_grid_size) {
ComputeTileGridInfo(tile_grid_size, &tile_grid_info_);
} }
void PicturePileBase::SetBufferPixels(int new_buffer_pixels) { void PicturePileBase::SetBufferPixels(int new_buffer_pixels) {
......
...@@ -41,6 +41,9 @@ class CC_EXPORT PicturePileBase : public base::RefCounted<PicturePileBase> { ...@@ -41,6 +41,9 @@ class CC_EXPORT PicturePileBase : public base::RefCounted<PicturePileBase> {
bool HasRecordingAt(int x, int y); bool HasRecordingAt(int x, int y);
bool CanRaster(float contents_scale, gfx::Rect content_rect); bool CanRaster(float contents_scale, gfx::Rect content_rect);
static void ComputeTileGridInfo(gfx::Size tile_grid_size,
SkTileGridPicture::TileGridInfo* info);
void SetTileGridSize(gfx::Size tile_grid_size); void SetTileGridSize(gfx::Size tile_grid_size);
TilingData& tiling() { return tiling_; } TilingData& tiling() { return tiling_; }
......
# 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.
import time
from telemetry.core.util import TimeoutException
from telemetry.page import page_measurement
class NewRasterizeAndRecord(page_measurement.PageMeasurement):
def __init__(self):
super(NewRasterizeAndRecord, self).__init__('', True)
def AddCommandLineOptions(self, parser):
parser.add_option('--start-wait-time', dest='start_wait_time',
default=2,
help='Wait time before the benchmark is started ' +
'(must be long enought to load all content)')
parser.add_option('--rasterize_repeat', dest='rasterize_repeat',
default=100,
help='Repeat each raster this many times. Increase ' +
'this value to reduce variance.')
parser.add_option('--record_repeat', dest='record_repeat',
default=100,
help='Repeat each record this many times. Increase ' +
'this value to reduce variance.')
def CustomizeBrowserOptions(self, options):
options.AppendExtraBrowserArgs([
'--enable-impl-side-painting',
'--force-compositing-mode',
'--enable-threaded-compositing',
'--enable-gpu-benchmarking'
])
def MeasurePage(self, page, tab, results):
try:
tab.WaitForJavaScriptExpression("document.readyState == 'complete'", 10)
except TimeoutException:
pass
time.sleep(float(self.options.start_wait_time))
record_repeat = self.options.record_repeat
rasterize_repeat = self.options.rasterize_repeat
# Enqueue benchmark
tab.ExecuteJavaScript("""
window.benchmark_results = {};
window.benchmark_results.done = false;
chrome.gpuBenchmarking.runMicroBenchmark(
"rasterize_and_record_benchmark",
function(value) {
window.benchmark_results.done = true;
window.benchmark_results.results = value;
}, {
"record_repeat_count": """ + str(record_repeat) + """,
"rasterize_repeat_count": """ + str(rasterize_repeat) + """
});
""")
tab.WaitForJavaScriptExpression('window.benchmark_results.done', 300)
data = tab.EvaluateJavaScript('window.benchmark_results.results')
pixels_recorded = data['pixels_recorded']
record_time = data['record_time_ms']
pixels_rasterized = data['pixels_rasterized']
rasterize_time = data['rasterize_time_ms']
results.Add('pixels_recorded', '', pixels_recorded)
results.Add('record_time', 'ms', record_time)
results.Add('pixels_rasterized', '', pixels_rasterized)
results.Add('rasterize_time', 'ms', rasterize_time)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment