Fix build problem with reverted issue 16948011
BUG= R=caryclark@google.com Author: sglez@google.com Review URL: https://chromiumcodereview.appspot.com/19541009 git-svn-id: http://skia.googlecode.com/svn/trunk@10201 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
fc70a4ae59
commit
6645cde43d
@ -15,7 +15,7 @@
|
||||
'dependencies': [
|
||||
'bench_pictures',
|
||||
'filter',
|
||||
'lua_pictures',
|
||||
'bbh_shootout',
|
||||
'lua_app',
|
||||
'pinspect',
|
||||
'render_pdfs',
|
||||
@ -299,6 +299,28 @@
|
||||
'flags.gyp:flags',
|
||||
],
|
||||
},
|
||||
{
|
||||
'target_name': 'bbh_shootout',
|
||||
'type': 'executable',
|
||||
'include_dirs': [
|
||||
'../bench',
|
||||
'../tools/'
|
||||
],
|
||||
'sources': [
|
||||
'../tools/bbh_shootout.cpp',
|
||||
|
||||
# Bench code:
|
||||
'../bench/TimerData.h',
|
||||
'../bench/TimerData.cpp',
|
||||
],
|
||||
'dependencies': [
|
||||
'skia_lib.gyp:skia_lib',
|
||||
'bench.gyp:bench_timer',
|
||||
'tools.gyp:picture_utils',
|
||||
'tools.gyp:picture_renderer',
|
||||
'flags.gyp:flags',
|
||||
],
|
||||
},
|
||||
{
|
||||
'target_name': 'filter',
|
||||
'type': 'executable',
|
||||
|
385
tools/bbh_shootout.cpp
Normal file
385
tools/bbh_shootout.cpp
Normal file
@ -0,0 +1,385 @@
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "BenchTimer.h"
|
||||
#include "LazyDecodeBitmap.h"
|
||||
#include "PictureBenchmark.h"
|
||||
#include "PictureRenderer.h"
|
||||
#include "SkBenchmark.h"
|
||||
#include "SkForceLinking.h"
|
||||
#include "SkGraphics.h"
|
||||
#include "SkStream.h"
|
||||
#include "SkString.h"
|
||||
#include "TimerData.h"
|
||||
|
||||
static const int kNumNormalRecordings = SkBENCHLOOP(10);
|
||||
static const int kNumRTreeRecordings = SkBENCHLOOP(10);
|
||||
static const int kNumPlaybacks = SkBENCHLOOP(4);
|
||||
static const size_t kNumBaseBenchmarks = 3;
|
||||
static const size_t kNumTileSizes = 3;
|
||||
static const size_t kNumBbhPlaybackBenchmarks = 3;
|
||||
static const size_t kNumBenchmarks = kNumBaseBenchmarks + kNumBbhPlaybackBenchmarks;
|
||||
|
||||
enum BenchmarkType {
|
||||
kNormal_BenchmarkType = 0,
|
||||
kRTree_BenchmarkType,
|
||||
};
|
||||
|
||||
struct Histogram {
|
||||
Histogram() {
|
||||
// Make fCpuTime negative so that we don't mess with stats:
|
||||
fCpuTime = SkIntToScalar(-1);
|
||||
}
|
||||
SkScalar fCpuTime;
|
||||
SkString fPath;
|
||||
};
|
||||
|
||||
typedef void (*BenchmarkFunction)
|
||||
(BenchmarkType, const SkISize&, const SkString&, SkPicture*, BenchTimer*);
|
||||
|
||||
// Defined below.
|
||||
static void benchmark_playback(
|
||||
BenchmarkType, const SkISize&, const SkString&, SkPicture*, BenchTimer*);
|
||||
static void benchmark_recording(
|
||||
BenchmarkType, const SkISize&, const SkString&, SkPicture*, BenchTimer*);
|
||||
|
||||
/**
|
||||
* Acts as a POD containing information needed to run a benchmark.
|
||||
* Provides static methods to poll benchmark info from an index.
|
||||
*/
|
||||
struct BenchmarkControl {
|
||||
SkISize fTileSize;
|
||||
BenchmarkType fType;
|
||||
BenchmarkFunction fFunction;
|
||||
SkString fName;
|
||||
|
||||
/**
|
||||
* Will construct a BenchmarkControl instance from an index between 0 an kNumBenchmarks.
|
||||
*/
|
||||
static BenchmarkControl Make(size_t i) {
|
||||
SkASSERT(kNumBenchmarks > i);
|
||||
BenchmarkControl benchControl;
|
||||
benchControl.fTileSize = getTileSize(i);
|
||||
benchControl.fType = getBenchmarkType(i);
|
||||
benchControl.fFunction = getBenchmarkFunc(i);
|
||||
benchControl.fName = getBenchmarkName(i);
|
||||
return benchControl;
|
||||
}
|
||||
|
||||
enum BaseBenchmarks {
|
||||
kNormalRecord = 0,
|
||||
kRTreeRecord,
|
||||
kNormalPlayback,
|
||||
};
|
||||
|
||||
static SkISize fTileSizes[kNumTileSizes];
|
||||
|
||||
static SkISize getTileSize(size_t i) {
|
||||
// Two of the base benchmarks don't need a tile size. But to maintain simplicity
|
||||
// down the pipeline we have to let a couple of values unused.
|
||||
if (i < kNumBaseBenchmarks) {
|
||||
return SkISize::Make(256, 256);
|
||||
}
|
||||
if (i >= kNumBaseBenchmarks && i < kNumBenchmarks) {
|
||||
return fTileSizes[i - kNumBaseBenchmarks];
|
||||
}
|
||||
SkASSERT(0);
|
||||
return SkISize::Make(0, 0);
|
||||
}
|
||||
|
||||
static BenchmarkType getBenchmarkType(size_t i) {
|
||||
if (i < kNumBaseBenchmarks) {
|
||||
switch (i) {
|
||||
case kNormalRecord:
|
||||
return kNormal_BenchmarkType;
|
||||
case kNormalPlayback:
|
||||
return kNormal_BenchmarkType;
|
||||
case kRTreeRecord:
|
||||
return kRTree_BenchmarkType;
|
||||
}
|
||||
}
|
||||
if (i < kNumBenchmarks) {
|
||||
return kRTree_BenchmarkType;
|
||||
}
|
||||
SkASSERT(0);
|
||||
return kRTree_BenchmarkType;
|
||||
}
|
||||
|
||||
static BenchmarkFunction getBenchmarkFunc(size_t i) {
|
||||
// Base functions.
|
||||
switch (i) {
|
||||
case kNormalRecord:
|
||||
return benchmark_recording;
|
||||
case kNormalPlayback:
|
||||
return benchmark_playback;
|
||||
case kRTreeRecord:
|
||||
return benchmark_recording;
|
||||
}
|
||||
// RTree playbacks
|
||||
if (i < kNumBenchmarks) {
|
||||
return benchmark_playback;
|
||||
}
|
||||
SkASSERT(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static SkString getBenchmarkName(size_t i) {
|
||||
// Base benchmark names
|
||||
switch (i) {
|
||||
case kNormalRecord:
|
||||
return SkString("normal_recording");
|
||||
case kNormalPlayback:
|
||||
return SkString("normal_playback");
|
||||
case kRTreeRecord:
|
||||
return SkString("rtree_recording");
|
||||
}
|
||||
// RTree benchmark names.
|
||||
if (i < kNumBenchmarks) {
|
||||
SkASSERT(i >= kNumBaseBenchmarks);
|
||||
SkString name;
|
||||
name.printf("rtree_playback_%dx%d",
|
||||
fTileSizes[i - kNumBaseBenchmarks].fWidth,
|
||||
fTileSizes[i - kNumBaseBenchmarks].fHeight);
|
||||
return name;
|
||||
|
||||
} else {
|
||||
SkASSERT(0);
|
||||
}
|
||||
return SkString("");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
SkISize BenchmarkControl::fTileSizes[kNumTileSizes] = {
|
||||
SkISize::Make(256, 256),
|
||||
SkISize::Make(512, 512),
|
||||
SkISize::Make(1024, 1024),
|
||||
};
|
||||
|
||||
static SkPicture* pic_from_path(const char path[]) {
|
||||
SkFILEStream stream(path);
|
||||
if (!stream.isValid()) {
|
||||
SkDebugf("-- Can't open '%s'\n", path);
|
||||
return NULL;
|
||||
}
|
||||
return SkPicture::CreateFromStream(&stream, &sk_tools::LazyDecodeBitmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is the sink to which all work ends up going.
|
||||
* Renders the picture into the renderer. It may or may not use an RTree.
|
||||
* The renderer is chosen upstream. If we want to measure recording, we will
|
||||
* use a RecordPictureRenderer. If we want to measure rendering, we eill use a
|
||||
* TiledPictureRenderer.
|
||||
*/
|
||||
static void do_benchmark_work(sk_tools::PictureRenderer* renderer,
|
||||
int benchmarkType, const SkString& path, SkPicture* pic,
|
||||
const int numRepeats, const char *msg, BenchTimer* timer) {
|
||||
SkString msgPrefix;
|
||||
|
||||
switch (benchmarkType){
|
||||
case kNormal_BenchmarkType:
|
||||
msgPrefix.set("Normal");
|
||||
renderer->setBBoxHierarchyType(sk_tools::PictureRenderer::kNone_BBoxHierarchyType);
|
||||
break;
|
||||
case kRTree_BenchmarkType:
|
||||
msgPrefix.set("RTree");
|
||||
renderer->setBBoxHierarchyType(sk_tools::PictureRenderer::kRTree_BBoxHierarchyType);
|
||||
break;
|
||||
default:
|
||||
SkASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
renderer->init(pic);
|
||||
|
||||
/**
|
||||
* If the renderer is not tiled, assume we are measuring recording.
|
||||
*/
|
||||
bool isPlayback = (NULL != renderer->getTiledRenderer());
|
||||
|
||||
SkDebugf("%s %s %s %d times...\n", msgPrefix.c_str(), msg, path.c_str(), numRepeats);
|
||||
for (int i = 0; i < numRepeats; ++i) {
|
||||
renderer->setup();
|
||||
// Render once to fill caches.
|
||||
renderer->render(NULL);
|
||||
// Render again to measure
|
||||
timer->start();
|
||||
bool result = renderer->render(NULL);
|
||||
timer->end();
|
||||
// We only care about a false result on playback. RecordPictureRenderer::render will always
|
||||
// return false because we are passing a NULL file name on purpose; which is fine.
|
||||
if(isPlayback && !result) {
|
||||
SkDebugf("Error rendering during playback.\n");
|
||||
}
|
||||
}
|
||||
renderer->end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call do_benchmark_work with a tiled renderer using the default tile dimensions.
|
||||
*/
|
||||
static void benchmark_playback(
|
||||
BenchmarkType benchmarkType, const SkISize& tileSize,
|
||||
const SkString& path, SkPicture* pic, BenchTimer* timer) {
|
||||
sk_tools::TiledPictureRenderer renderer;
|
||||
|
||||
SkString message("tiled_playback");
|
||||
message.appendf("_%dx%d", tileSize.fWidth, tileSize.fHeight);
|
||||
do_benchmark_work(&renderer, benchmarkType,
|
||||
path, pic, kNumPlaybacks, message.c_str(), timer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call do_benchmark_work with a RecordPictureRenderer.
|
||||
*/
|
||||
static void benchmark_recording(
|
||||
BenchmarkType benchmarkType, const SkISize& tileSize,
|
||||
const SkString& path, SkPicture* pic, BenchTimer* timer) {
|
||||
sk_tools::RecordPictureRenderer renderer;
|
||||
int numRecordings = 0;
|
||||
switch(benchmarkType) {
|
||||
case kRTree_BenchmarkType:
|
||||
numRecordings = kNumRTreeRecordings;
|
||||
break;
|
||||
case kNormal_BenchmarkType:
|
||||
numRecordings = kNumNormalRecordings;
|
||||
break;
|
||||
}
|
||||
do_benchmark_work(&renderer, benchmarkType, path, pic, numRecordings, "recording", timer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes argc,argv along with one of the benchmark functions defined above.
|
||||
* Will loop along all skp files and perform measurments.
|
||||
*
|
||||
* Returns a SkScalar representing CPU time taken during benchmark.
|
||||
* As a side effect, it spits the timer result to stdout.
|
||||
* Will return -1.0 on error.
|
||||
*/
|
||||
static bool benchmark_loop(
|
||||
int argc,
|
||||
char **argv,
|
||||
const BenchmarkControl& benchControl,
|
||||
SkTArray<Histogram>& histogram) {
|
||||
|
||||
static const SkString timeFormat("%f");
|
||||
TimerData timerData(timeFormat, timeFormat);
|
||||
for (int index = 1; index < argc; ++index) {
|
||||
BenchTimer timer;
|
||||
SkString path(argv[index]);
|
||||
SkAutoTUnref<SkPicture> pic(pic_from_path(path.c_str()));
|
||||
if (NULL == pic) {
|
||||
SkDebugf("Couldn't create picture. Ignoring path: %s\n", path.c_str());
|
||||
continue;
|
||||
}
|
||||
benchControl.fFunction(benchControl.fType, benchControl.fTileSize, path, pic, &timer);
|
||||
timerData.appendTimes(&timer, argc - 1 == index);
|
||||
|
||||
histogram[index - 1].fPath = path;
|
||||
histogram[index - 1].fCpuTime = SkDoubleToScalar(timer.fCpu);
|
||||
}
|
||||
|
||||
const SkString timerResult = timerData.getResult(
|
||||
/*logPerIter = */ false,
|
||||
/*printMin = */ false,
|
||||
/*repeatDraw = */ 1,
|
||||
/*configName = */ benchControl.fName.c_str(),
|
||||
/*showWallTime = */ false,
|
||||
/*showTruncatedWallTime = */ false,
|
||||
/*showCpuTime = */ true,
|
||||
/*showTruncatedCpuTime = */ false,
|
||||
/*showGpuTime = */ false);
|
||||
|
||||
const char findStr[] = "= ";
|
||||
int pos = timerResult.find(findStr);
|
||||
if (-1 == pos) {
|
||||
SkDebugf("Unexpected output from TimerData::getResult(...). Unable to parse.");
|
||||
return false;
|
||||
}
|
||||
|
||||
SkScalar cpuTime = SkDoubleToScalar(atof(timerResult.c_str() + pos + sizeof(findStr) - 1));
|
||||
if (cpuTime == 0) { // atof returns 0.0 on error.
|
||||
SkDebugf("Unable to read value from timer result.\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int tool_main(int argc, char** argv) {
|
||||
SkAutoGraphics ag;
|
||||
SkString usage;
|
||||
usage.printf("Usage: filename [filename]*\n");
|
||||
|
||||
if (argc < 2) {
|
||||
SkDebugf("%s\n", usage.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
static SkTArray<Histogram> histograms[kNumBenchmarks];
|
||||
|
||||
for (size_t i = 0; i < kNumBenchmarks; ++i) {
|
||||
histograms[i].reset(argc - 1);
|
||||
bool success = benchmark_loop(
|
||||
argc, argv,
|
||||
BenchmarkControl::Make(i),
|
||||
histograms[i]);
|
||||
if (!success) {
|
||||
SkDebugf("benchmark_loop failed at index %d", i);
|
||||
}
|
||||
}
|
||||
|
||||
// Output gnuplot readable histogram data..
|
||||
const char* pbTitle = "bbh_shootout_playback.dat";
|
||||
const char* recTitle = "bbh_shootout_record.dat";
|
||||
SkFILEWStream playbackOut(pbTitle);
|
||||
SkFILEWStream recordOut(recTitle);
|
||||
recordOut.writeText("# ");
|
||||
playbackOut.writeText("# ");
|
||||
for (size_t i = 0; i < kNumBenchmarks; ++i) {
|
||||
SkString out;
|
||||
out.printf("%s ", BenchmarkControl::getBenchmarkName(i).c_str());
|
||||
if (BenchmarkControl::getBenchmarkFunc(i) == &benchmark_recording) {
|
||||
recordOut.writeText(out.c_str());
|
||||
}
|
||||
if (BenchmarkControl::getBenchmarkFunc(i) == &benchmark_playback) {
|
||||
playbackOut.writeText(out.c_str());
|
||||
}
|
||||
}
|
||||
recordOut.writeText("\n");
|
||||
playbackOut.writeText("\n");
|
||||
|
||||
for (int i = 0; i < argc - 1; ++i) {
|
||||
SkString pbLine;
|
||||
SkString recLine;
|
||||
// ==== Write record info
|
||||
recLine.printf("%d ", i);
|
||||
recLine.appendf("%f ", histograms[0][i].fCpuTime); // Append normal_record time
|
||||
recLine.appendf("%f", histograms[1][i].fCpuTime); // Append rtree_record time
|
||||
|
||||
// ==== Write playback info
|
||||
pbLine.printf("%d ", i);
|
||||
pbLine.appendf("%f ", histograms[2][i].fCpuTime); // Start with normal playback time.
|
||||
// Append all playback benchmark times.
|
||||
for (size_t j = kNumBbhPlaybackBenchmarks; j < kNumBenchmarks; ++j) {
|
||||
pbLine.appendf("%f ", histograms[j][i].fCpuTime);
|
||||
}
|
||||
pbLine.remove(pbLine.size() - 1, 1); // Remove trailing space from line.
|
||||
pbLine.appendf("\n");
|
||||
recLine.appendf("\n");
|
||||
playbackOut.writeText(pbLine.c_str());
|
||||
recordOut.writeText(recLine.c_str());
|
||||
}
|
||||
SkDebugf("\nWrote data to gnuplot-readable files: %s %s\n", pbTitle, recTitle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
return tool_main(argc, argv);
|
||||
}
|
||||
|
148
tools/lua/bbh_filter.lua
Normal file
148
tools/lua/bbh_filter.lua
Normal file
@ -0,0 +1,148 @@
|
||||
-- bbh_filter.lua
|
||||
--
|
||||
-- This script outputs info about 'interesting' skp files,
|
||||
-- where the definition of 'interesting' changes but is roughly:
|
||||
-- "Interesting for bounding box hierarchy benchmarks."
|
||||
--
|
||||
-- Currently, the approach is to output, in equal ammounts, the names of the files that
|
||||
-- have most commands, and the names of the files that use the least popular commands.
|
||||
|
||||
function count_entries(table)
|
||||
local count = 0
|
||||
for _,_ in pairs(table) do
|
||||
count = count + 1
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
verbCounts = {}
|
||||
|
||||
function reset_current()
|
||||
-- Data about the skp in transit
|
||||
currentInfo = {
|
||||
fileName = '',
|
||||
verbs = {},
|
||||
numOps = 0
|
||||
}
|
||||
end
|
||||
reset_current()
|
||||
|
||||
numOutputFiles = 10 -- This is per measure.
|
||||
globalInfo = {} -- Saves currentInfo for each file to be used at the end.
|
||||
output = {} -- Stores {fileName, {verb, count}} tables.
|
||||
|
||||
function tostr(t)
|
||||
local str = ""
|
||||
for k, v in next, t do
|
||||
if #str > 0 then
|
||||
str = str .. ", "
|
||||
end
|
||||
if type(k) == "number" then
|
||||
str = str .. "[" .. k .. "] = "
|
||||
else
|
||||
str = str .. tostring(k) .. " = "
|
||||
end
|
||||
if type(v) == "table" then
|
||||
str = str .. "{ " .. tostr(v) .. " }"
|
||||
else
|
||||
str = str .. tostring(v)
|
||||
end
|
||||
end
|
||||
return str
|
||||
end
|
||||
|
||||
function sk_scrape_startcanvas(c, fileName) end
|
||||
|
||||
function sk_scrape_endcanvas(c, fileName)
|
||||
globalInfo[fileName] = currentInfo
|
||||
globalInfo[fileName].fileName = fileName
|
||||
reset_current()
|
||||
end
|
||||
|
||||
function sk_scrape_accumulate(t)
|
||||
-- dump the params in t, specifically showing the verb first, which we
|
||||
-- then nil out so it doesn't appear in tostr()
|
||||
--
|
||||
verbCounts[t.verb] = (verbCounts[t.verb] or 0) + 1
|
||||
currentInfo.verbs[t.verb] = (currentInfo.verbs[t.verb] or 0) + 1
|
||||
currentInfo.numOps = currentInfo.numOps + 1
|
||||
|
||||
t.verb = nil
|
||||
end
|
||||
|
||||
function sk_scrape_summarize()
|
||||
verbWeights = {} -- {verb, weight}, where 0 < weight <= 1
|
||||
|
||||
meta = {}
|
||||
for k,v in pairs(verbCounts) do
|
||||
table.insert(meta, {key=k, value=v})
|
||||
end
|
||||
table.sort(meta, function (a,b) return a.value > b.value; end)
|
||||
maxValue = meta[1].value
|
||||
io.write("-- ==================\n")
|
||||
io.write("------------------------------------------------------------------ \n")
|
||||
io.write("-- Command\t\t\tNumber of calls\t\tPopularity\n")
|
||||
io.write("------------------------------------------------------------------ \n")
|
||||
for k, v in pairs(meta) do
|
||||
verbWeights[v.key] = v.value / maxValue
|
||||
|
||||
-- Poor man's formatting:
|
||||
local padding = "\t\t\t"
|
||||
if (#v.key + 3) < 8 then
|
||||
padding = "\t\t\t\t"
|
||||
end
|
||||
if (#v.key + 3) >= 16 then
|
||||
padding = "\t\t"
|
||||
end
|
||||
|
||||
io.write ("-- ",v.key, padding, v.value, '\t\t\t', verbWeights[v.key], "\n")
|
||||
end
|
||||
|
||||
meta = {}
|
||||
function calculate_weight(verbs)
|
||||
local weight = 0
|
||||
for name, count in pairs(verbs) do
|
||||
weight = weight + (1 / verbWeights[name]) * count
|
||||
end
|
||||
return weight
|
||||
end
|
||||
for n, info in pairs(globalInfo) do
|
||||
table.insert(meta, info)
|
||||
end
|
||||
|
||||
local visitedFiles = {}
|
||||
|
||||
-- Prints out information in lua readable format
|
||||
function output_with_metric(metric_func, description, numOutputFiles)
|
||||
table.sort(meta, metric_func)
|
||||
print(description)
|
||||
local iter = 0
|
||||
for i, t in pairs(meta) do
|
||||
if not visitedFiles[t.fileName] then
|
||||
visitedFiles[t.fileName] = true
|
||||
io.write ("{\nname = \"", t.fileName, "\", \nverbs = {\n")
|
||||
for verb,count in pairs(globalInfo[t.fileName].verbs) do
|
||||
io.write(' ', verb, " = ", count, ",\n")
|
||||
end
|
||||
io.write("}\n},\n")
|
||||
|
||||
iter = iter + 1
|
||||
if iter >= numOutputFiles then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
output_with_metric(
|
||||
function(a, b) return calculate_weight(a.verbs) > calculate_weight(b.verbs); end,
|
||||
"\n-- ================== skps with calling unpopular commands.", 10)
|
||||
output_with_metric(
|
||||
function(a, b) return a.numOps > b.numOps; end,
|
||||
"\n-- ================== skps with the most calls.", 50)
|
||||
|
||||
local count = count_entries(visitedFiles)
|
||||
|
||||
print ("-- Spat", count, "files")
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user