| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2013 Google Inc. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
| 6 | */ |
| 7 | |
| 8 | #include "BenchTimer.h" |
| 9 | #include "LazyDecodeBitmap.h" |
| 10 | #include "PictureBenchmark.h" |
| 11 | #include "PictureRenderer.h" |
| 12 | #include "SkBenchmark.h" |
| 13 | #include "SkForceLinking.h" |
| 14 | #include "SkGraphics.h" |
| 15 | #include "SkStream.h" |
| 16 | #include "SkString.h" |
| commit-bot@chromium.org | 49a07ad | 2013-07-22 19:28:40 +0000 | [diff] [blame] | 17 | #include "SkTArray.h" |
| commit-bot@chromium.org | db34f33 | 2014-03-11 14:23:50 +0000 | [diff] [blame^] | 18 | #include "TimerData.h" |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 19 | |
| commit-bot@chromium.org | db34f33 | 2014-03-11 14:23:50 +0000 | [diff] [blame^] | 20 | static const int kNumNormalRecordings = 10; |
| 21 | static const int kNumRTreeRecordings = 10; |
| 22 | static const int kNumPlaybacks = 1; |
| 23 | static const size_t kNumBaseBenchmarks = 3; |
| 24 | static const size_t kNumTileSizes = 3; |
| 25 | static const size_t kNumBbhPlaybackBenchmarks = 3; |
| 26 | static const size_t kNumBenchmarks = kNumBaseBenchmarks + kNumBbhPlaybackBenchmarks; |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 27 | |
| commit-bot@chromium.org | db34f33 | 2014-03-11 14:23:50 +0000 | [diff] [blame^] | 28 | enum BenchmarkType { |
| 29 | kNormal_BenchmarkType = 0, |
| 30 | kRTree_BenchmarkType, |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 31 | }; |
| 32 | |
| commit-bot@chromium.org | db34f33 | 2014-03-11 14:23:50 +0000 | [diff] [blame^] | 33 | struct Histogram { |
| 34 | Histogram() { |
| 35 | // Make fCpuTime negative so that we don't mess with stats: |
| 36 | fCpuTime = SkIntToScalar(-1); |
| 37 | } |
| 38 | SkScalar fCpuTime; |
| 39 | SkString fPath; |
| 40 | }; |
| 41 | |
| 42 | |
| 43 | //////////////////////////////////////////////////////////////////////////////// |
| 44 | // Defined below. |
| 45 | struct BenchmarkControl; |
| 46 | |
| 47 | typedef void (*BenchmarkFunction) |
| 48 | (const BenchmarkControl&, const SkString&, SkPicture*, BenchTimer*); |
| 49 | |
| 50 | static void benchmark_playback( |
| 51 | const BenchmarkControl&, const SkString&, SkPicture*, BenchTimer*); |
| 52 | static void benchmark_recording( |
| 53 | const BenchmarkControl&, const SkString&, SkPicture*, BenchTimer*); |
| 54 | //////////////////////////////////////////////////////////////////////////////// |
| 55 | |
| 56 | /** |
| 57 | * Acts as a POD containing information needed to run a benchmark. |
| 58 | * Provides static methods to poll benchmark info from an index. |
| 59 | */ |
| 60 | struct BenchmarkControl { |
| 61 | SkISize fTileSize; |
| 62 | BenchmarkType fType; |
| 63 | BenchmarkFunction fFunction; |
| 64 | SkString fName; |
| 65 | |
| 66 | /** |
| 67 | * Will construct a BenchmarkControl instance from an index between 0 an kNumBenchmarks. |
| 68 | */ |
| 69 | static BenchmarkControl Make(size_t i) { |
| 70 | SkASSERT(kNumBenchmarks > i); |
| 71 | BenchmarkControl benchControl; |
| 72 | benchControl.fTileSize = GetTileSize(i); |
| 73 | benchControl.fType = GetBenchmarkType(i); |
| 74 | benchControl.fFunction = GetBenchmarkFunc(i); |
| 75 | benchControl.fName = GetBenchmarkName(i); |
| 76 | return benchControl; |
| 77 | } |
| 78 | |
| 79 | enum BaseBenchmarks { |
| 80 | kNormalRecord = 0, |
| 81 | kRTreeRecord, |
| 82 | kNormalPlayback, |
| 83 | }; |
| 84 | |
| 85 | static SkISize fTileSizes[kNumTileSizes]; |
| 86 | |
| 87 | static SkISize GetTileSize(size_t i) { |
| 88 | // Two of the base benchmarks don't need a tile size. But to maintain simplicity |
| 89 | // down the pipeline we have to let a couple of values unused. |
| 90 | if (i < kNumBaseBenchmarks) { |
| 91 | return SkISize::Make(256, 256); |
| 92 | } |
| 93 | if (i >= kNumBaseBenchmarks && i < kNumBenchmarks) { |
| 94 | return fTileSizes[i - kNumBaseBenchmarks]; |
| 95 | } |
| 96 | SkASSERT(0); |
| 97 | return SkISize::Make(0, 0); |
| 98 | } |
| 99 | |
| 100 | static BenchmarkType GetBenchmarkType(size_t i) { |
| 101 | if (i < kNumBaseBenchmarks) { |
| 102 | switch (i) { |
| 103 | case kNormalRecord: |
| 104 | return kNormal_BenchmarkType; |
| 105 | case kNormalPlayback: |
| 106 | return kNormal_BenchmarkType; |
| 107 | case kRTreeRecord: |
| 108 | return kRTree_BenchmarkType; |
| 109 | } |
| 110 | } |
| 111 | if (i < kNumBenchmarks) { |
| 112 | return kRTree_BenchmarkType; |
| 113 | } |
| 114 | SkASSERT(0); |
| 115 | return kRTree_BenchmarkType; |
| 116 | } |
| 117 | |
| 118 | static BenchmarkFunction GetBenchmarkFunc(size_t i) { |
| 119 | // Base functions. |
| 120 | switch (i) { |
| 121 | case kNormalRecord: |
| 122 | return benchmark_recording; |
| 123 | case kNormalPlayback: |
| 124 | return benchmark_playback; |
| 125 | case kRTreeRecord: |
| 126 | return benchmark_recording; |
| 127 | } |
| 128 | // RTree playbacks |
| 129 | if (i < kNumBenchmarks) { |
| 130 | return benchmark_playback; |
| 131 | } |
| 132 | SkASSERT(0); |
| 133 | return NULL; |
| 134 | } |
| 135 | |
| 136 | static SkString GetBenchmarkName(size_t i) { |
| 137 | // Base benchmark names |
| 138 | switch (i) { |
| 139 | case kNormalRecord: |
| 140 | return SkString("normal_recording"); |
| 141 | case kNormalPlayback: |
| 142 | return SkString("normal_playback"); |
| 143 | case kRTreeRecord: |
| 144 | return SkString("rtree_recording"); |
| 145 | } |
| 146 | // RTree benchmark names. |
| 147 | if (i < kNumBenchmarks) { |
| 148 | SkASSERT(i >= kNumBaseBenchmarks); |
| 149 | SkString name; |
| 150 | name.printf("rtree_playback_%dx%d", |
| 151 | fTileSizes[i - kNumBaseBenchmarks].fWidth, |
| 152 | fTileSizes[i - kNumBaseBenchmarks].fHeight); |
| 153 | return name; |
| 154 | |
| 155 | } else { |
| 156 | SkASSERT(0); |
| 157 | } |
| 158 | return SkString(""); |
| 159 | } |
| 160 | |
| 161 | }; |
| 162 | |
| 163 | SkISize BenchmarkControl::fTileSizes[kNumTileSizes] = { |
| 164 | SkISize::Make(256, 256), |
| 165 | SkISize::Make(512, 512), |
| 166 | SkISize::Make(1024, 1024), |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 167 | }; |
| 168 | |
| 169 | static SkPicture* pic_from_path(const char path[]) { |
| 170 | SkFILEStream stream(path); |
| 171 | if (!stream.isValid()) { |
| 172 | SkDebugf("-- Can't open '%s'\n", path); |
| 173 | return NULL; |
| 174 | } |
| 175 | return SkPicture::CreateFromStream(&stream, &sk_tools::LazyDecodeBitmap); |
| 176 | } |
| 177 | |
| 178 | /** |
| commit-bot@chromium.org | db34f33 | 2014-03-11 14:23:50 +0000 | [diff] [blame^] | 179 | * Returns true when a tiled renderer with no bounding box hierarchy produces the given bitmap. |
| 180 | */ |
| 181 | static bool compare_picture(const SkString& path, const SkBitmap& inBitmap, SkPicture* pic) { |
| 182 | SkBitmap* bitmap; |
| 183 | sk_tools::TiledPictureRenderer renderer; |
| 184 | renderer.setBBoxHierarchyType(sk_tools::PictureRenderer::kNone_BBoxHierarchyType); |
| 185 | renderer.init(pic); |
| 186 | renderer.setup(); |
| 187 | renderer.render(&path, &bitmap); |
| 188 | SkAutoTDelete<SkBitmap> bmDeleter(bitmap); |
| 189 | renderer.end(); |
| 190 | |
| 191 | if (bitmap->getSize() != inBitmap.getSize()) { |
| 192 | return false; |
| 193 | } |
| 194 | return !memcmp(bitmap->getPixels(), inBitmap.getPixels(), bitmap->getSize()); |
| 195 | } |
| 196 | |
| 197 | /** |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 198 | * This function is the sink to which all work ends up going. |
| commit-bot@chromium.org | db34f33 | 2014-03-11 14:23:50 +0000 | [diff] [blame^] | 199 | * Renders the picture into the renderer. It may or may not use an RTree. |
| 200 | * The renderer is chosen upstream. If we want to measure recording, we will |
| 201 | * use a RecordPictureRenderer. If we want to measure rendering, we will use a |
| 202 | * TiledPictureRenderer. |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 203 | */ |
| 204 | static void do_benchmark_work(sk_tools::PictureRenderer* renderer, |
| commit-bot@chromium.org | db34f33 | 2014-03-11 14:23:50 +0000 | [diff] [blame^] | 205 | int benchmarkType, const SkString& path, SkPicture* pic, |
| 206 | const int numRepeats, const char *msg, BenchTimer* timer) { |
| 207 | SkString msgPrefix; |
| 208 | |
| 209 | switch (benchmarkType){ |
| 210 | case kNormal_BenchmarkType: |
| 211 | msgPrefix.set("Normal"); |
| 212 | renderer->setBBoxHierarchyType(sk_tools::PictureRenderer::kNone_BBoxHierarchyType); |
| 213 | break; |
| 214 | case kRTree_BenchmarkType: |
| 215 | msgPrefix.set("RTree"); |
| 216 | renderer->setBBoxHierarchyType(sk_tools::PictureRenderer::kRTree_BBoxHierarchyType); |
| 217 | break; |
| 218 | default: |
| 219 | SkASSERT(0); |
| 220 | break; |
| 221 | } |
| 222 | |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 223 | renderer->init(pic); |
| 224 | |
| commit-bot@chromium.org | db34f33 | 2014-03-11 14:23:50 +0000 | [diff] [blame^] | 225 | /** |
| 226 | * If the renderer is not tiled, assume we are measuring recording. |
| 227 | */ |
| 228 | bool isPlayback = (NULL != renderer->getTiledRenderer()); |
| 229 | // Will be non-null during RTree picture playback. For correctness test. |
| 230 | SkBitmap* bitmap = NULL; |
| 231 | |
| 232 | SkDebugf("%s %s %s %d times...\n", msgPrefix.c_str(), msg, path.c_str(), numRepeats); |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 233 | for (int i = 0; i < numRepeats; ++i) { |
| commit-bot@chromium.org | db34f33 | 2014-03-11 14:23:50 +0000 | [diff] [blame^] | 234 | // Set up the bitmap. |
| 235 | SkBitmap** out = NULL; |
| 236 | if (i == 0 && kRTree_BenchmarkType == benchmarkType && isPlayback) { |
| 237 | out = &bitmap; |
| 238 | } |
| 239 | |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 240 | renderer->setup(); |
| commit-bot@chromium.org | db34f33 | 2014-03-11 14:23:50 +0000 | [diff] [blame^] | 241 | // Render once to fill caches. Fill bitmap during the first iteration. |
| 242 | renderer->render(NULL, out); |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 243 | // Render again to measure |
| 244 | timer->start(); |
| commit-bot@chromium.org | db34f33 | 2014-03-11 14:23:50 +0000 | [diff] [blame^] | 245 | bool result = renderer->render(NULL); |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 246 | timer->end(); |
| commit-bot@chromium.org | db34f33 | 2014-03-11 14:23:50 +0000 | [diff] [blame^] | 247 | |
| 248 | // We only care about a false result on playback. RecordPictureRenderer::render will always |
| 249 | // return false because we are passing a NULL file name on purpose; which is fine. |
| 250 | if (isPlayback && !result) { |
| 251 | SkDebugf("Error rendering during playback.\n"); |
| 252 | } |
| 253 | } |
| 254 | if (bitmap) { |
| 255 | SkAutoTDelete<SkBitmap> bmDeleter(bitmap); |
| 256 | if (!compare_picture(path, *bitmap, pic)) { |
| 257 | SkDebugf("Error: RTree produced different bitmap\n"); |
| 258 | } |
| 259 | } |
| 260 | } |
| 261 | |
| 262 | /** |
| 263 | * Call do_benchmark_work with a tiled renderer using the default tile dimensions. |
| 264 | */ |
| 265 | static void benchmark_playback( |
| 266 | const BenchmarkControl& benchControl, |
| 267 | const SkString& path, SkPicture* pic, BenchTimer* timer) { |
| 268 | sk_tools::TiledPictureRenderer renderer; |
| 269 | |
| 270 | SkString message("tiled_playback"); |
| 271 | message.appendf("_%dx%d", benchControl.fTileSize.fWidth, benchControl.fTileSize.fHeight); |
| 272 | do_benchmark_work(&renderer, benchControl.fType, |
| 273 | path, pic, kNumPlaybacks, message.c_str(), timer); |
| 274 | } |
| 275 | |
| 276 | /** |
| 277 | * Call do_benchmark_work with a RecordPictureRenderer. |
| 278 | */ |
| 279 | static void benchmark_recording( |
| 280 | const BenchmarkControl& benchControl, |
| 281 | const SkString& path, SkPicture* pic, BenchTimer* timer) { |
| 282 | sk_tools::RecordPictureRenderer renderer; |
| 283 | int numRecordings = 0; |
| 284 | switch(benchControl.fType) { |
| 285 | case kRTree_BenchmarkType: |
| 286 | numRecordings = kNumRTreeRecordings; |
| 287 | break; |
| 288 | case kNormal_BenchmarkType: |
| 289 | numRecordings = kNumNormalRecordings; |
| 290 | break; |
| 291 | } |
| 292 | do_benchmark_work(&renderer, benchControl.fType, |
| 293 | path, pic, numRecordings, "recording", timer); |
| 294 | } |
| 295 | |
| 296 | /** |
| 297 | * Takes argc,argv along with one of the benchmark functions defined above. |
| 298 | * Will loop along all skp files and perform measurments. |
| 299 | */ |
| 300 | static void benchmark_loop( |
| 301 | int argc, |
| 302 | char **argv, |
| 303 | const BenchmarkControl& benchControl, |
| 304 | SkTArray<Histogram>& histogram) { |
| 305 | for (int index = 1; index < argc; ++index) { |
| 306 | BenchTimer timer; |
| 307 | SkString path(argv[index]); |
| 308 | SkAutoTUnref<SkPicture> pic(pic_from_path(path.c_str())); |
| 309 | if (NULL == pic) { |
| 310 | SkDebugf("Couldn't create picture. Ignoring path: %s\n", path.c_str()); |
| 311 | continue; |
| 312 | } |
| 313 | benchControl.fFunction(benchControl, path, pic, &timer); |
| 314 | histogram[index - 1].fPath = path; |
| 315 | histogram[index - 1].fCpuTime = SkDoubleToScalar(timer.fCpu); |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 316 | } |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 317 | } |
| 318 | |
| sglez@google.com | 1d38ae9 | 2013-07-19 20:03:57 +0000 | [diff] [blame] | 319 | int tool_main(int argc, char** argv); |
| 320 | int tool_main(int argc, char** argv) { |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 321 | SkAutoGraphics ag; |
| commit-bot@chromium.org | db34f33 | 2014-03-11 14:23:50 +0000 | [diff] [blame^] | 322 | SkString usage; |
| 323 | usage.printf("Usage: filename [filename]*\n"); |
| 324 | |
| 325 | if (argc < 2) { |
| 326 | SkDebugf("%s\n", usage.c_str()); |
| 327 | return -1; |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 328 | } |
| 329 | |
| commit-bot@chromium.org | db34f33 | 2014-03-11 14:23:50 +0000 | [diff] [blame^] | 330 | SkTArray<Histogram> histograms[kNumBenchmarks]; |
| 331 | |
| 332 | for (size_t i = 0; i < kNumBenchmarks; ++i) { |
| 333 | histograms[i].reset(argc - 1); |
| 334 | benchmark_loop(argc, argv, BenchmarkControl::Make(i), histograms[i]); |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 335 | } |
| 336 | |
| 337 | // Output gnuplot readable histogram data.. |
| 338 | const char* pbTitle = "bbh_shootout_playback.dat"; |
| 339 | const char* recTitle = "bbh_shootout_record.dat"; |
| 340 | SkFILEWStream playbackOut(pbTitle); |
| 341 | SkFILEWStream recordOut(recTitle); |
| 342 | recordOut.writeText("# "); |
| 343 | playbackOut.writeText("# "); |
| commit-bot@chromium.org | db34f33 | 2014-03-11 14:23:50 +0000 | [diff] [blame^] | 344 | for (size_t i = 0; i < kNumBenchmarks; ++i) { |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 345 | SkString out; |
| commit-bot@chromium.org | db34f33 | 2014-03-11 14:23:50 +0000 | [diff] [blame^] | 346 | out.printf("%s ", BenchmarkControl::GetBenchmarkName(i).c_str()); |
| 347 | if (BenchmarkControl::GetBenchmarkFunc(i) == &benchmark_recording) { |
| 348 | recordOut.writeText(out.c_str()); |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 349 | } |
| commit-bot@chromium.org | db34f33 | 2014-03-11 14:23:50 +0000 | [diff] [blame^] | 350 | if (BenchmarkControl::GetBenchmarkFunc(i) == &benchmark_playback) { |
| 351 | playbackOut.writeText(out.c_str()); |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 352 | } |
| 353 | } |
| 354 | recordOut.writeText("\n"); |
| 355 | playbackOut.writeText("\n"); |
| commit-bot@chromium.org | 2e915b3 | 2013-08-20 12:23:18 +0000 | [diff] [blame] | 356 | // Write to file, and save recording averages. |
| commit-bot@chromium.org | db34f33 | 2014-03-11 14:23:50 +0000 | [diff] [blame^] | 357 | SkScalar avgRecord = SkIntToScalar(0); |
| 358 | SkScalar avgPlayback = SkIntToScalar(0); |
| 359 | SkScalar avgRecordRTree = SkIntToScalar(0); |
| 360 | SkScalar avgPlaybackRTree = SkIntToScalar(0); |
| 361 | for (int i = 0; i < argc - 1; ++i) { |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 362 | SkString pbLine; |
| 363 | SkString recLine; |
| commit-bot@chromium.org | db34f33 | 2014-03-11 14:23:50 +0000 | [diff] [blame^] | 364 | // ==== Write record info |
| 365 | recLine.printf("%d ", i); |
| 366 | SkScalar cpuTime = histograms[BenchmarkControl::kNormalRecord][i].fCpuTime; |
| 367 | recLine.appendf("%f ", cpuTime); |
| 368 | avgRecord += cpuTime; |
| 369 | cpuTime = histograms[BenchmarkControl::kRTreeRecord][i].fCpuTime; |
| 370 | recLine.appendf("%f", cpuTime); |
| 371 | avgRecordRTree += cpuTime; |
| 372 | avgPlaybackRTree += cpuTime; |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 373 | |
| commit-bot@chromium.org | db34f33 | 2014-03-11 14:23:50 +0000 | [diff] [blame^] | 374 | // ==== Write playback info |
| 375 | pbLine.printf("%d ", i); |
| 376 | pbLine.appendf("%f ", histograms[2][i].fCpuTime); // Start with normal playback time. |
| 377 | avgPlayback += histograms[kNumBbhPlaybackBenchmarks - 1][i].fCpuTime; |
| 378 | avgPlaybackRTree += histograms[kNumBbhPlaybackBenchmarks][i].fCpuTime; |
| 379 | // Append all playback benchmark times. |
| 380 | for (size_t j = kNumBbhPlaybackBenchmarks; j < kNumBenchmarks; ++j) { |
| 381 | pbLine.appendf("%f ", histograms[j][i].fCpuTime); |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 382 | } |
| commit-bot@chromium.org | db34f33 | 2014-03-11 14:23:50 +0000 | [diff] [blame^] | 383 | pbLine.remove(pbLine.size() - 1, 1); // Remove trailing space from line. |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 384 | pbLine.appendf("\n"); |
| 385 | recLine.appendf("\n"); |
| 386 | playbackOut.writeText(pbLine.c_str()); |
| 387 | recordOut.writeText(recLine.c_str()); |
| 388 | } |
| commit-bot@chromium.org | db34f33 | 2014-03-11 14:23:50 +0000 | [diff] [blame^] | 389 | avgRecord /= argc - 1; |
| 390 | avgRecordRTree /= argc - 1; |
| 391 | avgPlayback /= argc - 1; |
| 392 | avgPlaybackRTree /= argc - 1; |
| 393 | SkDebugf("Average base recording time: %.3fms\n", avgRecord); |
| 394 | SkDebugf("Average recording time with rtree: %.3fms\n", avgRecordRTree); |
| 395 | SkDebugf("Average base playback time: %.3fms\n", avgPlayback); |
| 396 | SkDebugf("Average playback time with rtree: %.3fms\n", avgPlaybackRTree); |
| 397 | |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 398 | SkDebugf("\nWrote data to gnuplot-readable files: %s %s\n", pbTitle, recTitle); |
| commit-bot@chromium.org | db34f33 | 2014-03-11 14:23:50 +0000 | [diff] [blame^] | 399 | |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 400 | return 0; |
| 401 | } |
| 402 | |
| sglez@google.com | 5f3f681 | 2013-07-19 20:21:05 +0000 | [diff] [blame] | 403 | #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) |
| commit-bot@chromium.org | 6645cde | 2013-07-19 18:54:04 +0000 | [diff] [blame] | 404 | int main(int argc, char** argv) { |
| 405 | return tool_main(argc, argv); |
| 406 | } |
| sglez@google.com | 5f3f681 | 2013-07-19 20:21:05 +0000 | [diff] [blame] | 407 | #endif |