Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 | 1 |
| 2 /* | 2 /* |
| 3 * Copyright 2011 Google Inc. | 3 * Copyright 2011 Google Inc. |
| 4 * | 4 * |
| 5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
| 6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 | |
| 10 #include "BenchTimer.h" | |
| 11 | |
| 12 #if SK_SUPPORT_GPU | 9 #if SK_SUPPORT_GPU |
| 13 #include "GrContext.h" | 10 #include "GrContext.h" |
| 14 #include "GrContextFactory.h" | 11 #include "GrContextFactory.h" |
| 15 #include "gl/GrGLDefines.h" | |
| 16 #include "GrRenderTarget.h" | 12 #include "GrRenderTarget.h" |
| 17 #include "SkGpuDevice.h" | 13 #include "SkGpuDevice.h" |
| 14 #include "gl/GrGLDefines.h" | |
| 18 #else | 15 #else |
| 19 class GrContext; | 16 class GrContext; |
| 20 #endif // SK_SUPPORT_GPU | 17 #endif // SK_SUPPORT_GPU |
| 21 | 18 |
| 19 #include "BenchTimer.h" | |
| 22 #include "SkBenchLogger.h" | 20 #include "SkBenchLogger.h" |
| 23 #include "SkBenchmark.h" | 21 #include "SkBenchmark.h" |
| 24 #include "SkBitmapDevice.h" | 22 #include "SkBitmapDevice.h" |
| 25 #include "SkCanvas.h" | 23 #include "SkCanvas.h" |
| 26 #include "SkCommandLineFlags.h" | 24 #include "SkCommandLineFlags.h" |
| 27 #include "SkDeferredCanvas.h" | 25 #include "SkDeferredCanvas.h" |
| 28 #include "SkColorPriv.h" | |
| 29 #include "SkGraphics.h" | 26 #include "SkGraphics.h" |
| 30 #include "SkImageEncoder.h" | 27 #include "SkImageEncoder.h" |
| 31 #include "SkNWayCanvas.h" | |
| 32 #include "SkPicture.h" | 28 #include "SkPicture.h" |
| 33 #include "SkString.h" | 29 #include "SkString.h" |
| 34 #include "SkTArray.h" | |
| 35 #include "TimerData.h" | |
| 36 | 30 |
| 37 enum benchModes { | 31 enum BenchMode { |
|
scroggo
2013/09/03 19:36:43
Officially I think we're supposed to make the enum
mtklein
2013/09/03 20:04:43
Updated the style guide so that BenchMode and Back
| |
| 38 kNormal_benchModes, | 32 kNormal_BenchMode, |
| 39 kDeferred_benchModes, | 33 kDeferred_BenchMode, |
| 40 kDeferredSilent_benchModes, | 34 kDeferredSilent_BenchMode, |
| 41 kRecord_benchModes, | 35 kRecord_BenchMode, |
| 42 kPictureRecord_benchModes | 36 kPictureRecord_BenchMode |
| 43 }; | 37 }; |
| 38 const char* BenchMode_Name[] = { "normal", "deferred", "deferredSilent", "record ", "picturerecord" }; | |
| 44 | 39 |
| 45 #ifdef SK_DEBUG | 40 enum TimerType { |
|
scroggo
2013/09/03 19:36:43
Would be nice to consolidate this with bench_pictu
mtklein
2013/09/03 20:04:43
I was thinking maybe I'd go whole-hog and follow u
scroggo
2013/09/03 20:13:53
+1
| |
| 46 static const bool kDebugOnly = true; | 41 kWall_TimerType, |
| 47 #else | 42 kTruncWall_TimerType, |
| 48 static const bool kDebugOnly = false; | 43 kCpu_TimerType, |
| 49 #endif | 44 kTruncCpu_TimerType, |
| 45 kGpu_TimerType, | |
| 46 }; | |
| 47 const char TimerType_Short[] = { 'w', 'W', 'c', 'C', 'g' }; | |
| 48 const char* TimerType_Name[] = { "msecs", "Wmsecs", "cmsecs", "Cmsecs", "gmsecs" }; | |
| 50 | 49 |
| 51 /////////////////////////////////////////////////////////////////////////////// | 50 /////////////////////////////////////////////////////////////////////////////// |
| 52 | 51 |
| 53 static void erase(SkBitmap& bm) { | 52 static void erase(SkBitmap& bm) { |
| 54 if (bm.config() == SkBitmap::kA8_Config) { | 53 if (bm.config() == SkBitmap::kA8_Config) { |
| 55 bm.eraseColor(SK_ColorTRANSPARENT); | 54 bm.eraseColor(SK_ColorTRANSPARENT); |
| 56 } else { | 55 } else { |
| 57 bm.eraseColor(SK_ColorWHITE); | 56 bm.eraseColor(SK_ColorWHITE); |
| 58 } | 57 } |
| 59 } | 58 } |
| 60 | 59 |
| 61 #if 0 | |
| 62 static bool equal(const SkBitmap& bm1, const SkBitmap& bm2) { | |
| 63 if (bm1.width() != bm2.width() || | |
| 64 bm1.height() != bm2.height() || | |
| 65 bm1.config() != bm2.config()) { | |
| 66 return false; | |
| 67 } | |
| 68 | |
| 69 size_t pixelBytes = bm1.width() * bm1.bytesPerPixel(); | |
| 70 for (int y = 0; y < bm1.height(); y++) { | |
| 71 if (memcmp(bm1.getAddr(0, y), bm2.getAddr(0, y), pixelBytes)) { | |
| 72 return false; | |
| 73 } | |
| 74 } | |
| 75 return true; | |
| 76 } | |
| 77 #endif | |
| 78 | |
| 79 class Iter { | 60 class Iter { |
| 80 public: | 61 public: |
| 81 Iter(void* param) { | 62 Iter() : fBench(BenchRegistry::Head()) {} |
| 82 fBench = BenchRegistry::Head(); | |
| 83 fParam = param; | |
| 84 } | |
| 85 | 63 |
| 86 SkBenchmark* next() { | 64 SkBenchmark* next() { |
| 87 if (fBench) { | 65 if (fBench) { |
| 88 BenchRegistry::Factory f = fBench->factory(); | 66 BenchRegistry::Factory f = fBench->factory(); |
| 89 fBench = fBench->next(); | 67 fBench = fBench->next(); |
| 90 return f(fParam); | 68 return f(NULL); |
| 91 } | 69 } |
| 92 return NULL; | 70 return NULL; |
| 93 } | 71 } |
| 94 | 72 |
| 95 private: | 73 private: |
| 96 const BenchRegistry* fBench; | 74 const BenchRegistry* fBench; |
| 97 void* fParam; | |
| 98 }; | 75 }; |
| 99 | 76 |
| 100 class AutoPrePostDraw { | 77 class AutoPrePostDraw { |
| 101 public: | 78 public: |
| 102 AutoPrePostDraw(SkBenchmark* bench) : fBench(bench) { | 79 AutoPrePostDraw(SkBenchmark* bench) : fBench(bench) { |
| 103 fBench->preDraw(); | 80 fBench->preDraw(); |
| 104 } | 81 } |
| 105 ~AutoPrePostDraw() { | 82 ~AutoPrePostDraw() { |
| 106 fBench->postDraw(); | 83 fBench->postDraw(); |
| 107 } | 84 } |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 140 int c = (*p >> SK_A32_SHIFT) & 0xFF; | 117 int c = (*p >> SK_A32_SHIFT) & 0xFF; |
| 141 c = 255 - c; | 118 c = 255 - c; |
| 142 c |= (c << 24) | (c << 16) | (c << 8); | 119 c |= (c << 24) | (c << 16) | (c << 8); |
| 143 *p++ = c | (SK_A32_MASK << SK_A32_SHIFT); | 120 *p++ = c | (SK_A32_MASK << SK_A32_SHIFT); |
| 144 } | 121 } |
| 145 } | 122 } |
| 146 | 123 |
| 147 SkString str; | 124 SkString str; |
| 148 make_filename(name, &str); | 125 make_filename(name, &str); |
| 149 str.appendf("_%s.png", config); | 126 str.appendf("_%s.png", config); |
| 127 str.prepend("/"); | |
|
scroggo
2013/09/03 19:36:43
SkOSFile now has a function for modifying path nam
mtklein
2013/09/03 20:04:43
Done.
| |
| 150 str.prepend(dir); | 128 str.prepend(dir); |
| 151 ::remove(str.c_str()); | 129 ::remove(str.c_str()); |
| 152 SkImageEncoder::EncodeFile(str.c_str(), copy, SkImageEncoder::kPNG_Type, | 130 SkImageEncoder::EncodeFile(str.c_str(), copy, SkImageEncoder::kPNG_Type, |
| 153 100); | 131 100); |
| 154 } | 132 } |
| 155 | 133 |
| 156 static void performClip(SkCanvas* canvas, int w, int h) { | 134 static void performClip(SkCanvas* canvas, int w, int h) { |
| 157 SkRect r; | 135 SkRect r; |
| 158 | 136 |
| 159 r.set(SkIntToScalar(10), SkIntToScalar(10), | 137 r.set(SkIntToScalar(10), SkIntToScalar(10), |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 177 static void performScale(SkCanvas* canvas, int w, int h) { | 155 static void performScale(SkCanvas* canvas, int w, int h) { |
| 178 const SkScalar x = SkIntToScalar(w) / 2; | 156 const SkScalar x = SkIntToScalar(w) / 2; |
| 179 const SkScalar y = SkIntToScalar(h) / 2; | 157 const SkScalar y = SkIntToScalar(h) / 2; |
| 180 | 158 |
| 181 canvas->translate(x, y); | 159 canvas->translate(x, y); |
| 182 // just enough so we can't take the sprite case | 160 // just enough so we can't take the sprite case |
| 183 canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100); | 161 canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100); |
| 184 canvas->translate(-x, -y); | 162 canvas->translate(-x, -y); |
| 185 } | 163 } |
| 186 | 164 |
| 187 static bool parse_bool_arg(char * const* argv, char* const* stop, bool* var) { | |
| 188 if (argv < stop) { | |
| 189 *var = atoi(*argv) != 0; | |
| 190 return true; | |
| 191 } | |
| 192 return false; | |
| 193 } | |
| 194 | |
| 195 enum Backend { | 165 enum Backend { |
| 196 kNonRendering_Backend, | 166 kNonRendering_Backend, |
| 197 kRaster_Backend, | 167 kRaster_Backend, |
| 198 kGPU_Backend, | 168 kGPU_Backend, |
| 199 kPDF_Backend, | 169 kPDF_Backend, |
| 200 }; | 170 }; |
| 201 | 171 |
| 202 static SkBaseDevice* make_device(SkBitmap::Config config, const SkIPoint& size, | 172 static SkBaseDevice* make_device(SkBitmap::Config config, const SkIPoint& size, |
| 203 Backend backend, int sampleCount, GrContext* co ntext) { | 173 Backend backend, int sampleCount, GrContext* co ntext) { |
| 204 SkBaseDevice* device = NULL; | 174 SkBaseDevice* device = NULL; |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 230 case kPDF_Backend: | 200 case kPDF_Backend: |
| 231 default: | 201 default: |
| 232 SkDEBUGFAIL("unsupported"); | 202 SkDEBUGFAIL("unsupported"); |
| 233 } | 203 } |
| 234 return device; | 204 return device; |
| 235 } | 205 } |
| 236 | 206 |
| 237 #if SK_SUPPORT_GPU | 207 #if SK_SUPPORT_GPU |
| 238 GrContextFactory gContextFactory; | 208 GrContextFactory gContextFactory; |
| 239 typedef GrContextFactory::GLContextType GLContextType; | 209 typedef GrContextFactory::GLContextType GLContextType; |
| 240 static const GLContextType kDontCareGLCtxType = GrContextFactory::kNative_GLCont extType; | 210 static const GLContextType kNative = GrContextFactory::kNative_GLContextType; |
| 211 #if SK_ANGLE | |
| 212 static const GLContextType kANGLE = GrContextFactory::kANGLE_GLContextType; | |
| 213 #else | |
| 214 static const GLContextType kANGLE = kNative; | |
| 215 #endif | |
| 216 static const GLContextType kDebug = GrContextFactory::kDebug_GLContextType; | |
| 217 static const GLContextType kNull = GrContextFactory::kNull_GLContextType; | |
| 241 #else | 218 #else |
| 242 typedef int GLContextType; | 219 typedef int GLContextType; |
| 243 static const GLContextType kDontCareGLCtxType = 0; | 220 static const GLContextType kNative = 0, kANGLE = 0, kDebug = 0, kNull = 0; |
| 244 #endif | 221 #endif |
| 245 | 222 |
| 246 static const struct { | 223 #ifdef SK_DEBUG |
| 247 SkBitmap::Config fConfig; | 224 static const bool kIsDebug = true; |
| 248 const char* fName; | 225 #else |
| 249 int fSampleCnt; | 226 static const bool kIsDebug = false; |
| 250 Backend fBackend; | 227 #endif |
| 251 GLContextType fContextType; | 228 |
| 252 bool fRunByDefault; | 229 static const struct Config { |
| 230 SkBitmap::Config config; | |
| 231 const char* name; | |
| 232 int sampleCount; | |
| 233 Backend backend; | |
| 234 GLContextType contextType; | |
| 235 bool runByDefault; | |
| 253 } gConfigs[] = { | 236 } gConfigs[] = { |
| 254 { SkBitmap::kNo_Config, "NONRENDERING", 0, kNonRendering_Backend, kD ontCareGLCtxType, true }, | 237 { SkBitmap::kNo_Config, "NONRENDERING", 0, kNonRendering_Backend, kNa tive, true}, |
| 255 { SkBitmap::kARGB_8888_Config, "8888", 0, kRaster_Backend, kD ontCareGLCtxType, true }, | 238 { SkBitmap::kARGB_8888_Config, "8888", 0, kRaster_Backend, kNa tive, true}, |
| 256 { SkBitmap::kRGB_565_Config, "565", 0, kRaster_Backend, kD ontCareGLCtxType, true }, | 239 { SkBitmap::kRGB_565_Config, "565", 0, kRaster_Backend, kNa tive, true}, |
| 257 #if SK_SUPPORT_GPU | 240 #if SK_SUPPORT_GPU |
| 258 { SkBitmap::kARGB_8888_Config, "GPU", 0, kGPU_Backend, Gr ContextFactory::kNative_GLContextType, true }, | 241 { SkBitmap::kARGB_8888_Config, "GPU", 0, kGPU_Backend, kNa tive, true}, |
| 259 { SkBitmap::kARGB_8888_Config, "MSAA4", 4, kGPU_Backend, Gr ContextFactory::kNative_GLContextType, false }, | 242 { SkBitmap::kARGB_8888_Config, "MSAA4", 4, kGPU_Backend, kNa tive, false}, |
| 260 { SkBitmap::kARGB_8888_Config, "MSAA16", 16, kGPU_Backend, Gr ContextFactory::kNative_GLContextType, false }, | 243 { SkBitmap::kARGB_8888_Config, "MSAA16", 16, kGPU_Backend, kNa tive, false}, |
| 261 #if SK_ANGLE | 244 #if SK_ANGLE |
| 262 { SkBitmap::kARGB_8888_Config, "ANGLE", 0, kGPU_Backend, Gr ContextFactory::kANGLE_GLContextType, true }, | 245 { SkBitmap::kARGB_8888_Config, "ANGLE", 0, kGPU_Backend, kAN GLE, true}, |
| 263 #endif // SK_ANGLE | 246 #endif // SK_ANGLE |
| 264 { SkBitmap::kARGB_8888_Config, "Debug", 0, kGPU_Backend, Gr ContextFactory::kDebug_GLContextType, kDebugOnly }, | 247 { SkBitmap::kARGB_8888_Config, "Debug", 0, kGPU_Backend, kDe bug, kIsDebug}, |
| 265 { SkBitmap::kARGB_8888_Config, "NULLGPU", 0, kGPU_Backend, Gr ContextFactory::kNull_GLContextType, true }, | 248 { SkBitmap::kARGB_8888_Config, "NULLGPU", 0, kGPU_Backend, kNu ll, true}, |
| 266 #endif // SK_SUPPORT_GPU | 249 #endif // SK_SUPPORT_GPU |
| 267 }; | 250 }; |
| 268 | 251 |
| 269 static int findConfig(const char config[]) { | 252 DEFINE_string(outDir, "", "If given, image of each bench will be put in outDir." ); |
| 270 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); i++) { | 253 DEFINE_string(timers, "cg", "Timers to display. " |
|
scroggo
2013/09/03 19:36:43
It would be nice to combine this with bench_pictur
mtklein
2013/09/03 20:04:43
+1
| |
| 271 if (!strcmp(config, gConfigs[i].fName)) { | 254 "Options: w(all) W(all, truncated) c(pu) C(pu, truncated) g(pu)"); |
| 272 return i; | |
| 273 } | |
| 274 } | |
| 275 return -1; | |
| 276 } | |
| 277 | 255 |
| 278 static void help() { | 256 DEFINE_bool(rotate, false, "Rotate canvas before bench run?"); |
| 279 SkString configsStr; | 257 DEFINE_bool(scale, false, "Scale canvas before bench run?"); |
| 280 static const size_t kConfigCount = SK_ARRAY_COUNT(gConfigs); | 258 DEFINE_bool(clip, false, "Clip canvas before bench run?"); |
| 281 for (size_t i = 0; i < kConfigCount; ++i) { | |
| 282 configsStr.appendf("%s%s", gConfigs[i].fName, ((i == kConfigCount - 1) ? "" : "|")); | |
| 283 } | |
| 284 | 259 |
| 285 SkDebugf("Usage: bench [-o outDir] [--repeat nr] [--logPerIter] " | 260 DEFINE_bool(forceAA, true, "Force anti-aliasing?"); |
| 286 "[--timers [wcgWC]*] [--rotate]\n" | 261 DEFINE_bool(forceFilter, false, "Force bitmap filtering?"); |
| 287 " [--scale] [--clip] [--min] [--forceAA 1|0] [--forceFilter 1|0] \n" | 262 DEFINE_string(forceDither, "default", "Force dithering: true, false, or default? "); |
| 288 " [--forceDither 1|0] [--forceBlend 1|0]" | 263 DEFINE_bool(forceBlend, false, "Force alpha blending?"); |
| 289 #if SK_SUPPORT_GPU | 264 |
| 290 " [--gpuCacheSize <bytes> <count>]" | 265 DEFINE_int32(gpuCacheBytes, -1, "GPU cache size limit in bytes. 0 to disable ca che."); |
| 291 #endif | 266 DEFINE_int32(gpuCacheCount, -1, "GPU cache size limit in object count. 0 to dis able cache."); |
| 292 "\n" | 267 |
| 293 " [--strokeWidth width] [--match name]\n" | 268 DEFINE_string(match, "", "[~][^]substring[$] [...] of test name to run.\n" |
|
scroggo
2013/09/03 19:36:43
Isn't this now built in to SkCommandLineFlags?
mtklein
2013/09/03 20:04:43
Sort of. We can now parse FLAGS_match directly ra
scroggo
2013/09/03 20:13:53
What if SkCommandLineFlags defined it optionally?
| |
| 294 " [--mode normal|deferred|deferredSilent|record|picturerecord]\n " | 269 "Multiple matches may be separated by spaces.\n" |
| 295 " [--config "); | 270 "~ causes a matching test to always be skipped\n" |
| 296 SkDebugf("%s]\n", configsStr.c_str()); | 271 "^ requires the start of the test to match\n" |
| 297 SkDebugf(" [-Dfoo bar] [--logFile filename] [-h|--help]"); | 272 "$ requires the end of the test to match\n" |
| 298 SkDebugf("\n\n"); | 273 "^ and $ requires an exact match\n" |
| 299 SkDebugf(" -o outDir : Image of each bench will be put in outDir.\n"); | 274 "If a test does not match any list entry,\n" |
| 300 SkDebugf(" --repeat nr : Each bench repeats for nr times.\n"); | 275 "it is skipped unless some list entry starts with ~\n" ); |
| 301 SkDebugf(" --logPerIter : " | 276 DEFINE_string(mode, "normal", |
| 302 "Log each repeat timer instead of mean, default is disabled.\n"); | 277 "normal: draw to a normal canvas;\n" |
| 303 SkDebugf(" --timers [wcgWC]* : " | 278 "deferred: draw to a deferred canvas;\n" |
| 304 "Display wall, cpu, gpu, truncated wall or truncated cpu time for e ach bench.\n"); | 279 "deferredSilent: deferred with silent playback;\n" |
| 305 SkDebugf(" --rotate : Rotate before each bench runs.\n"); | 280 "record: draw to an SkPicture;\n" |
| 306 SkDebugf(" --scale : Scale before each bench runs.\n"); | 281 "picturerecord: draw from an SkPicture to an SkPicture.\n"); |
| 307 SkDebugf(" --clip : Clip before each bench runs.\n"); | 282 DEFINE_string(config, "", "Run configs given. If empty, runs the defaults set i n gConfigs."); |
| 308 SkDebugf(" --min : Print the minimum times (instead of average).\n"); | 283 DEFINE_string(logFile, "", "Also write stdout here."); |
| 309 SkDebugf(" --forceAA 1|0 : " | 284 DEFINE_int32(benchMs, 20, "Target time in ms to run each benchmark config."); |
| 310 "Enable/disable anti-aliased, default is enabled.\n"); | 285 DEFINE_string(timeFormat, "%9.2f", "Format to print results, in milliseconds per 1000 loops."); |
| 311 SkDebugf(" --forceFilter 1|0 : " | |
| 312 "Enable/disable bitmap filtering, default is disabled.\n"); | |
| 313 SkDebugf(" --forceDither 1|0 : " | |
| 314 "Enable/disable dithering, default is disabled.\n"); | |
| 315 SkDebugf(" --forceBlend 1|0 : " | |
| 316 "Enable/disable dithering, default is disabled.\n"); | |
| 317 #if SK_SUPPORT_GPU | |
| 318 SkDebugf(" --gpuCacheSize <bytes> <count>: " | |
| 319 "limits gpu cache to bytes size or object count.\n"); | |
| 320 SkDebugf(" -1 for either value means use the default. 0 for either disa bles the cache.\n"); | |
| 321 #endif | |
| 322 SkDebugf(" --strokeWidth width : The width for path stroke.\n"); | |
| 323 SkDebugf(" --match [~][^]substring[$] [...] of test name to run.\n" | |
| 324 " Multiple matches may be separated by spaces.\n" | |
| 325 " ~ causes a matching test to always be skipped\n" | |
| 326 " ^ requires the start of the test to match\n" | |
| 327 " $ requires the end of the test to match\n" | |
| 328 " ^ and $ requires an exact match\n" | |
| 329 " If a test does not match any list entry,\n" | |
| 330 " it is skipped unless some list entry starts with ~\n" ); | |
| 331 SkDebugf(" --mode normal|deferred|deferredSilent|record|picturerecord :\n " | |
| 332 " Run in the corresponding mode\n" | |
| 333 " normal, Use a normal canvas to draw to;\n" | |
| 334 " deferred, Use a deferrred canvas when drawing;\n" | |
| 335 " deferredSilent, deferred with silent playback;\n" | |
| 336 " record, Benchmark the time to record to an SkPict ure;\n" | |
| 337 " picturerecord, Benchmark the time to do record fr om a \n" | |
| 338 " SkPicture to a SkPicture.\n"); | |
| 339 SkDebugf(" --logFile filename : destination for writing log output, in ad dition to stdout.\n"); | |
| 340 SkDebugf(" --config %s:\n", configsStr.c_str()); | |
| 341 SkDebugf(" Run bench in corresponding config mode.\n"); | |
| 342 SkDebugf(" -Dfoo bar : Add extra definition to bench.\n"); | |
| 343 SkDebugf(" -h|--help : Show this help message.\n"); | |
| 344 } | |
| 345 | 286 |
| 346 int tool_main(int argc, char** argv); | 287 int tool_main(int argc, char** argv); |
| 347 int tool_main(int argc, char** argv) { | 288 int tool_main(int argc, char** argv) { |
| 348 #if SK_ENABLE_INST_COUNT | 289 #if SK_ENABLE_INST_COUNT |
| 349 gPrintInstCount = true; | 290 gPrintInstCount = true; |
| 350 #endif | 291 #endif |
| 351 SkAutoGraphics ag; | 292 SkAutoGraphics ag; |
| 293 SkCommandLineFlags::Parse(argc, argv); | |
| 352 | 294 |
| 353 SkTDict<const char*> defineDict(1024); | 295 // First, parse some flags. |
|
scroggo
2013/09/03 19:36:43
It seems this functionality (supplying defines on
mtklein
2013/09/03 20:04:43
Yes. Only DecodeBench.cpp was using it for one po
| |
| 354 int repeatDraw = 1; | |
| 355 | |
| 356 int forceAlpha = 0xFF; | |
| 357 bool forceAA = true; | |
| 358 bool forceFilter = false; | |
| 359 SkTriState::State forceDither = SkTriState::kDefault; | |
| 360 | |
| 361 static const uint32_t kDefaultTimerTypes = TimerData::kCpu_Flag | TimerData: :kGpu_Flag; | |
| 362 static const TimerData::Result kDefaultTimerResult = TimerData::kAvg_Result; | |
| 363 uint32_t timerTypes = kDefaultTimerTypes; | |
| 364 TimerData::Result timerResult = kDefaultTimerResult; | |
| 365 | |
| 366 bool doScale = false; | |
| 367 bool doRotate = false; | |
| 368 bool doClip = false; | |
| 369 bool hasStrokeWidth = false; | |
| 370 | |
| 371 #if SK_SUPPORT_GPU | |
| 372 struct { | |
| 373 int fBytes; | |
| 374 int fCount; | |
| 375 } gpuCacheSize = { -1, -1 }; // -1s mean use the default | |
| 376 #endif | |
| 377 | |
| 378 float strokeWidth; | |
| 379 SkTDArray<const char*> fMatches; | |
| 380 benchModes benchMode = kNormal_benchModes; | |
| 381 SkString perIterTimeformat("%.2f"); | |
| 382 SkString normalTimeFormat("%6.2f"); | |
| 383 | |
| 384 SkString outDir; | |
| 385 SkBitmap::Config outConfig = SkBitmap::kNo_Config; | |
| 386 const char* configName = ""; | |
| 387 Backend backend = kRaster_Backend; // for warning | |
| 388 int sampleCount = 0; | |
| 389 SkTDArray<int> configs; | |
| 390 bool userConfig = false; | |
| 391 | 296 |
| 392 SkBenchLogger logger; | 297 SkBenchLogger logger; |
| 298 if (FLAGS_logFile.count()) { | |
| 299 logger.SetLogFile(FLAGS_logFile[0]); | |
| 300 } | |
| 393 | 301 |
| 394 char* const* stop = argv + argc; | 302 const uint8_t alpha = FLAGS_forceBlend ? 0x80 : 0xFF; |
| 395 for (++argv; argv < stop; ++argv) { | 303 SkTriState::State dither = SkTriState::kDefault; |
| 396 if (strcmp(*argv, "-o") == 0) { | 304 for (size_t i = 0; i < 3; i++) { |
| 397 argv++; | 305 if (strcmp(SkTriState::Name[i], FLAGS_forceDither[0]) == 0) { |
| 398 if (argv < stop && **argv) { | 306 dither = static_cast<SkTriState::State>(i); |
| 399 outDir.set(*argv); | |
| 400 if (outDir.c_str()[outDir.size() - 1] != '/') { | |
| 401 outDir.append("/"); | |
| 402 } | |
| 403 } | |
| 404 } else if (strcmp(*argv, "--repeat") == 0) { | |
| 405 argv++; | |
| 406 if (argv < stop) { | |
| 407 repeatDraw = atoi(*argv); | |
| 408 if (repeatDraw < 1) { | |
| 409 repeatDraw = 1; | |
| 410 } | |
| 411 } else { | |
| 412 logger.logError("missing arg for --repeat\n"); | |
| 413 help(); | |
| 414 return -1; | |
| 415 } | |
| 416 } else if (strcmp(*argv, "--logPerIter") == 0) { | |
| 417 timerResult = TimerData::kPerIter_Result; | |
| 418 } else if (strcmp(*argv, "--timers") == 0) { | |
| 419 argv++; | |
| 420 if (argv < stop) { | |
| 421 timerTypes = 0; | |
| 422 for (char* t = *argv; *t; ++t) { | |
| 423 switch (*t) { | |
| 424 case 'w': timerTypes |= TimerData::kWall_Flag; break; | |
| 425 case 'c': timerTypes |= TimerData::kCpu_Flag; break; | |
| 426 case 'W': timerTypes |= TimerData::kTruncatedWall_Flag; brea k; | |
| 427 case 'C': timerTypes |= TimerData::kTruncatedCpu_Flag; break ; | |
| 428 case 'g': timerTypes |= TimerData::kGpu_Flag; break; | |
| 429 } | |
| 430 } | |
| 431 } else { | |
| 432 logger.logError("missing arg for --timers\n"); | |
| 433 help(); | |
| 434 return -1; | |
| 435 } | |
| 436 } else if (!strcmp(*argv, "--rotate")) { | |
| 437 doRotate = true; | |
| 438 } else if (!strcmp(*argv, "--scale")) { | |
| 439 doScale = true; | |
| 440 } else if (!strcmp(*argv, "--clip")) { | |
| 441 doClip = true; | |
| 442 } else if (!strcmp(*argv, "--min")) { | |
| 443 timerResult = TimerData::kMin_Result; | |
| 444 } else if (strcmp(*argv, "--forceAA") == 0) { | |
| 445 if (!parse_bool_arg(++argv, stop, &forceAA)) { | |
| 446 logger.logError("missing arg for --forceAA\n"); | |
| 447 help(); | |
| 448 return -1; | |
| 449 } | |
| 450 } else if (strcmp(*argv, "--forceFilter") == 0) { | |
| 451 if (!parse_bool_arg(++argv, stop, &forceFilter)) { | |
| 452 logger.logError("missing arg for --forceFilter\n"); | |
| 453 help(); | |
| 454 return -1; | |
| 455 } | |
| 456 } else if (strcmp(*argv, "--forceDither") == 0) { | |
| 457 bool tmp; | |
| 458 if (!parse_bool_arg(++argv, stop, &tmp)) { | |
| 459 logger.logError("missing arg for --forceDither\n"); | |
| 460 help(); | |
| 461 return -1; | |
| 462 } | |
| 463 forceDither = tmp ? SkTriState::kTrue : SkTriState::kFalse; | |
| 464 } else if (strcmp(*argv, "--forceBlend") == 0) { | |
| 465 bool wantAlpha = false; | |
| 466 if (!parse_bool_arg(++argv, stop, &wantAlpha)) { | |
| 467 logger.logError("missing arg for --forceBlend\n"); | |
| 468 help(); | |
| 469 return -1; | |
| 470 } | |
| 471 forceAlpha = wantAlpha ? 0x80 : 0xFF; | |
| 472 #if SK_SUPPORT_GPU | |
| 473 } else if (strcmp(*argv, "--gpuCacheSize") == 0) { | |
| 474 if (stop - argv > 2) { | |
| 475 gpuCacheSize.fBytes = atoi(*++argv); | |
| 476 gpuCacheSize.fCount = atoi(*++argv); | |
| 477 } else { | |
| 478 SkDebugf("missing arg for --gpuCacheSize\n"); | |
| 479 help(); | |
| 480 return -1; | |
| 481 } | |
| 482 #endif | |
| 483 } else if (strcmp(*argv, "--mode") == 0) { | |
| 484 argv++; | |
| 485 if (argv < stop) { | |
| 486 if (strcmp(*argv, "normal") == 0) { | |
| 487 benchMode = kNormal_benchModes; | |
| 488 } else if (strcmp(*argv, "deferred") == 0) { | |
| 489 benchMode = kDeferred_benchModes; | |
| 490 } else if (strcmp(*argv, "deferredSilent") == 0) { | |
| 491 benchMode = kDeferredSilent_benchModes; | |
| 492 } else if (strcmp(*argv, "record") == 0) { | |
| 493 benchMode = kRecord_benchModes; | |
| 494 } else if (strcmp(*argv, "picturerecord") == 0) { | |
| 495 benchMode = kPictureRecord_benchModes; | |
| 496 } else { | |
| 497 logger.logError("bad arg for --mode\n"); | |
| 498 help(); | |
| 499 return -1; | |
| 500 } | |
| 501 } else { | |
| 502 logger.logError("missing arg for --mode\n"); | |
| 503 help(); | |
| 504 return -1; | |
| 505 } | |
| 506 } else if (strcmp(*argv, "--strokeWidth") == 0) { | |
| 507 argv++; | |
| 508 if (argv < stop) { | |
| 509 const char *strokeWidthStr = *argv; | |
| 510 if (sscanf(strokeWidthStr, "%f", &strokeWidth) != 1) { | |
| 511 logger.logError("bad arg for --strokeWidth\n"); | |
| 512 help(); | |
| 513 return -1; | |
| 514 } | |
| 515 hasStrokeWidth = true; | |
| 516 } else { | |
| 517 logger.logError("missing arg for --strokeWidth\n"); | |
| 518 help(); | |
| 519 return -1; | |
| 520 } | |
| 521 } else if (strcmp(*argv, "--match") == 0) { | |
| 522 argv++; | |
| 523 while (argv < stop && (*argv)[0] != '-') { | |
| 524 *fMatches.append() = *argv++; | |
| 525 } | |
| 526 argv--; | |
| 527 if (!fMatches.count()) { | |
| 528 logger.logError("missing arg for --match\n"); | |
| 529 help(); | |
| 530 return -1; | |
| 531 } | |
| 532 } else if (strcmp(*argv, "--config") == 0) { | |
| 533 argv++; | |
| 534 if (argv < stop) { | |
| 535 int index = findConfig(*argv); | |
| 536 if (index >= 0) { | |
| 537 *configs.append() = index; | |
| 538 userConfig = true; | |
| 539 } else { | |
| 540 SkString str; | |
| 541 str.printf("unrecognized config %s\n", *argv); | |
| 542 logger.logError(str); | |
| 543 help(); | |
| 544 return -1; | |
| 545 } | |
| 546 } else { | |
| 547 logger.logError("missing arg for --config\n"); | |
| 548 help(); | |
| 549 return -1; | |
| 550 } | |
| 551 } else if (strcmp(*argv, "--logFile") == 0) { | |
| 552 argv++; | |
| 553 if (argv < stop) { | |
| 554 if (!logger.SetLogFile(*argv)) { | |
| 555 SkString str; | |
| 556 str.printf("Could not open %s for writing.", *argv); | |
| 557 logger.logError(str); | |
| 558 return -1; | |
| 559 } | |
| 560 } else { | |
| 561 logger.logError("missing arg for --logFile\n"); | |
| 562 help(); | |
| 563 return -1; | |
| 564 } | |
| 565 } else if (strlen(*argv) > 2 && strncmp(*argv, "-D", 2) == 0) { | |
| 566 argv++; | |
| 567 if (argv < stop) { | |
| 568 defineDict.set(argv[-1] + 2, *argv); | |
| 569 } else { | |
| 570 logger.logError("incomplete '-Dfoo bar' definition\n"); | |
| 571 help(); | |
| 572 return -1; | |
| 573 } | |
| 574 } else if (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0) { | |
| 575 help(); | |
| 576 return 0; | |
| 577 } else { | |
| 578 SkString str; | |
| 579 str.printf("unrecognized arg %s\n", *argv); | |
| 580 logger.logError(str); | |
| 581 help(); | |
| 582 return -1; | |
| 583 } | 307 } |
| 584 } | 308 } |
| 585 if ((benchMode == kRecord_benchModes || benchMode == kPictureRecord_benchMod es) | 309 |
| 586 && !outDir.isEmpty()) { | 310 uint32_t timerTypes = 0; |
| 587 logger.logError("'--mode record' and '--mode picturerecord' are not" | 311 for (const char* c = FLAGS_timers[0]; *c; ++c) { |
| 588 " compatible with -o.\n"); | 312 for (size_t i = 0; i < SK_ARRAY_COUNT(TimerType_Short); i++) { |
| 589 return -1; | 313 if (*c == TimerType_Short[i]) { |
| 314 timerTypes |= (1<<i); | |
| 315 } | |
| 316 } | |
| 590 } | 317 } |
| 591 if ((benchMode == kRecord_benchModes || benchMode == kPictureRecord_benchMod es)) { | 318 |
| 592 perIterTimeformat.set("%.4f"); | 319 BenchMode benchMode = kNormal_BenchMode; |
| 593 normalTimeFormat.set("%6.4f"); | 320 for (size_t i = 0; i < SK_ARRAY_COUNT(BenchMode_Name); i++) { |
| 321 if (strcmp(FLAGS_mode[0], BenchMode_Name[i]) == 0) { | |
| 322 benchMode = static_cast<BenchMode>(i); | |
| 323 } | |
| 594 } | 324 } |
| 595 if (!userConfig) { | 325 |
| 596 // if no config is specified by user, add the default configs | 326 SkTDArray<int> configs; |
| 597 for (unsigned int i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { | 327 // Try user-given configs first. |
| 598 if (gConfigs[i].fRunByDefault) { | 328 for (int i = 0; i < FLAGS_config.count(); i++) { |
| 329 for (size_t j = 0; j < SK_ARRAY_COUNT(gConfigs); j++) { | |
| 330 if (0 == strcmp(FLAGS_config[i], gConfigs[j].name)) { | |
| 331 *configs.append() = j; | |
| 332 } | |
| 333 } | |
| 334 } | |
| 335 // If there weren't any, fill in with defaults. | |
| 336 if (configs.count() == 0) { | |
| 337 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { | |
| 338 if (gConfigs[i].runByDefault) { | |
| 599 *configs.append() = i; | 339 *configs.append() = i; |
| 600 } | 340 } |
| 601 } | 341 } |
| 602 } | 342 } |
| 603 if (kNormal_benchModes != benchMode) { | 343 // Filter out things we can't run. |
| 344 if (kNormal_BenchMode != benchMode) { | |
| 604 // Non-rendering configs only run in normal mode | 345 // Non-rendering configs only run in normal mode |
| 605 for (int i = 0; i < configs.count(); ++i) { | 346 for (int i = 0; i < configs.count(); ++i) { |
| 606 int configIdx = configs[i]; | 347 const Config& config = gConfigs[configs[i]]; |
| 607 if (kNonRendering_Backend == gConfigs[configIdx].fBackend) { | 348 if (kNonRendering_Backend == config.backend) { |
| 608 configs.remove(i, 1); | 349 configs.remove(i, 1); |
| 609 --i; | 350 --i; |
| 610 } | 351 } |
| 611 } | 352 } |
| 612 } | 353 } |
| 613 | |
| 614 #if SK_SUPPORT_GPU | 354 #if SK_SUPPORT_GPU |
| 615 for (int i = 0; i < configs.count(); ++i) { | 355 for (int i = 0; i < configs.count(); ++i) { |
| 616 int configIdx = configs[i]; | 356 const Config& config = gConfigs[configs[i]]; |
| 617 | 357 |
| 618 if (kGPU_Backend == gConfigs[configIdx].fBackend && gConfigs[configIdx]. fSampleCnt > 0) { | 358 if (kGPU_Backend == config.backend) { |
| 619 GrContext* context = gContextFactory.get(gConfigs[configIdx].fContex tType); | 359 GrContext* context = gContextFactory.get(config.contextType); |
| 620 if (NULL == context) { | 360 if (NULL == context) { |
| 621 SkString error; | 361 SkString error; |
| 622 error.printf("Error creating GrContext for config %s. Config wil l be skipped.\n", | 362 error.printf("Error creating GrContext for config %s. Config wil l be skipped.\n", |
| 623 gConfigs[configIdx].fName); | 363 config.name); |
| 624 logger.logError(error.c_str()); | 364 logger.logError(error); |
| 625 configs.remove(i); | 365 configs.remove(i); |
| 626 --i; | 366 --i; |
| 627 continue; | 367 continue; |
| 628 } | 368 } |
| 629 if (gConfigs[configIdx].fSampleCnt > context->getMaxSampleCount()){ | 369 if (config.sampleCount > context->getMaxSampleCount()){ |
| 630 SkString error; | 370 SkString error; |
| 631 error.printf("Sample count (%d) for config %s is unsupported. " | 371 error.printf("Sample count (%d) for config %s is unsupported. " |
| 632 "Config will be skipped.\n", | 372 "Config will be skipped.\n", |
| 633 gConfigs[configIdx].fSampleCnt, gConfigs[configIdx] .fName); | 373 config.sampleCount, config.name); |
| 634 logger.logError(error.c_str()); | 374 logger.logError(error); |
| 635 configs.remove(i); | 375 configs.remove(i); |
| 636 --i; | 376 --i; |
| 637 continue; | 377 continue; |
| 638 } | 378 } |
| 639 } | 379 } |
| 640 } | 380 } |
| 641 #endif | 381 #endif |
| 642 | 382 |
| 643 // report our current settings | 383 // All flags should be parsed now. Report our settings. |
| 644 { | 384 SkString str("skia bench:"); |
| 645 SkString str; | 385 str.appendf(" mode=%s", FLAGS_mode[0]); |
| 646 const char* deferredMode = benchMode == kDeferred_benchModes ? "yes" : | 386 str.appendf(" alpha=0x%02X antialias=%d filter=%d dither=%s", |
| 647 (benchMode == kDeferredSilent_benchModes ? "silent" : "no"); | 387 alpha, FLAGS_forceAA, FLAGS_forceFilter, SkTriState::Name[dither ]); |
| 648 str.printf("skia bench: alpha=0x%02X antialias=%d filter=%d " | 388 str.appendf(" rotate=%d scale=%d clip=%d", FLAGS_rotate, FLAGS_scale, FLAGS_ clip); |
| 649 "deferred=%s logperiter=%d", | 389 |
| 650 forceAlpha, forceAA, forceFilter, deferredMode, | 390 #if defined(SK_SCALAR_IS_FIXED) |
| 651 TimerData::kPerIter_Result == timerResult); | 391 str.append(" scalar=fixed"); |
| 652 str.appendf(" rotate=%d scale=%d clip=%d min=%d", | 392 #else |
| 653 doRotate, doScale, doClip, TimerData::kMin_Result == timerRes ult); | 393 str.append(" scalar=float"); |
| 654 str.appendf(" record=%d picturerecord=%d", | |
| 655 benchMode == kRecord_benchModes, | |
| 656 benchMode == kPictureRecord_benchModes); | |
| 657 const char * ditherName; | |
| 658 switch (forceDither) { | |
| 659 case SkTriState::kDefault: ditherName = "default"; break; | |
| 660 case SkTriState::kTrue: ditherName = "true"; break; | |
| 661 case SkTriState::kFalse: ditherName = "false"; break; | |
| 662 default: ditherName = "<invalid>"; break; | |
| 663 } | |
| 664 str.appendf(" dither=%s", ditherName); | |
| 665 | |
| 666 if (hasStrokeWidth) { | |
| 667 str.appendf(" strokeWidth=%f", strokeWidth); | |
| 668 } else { | |
| 669 str.append(" strokeWidth=none"); | |
| 670 } | |
| 671 | |
| 672 #if defined(SK_SCALAR_IS_FLOAT) | |
| 673 str.append(" scalar=float"); | |
| 674 #elif defined(SK_SCALAR_IS_FIXED) | |
| 675 str.append(" scalar=fixed"); | |
| 676 #endif | 394 #endif |
| 677 | 395 |
| 678 #if defined(SK_BUILD_FOR_WIN32) | 396 #if defined(SK_BUILD_FOR_WIN32) |
| 679 str.append(" system=WIN32"); | 397 str.append(" system=WIN32"); |
| 680 #elif defined(SK_BUILD_FOR_MAC) | 398 #elif defined(SK_BUILD_FOR_MAC) |
| 681 str.append(" system=MAC"); | 399 str.append(" system=MAC"); |
| 682 #elif defined(SK_BUILD_FOR_ANDROID) | 400 #elif defined(SK_BUILD_FOR_ANDROID) |
| 683 str.append(" system=ANDROID"); | 401 str.append(" system=ANDROID"); |
| 684 #elif defined(SK_BUILD_FOR_UNIX) | 402 #elif defined(SK_BUILD_FOR_UNIX) |
| 685 str.append(" system=UNIX"); | 403 str.append(" system=UNIX"); |
| 686 #else | 404 #else |
| 687 str.append(" system=other"); | 405 str.append(" system=other"); |
| 688 #endif | 406 #endif |
| 689 | 407 |
| 690 #if defined(SK_DEBUG) | 408 #if defined(SK_DEBUG) |
| 691 str.append(" DEBUG"); | 409 str.append(" DEBUG"); |
| 692 #endif | 410 #endif |
| 693 str.append("\n"); | 411 str.append("\n"); |
| 694 logger.logProgress(str); | 412 logger.logProgress(str); |
| 695 } | 413 |
| 696 | 414 |
| 697 SkTArray<BenchTimer*> timers(SK_ARRAY_COUNT(gConfigs)); | 415 // Set texture cache limits and get timers suitable for each config. |
| 416 SkTDArray<BenchTimer*> timers; | |
| 698 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { | 417 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { |
| 699 #if SK_SUPPORT_GPU | 418 #if SK_SUPPORT_GPU |
| 419 const Config& config = gConfigs[i]; | |
| 700 SkGLContextHelper* glCtx = NULL; | 420 SkGLContextHelper* glCtx = NULL; |
| 701 if (kGPU_Backend == gConfigs[i].fBackend) { | 421 if (kGPU_Backend == config.backend) { |
| 702 GrContext* context = gContextFactory.get(gConfigs[i].fContextType); | 422 GrContext* context = gContextFactory.get(config.contextType); |
| 703 if (NULL != context) { | 423 if (NULL != context) { |
| 704 // Set the user specified cache limits if non-default. | 424 // Set the user specified cache limits if non-default. |
| 705 size_t bytes; | 425 size_t bytes; |
| 706 int count; | 426 int count; |
| 707 context->getTextureCacheLimits(&count, &bytes); | 427 context->getTextureCacheLimits(&count, &bytes); |
| 708 if (-1 != gpuCacheSize.fBytes) { | 428 if (-1 != FLAGS_gpuCacheBytes) { |
| 709 bytes = static_cast<size_t>(gpuCacheSize.fBytes); | 429 bytes = static_cast<size_t>(FLAGS_gpuCacheBytes); |
| 710 } | 430 } |
| 711 if (-1 != gpuCacheSize.fCount) { | 431 if (-1 != FLAGS_gpuCacheCount) { |
| 712 count = gpuCacheSize.fCount; | 432 count = FLAGS_gpuCacheCount; |
| 713 } | 433 } |
| 714 context->setTextureCacheLimits(count, bytes); | 434 context->setTextureCacheLimits(count, bytes); |
| 715 } | 435 } |
| 716 glCtx = gContextFactory.getGLContext(gConfigs[i].fContextType); | 436 glCtx = gContextFactory.getGLContext(config.contextType); |
| 717 } | 437 } |
| 718 timers.push_back(SkNEW_ARGS(BenchTimer, (glCtx))); | 438 *timers.append() = SkNEW_ARGS(BenchTimer, (glCtx)); |
| 719 #else | 439 #else |
| 720 timers.push_back(SkNEW(BenchTimer)); | 440 *timers.append() = SkNEW(BenchTimer); |
| 721 #endif | 441 #endif |
| 722 } | 442 } |
| 723 | 443 |
| 724 Iter iter(&defineDict); | 444 // Find the longest name of the benches we're going to run to make the outpu t pretty. |
|
scroggo
2013/09/03 19:36:43
I suppose no benches ever use the dictionary?
mtklein
2013/09/03 20:04:43
Yup. I've just been too lazy to un-plumb the void
mtklein
2013/09/04 19:06:51
Turns out unplumbing the void* here is another CL
| |
| 445 Iter names; | |
| 725 SkBenchmark* bench; | 446 SkBenchmark* bench; |
| 447 int longestName = 0; | |
| 448 while ((bench = names.next()) != NULL) { | |
| 449 SkAutoTUnref<SkBenchmark> benchUnref(bench); | |
| 450 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getName())) { | |
| 451 continue; | |
| 452 } | |
| 453 const int length = strlen(bench->getName()); | |
| 454 longestName = length > longestName ? length : longestName; | |
| 455 } | |
| 456 | |
| 457 // Run each bench in each configuration it supports and we asked for. | |
| 458 Iter iter; | |
| 726 while ((bench = iter.next()) != NULL) { | 459 while ((bench = iter.next()) != NULL) { |
| 727 SkAutoTUnref<SkBenchmark> benchUnref(bench); | 460 SkAutoTUnref<SkBenchmark> benchUnref(bench); |
| 728 | 461 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getName())) { |
| 729 SkIPoint dim = bench->getSize(); | |
| 730 if (dim.fX <= 0 || dim.fY <= 0) { | |
| 731 continue; | 462 continue; |
| 732 } | 463 } |
| 733 | 464 |
| 734 bench->setForceAlpha(forceAlpha); | 465 bench->setForceAlpha(alpha); |
| 735 bench->setForceAA(forceAA); | 466 bench->setForceAA(FLAGS_forceAA); |
| 736 bench->setForceFilter(forceFilter); | 467 bench->setForceFilter(FLAGS_forceFilter); |
| 737 bench->setDither(forceDither); | 468 bench->setDither(dither); |
| 738 if (hasStrokeWidth) { | |
| 739 bench->setStrokeWidth(strokeWidth); | |
| 740 } | |
| 741 | |
| 742 // only run benchmarks if their name contains matchStr | |
| 743 if (SkCommandLineFlags::ShouldSkip(fMatches, bench->getName())) { | |
| 744 continue; | |
| 745 } | |
| 746 | |
| 747 bool loggedBenchStart = false; | |
| 748 | |
| 749 AutoPrePostDraw appd(bench); | 469 AutoPrePostDraw appd(bench); |
| 750 | 470 |
| 751 for (int x = 0; x < configs.count(); ++x) { | 471 bool loggedBenchName = false; |
| 752 int configIndex = configs[x]; | 472 for (int i = 0; i < configs.count(); ++i) { |
| 753 | 473 const int configIndex = configs[i]; |
| 754 bool setupFailed = false; | 474 const Config& config = gConfigs[configIndex]; |
| 755 | 475 |
| 756 if (kNonRendering_Backend == gConfigs[configIndex].fBackend) { | 476 if ((kNonRendering_Backend == config.backend) == bench->isRendering( )) { |
| 757 if (bench->isRendering()) { | 477 continue; |
| 758 continue; | 478 } |
| 759 } | 479 |
| 760 } else { | |
| 761 if (!bench->isRendering()) { | |
| 762 continue; | |
| 763 } | |
| 764 } | |
| 765 | |
| 766 outConfig = gConfigs[configIndex].fConfig; | |
| 767 configName = gConfigs[configIndex].fName; | |
| 768 backend = gConfigs[configIndex].fBackend; | |
| 769 sampleCount = gConfigs[configIndex].fSampleCnt; | |
| 770 GrContext* context = NULL; | 480 GrContext* context = NULL; |
| 771 BenchTimer* timer = timers[configIndex]; | |
| 772 | |
| 773 #if SK_SUPPORT_GPU | 481 #if SK_SUPPORT_GPU |
| 774 SkGLContextHelper* glContext = NULL; | 482 SkGLContextHelper* glContext = NULL; |
| 775 if (kGPU_Backend == backend) { | 483 if (kGPU_Backend == config.backend) { |
| 776 context = gContextFactory.get(gConfigs[configIndex].fContextType ); | 484 context = gContextFactory.get(config.contextType); |
| 777 if (NULL == context) { | 485 if (NULL == context) { |
| 778 continue; | 486 continue; |
| 779 } | 487 } |
| 780 glContext = gContextFactory.getGLContext(gConfigs[configIndex].f ContextType); | 488 glContext = gContextFactory.getGLContext(config.contextType); |
| 781 } | 489 } |
| 782 #endif | 490 #endif |
| 783 SkBaseDevice* device = NULL; | 491 SkAutoTUnref<SkBaseDevice> device; |
| 784 SkCanvas* canvas = NULL; | 492 SkAutoTUnref<SkCanvas> canvas; |
| 785 SkPicture pictureRecordFrom; | 493 SkPicture recordFrom, recordTo; |
| 786 SkPicture pictureRecordTo; | 494 const SkIPoint dim = bench->getSize(); |
| 787 | 495 |
| 788 if (kNonRendering_Backend != backend) { | 496 const SkPicture::RecordingFlags kRecordFlags = |
| 789 device = make_device(outConfig, dim, backend, sampleCount, conte xt); | 497 SkPicture::kUsePathBoundsForClip_RecordingFlag; |
| 790 if (NULL == device) { | 498 |
| 499 if (kNonRendering_Backend != config.backend) { | |
| 500 device.reset(make_device(config.config, dim, config.backend, con fig.sampleCount, context)); | |
|
scroggo
2013/09/03 19:36:43
100 chars
mtklein
2013/09/03 20:04:43
Done.
| |
| 501 if (!device.get()) { | |
| 791 SkString error; | 502 SkString error; |
| 792 error.printf("Device creation failure for config %s. Will sk ip.\n", configName); | 503 error.printf("Device creation failure for config %s. Will sk ip.\n", config.name); |
| 793 logger.logError(error.c_str()); | 504 logger.logError(error); |
| 794 setupFailed = true; | 505 continue; |
| 506 } | |
| 507 | |
| 508 switch(benchMode) { | |
| 509 case kDeferredSilent_BenchMode: | |
| 510 case kDeferred_BenchMode: | |
| 511 canvas.reset(SkDeferredCanvas::Create(device.get())); | |
| 512 break; | |
| 513 case kRecord_BenchMode: | |
| 514 canvas.reset(SkRef(recordTo.beginRecording(dim.fX, dim.f Y, kRecordFlags))); | |
| 515 break; | |
| 516 case kPictureRecord_BenchMode: | |
| 517 bench->draw(recordFrom.beginRecording(dim.fX, dim.fY, kR ecordFlags)); | |
| 518 recordFrom.endRecording(); | |
| 519 canvas.reset(SkRef(recordTo.beginRecording(dim.fX, dim.f Y, kRecordFlags))); | |
| 520 break; | |
| 521 case kNormal_BenchMode: | |
| 522 canvas.reset(new SkCanvas(device.get())); | |
| 523 break; | |
| 524 default: | |
| 525 SkASSERT(false); | |
| 526 } | |
| 527 } | |
| 528 | |
| 529 if (NULL != canvas) { | |
| 530 canvas->clear(SK_ColorWHITE); | |
| 531 if (FLAGS_clip) { performClip(canvas, dim.fX, dim.fY); } | |
| 532 if (FLAGS_scale) { performScale(canvas, dim.fX, dim.fY); } | |
| 533 if (FLAGS_rotate) { performRotate(canvas, dim.fX, dim.fY); } | |
| 534 } | |
| 535 | |
| 536 if (!loggedBenchName) { | |
| 537 loggedBenchName = true; | |
| 538 SkString str; | |
| 539 str.printf("running bench [%3d %3d] %*s ", | |
| 540 dim.fX, dim.fY, longestName, bench->getName()); | |
| 541 logger.logProgress(str); | |
| 542 } | |
| 543 | |
| 544 BenchTimer* const timer = timers[configIndex]; | |
| 545 bench->setLoops(0); | |
| 546 do { | |
| 547 // Ramp up 1 -> 4 -> 16 -> ... -> ~1 billion. | |
| 548 const int loops = bench->getLoops(); | |
| 549 if (loops >= (1<<30)) { | |
| 550 SkString str; | |
| 551 str.printf("Can't ramp %s to %dms.\n", bench->getName(), FLA GS_benchMs); | |
| 552 logger.logError(str); | |
| 553 break; | |
| 554 } | |
| 555 bench->setLoops(loops == 0 ? 1 : loops * 4); | |
| 556 | |
| 557 if ((benchMode == kRecord_BenchMode || benchMode == kPictureReco rd_BenchMode)) { | |
| 558 // Clear the recorded commands so that they do not accumulat e. | |
| 559 canvas.reset(recordTo.beginRecording(dim.fX, dim.fY, kRecord Flags)); | |
| 560 } | |
| 561 | |
| 562 timer->start(); | |
| 563 if (NULL != canvas) { | |
| 564 canvas->save(); | |
| 565 } | |
| 566 if (benchMode == kPictureRecord_BenchMode) { | |
| 567 recordFrom.draw(canvas); | |
| 795 } else { | 568 } else { |
| 796 switch(benchMode) { | 569 bench->draw(canvas); |
| 797 case kDeferredSilent_benchModes: | 570 } |
| 798 case kDeferred_benchModes: | 571 |
| 799 canvas = SkDeferredCanvas::Create(device); | 572 if (kDeferredSilent_BenchMode == benchMode) { |
| 800 break; | 573 static_cast<SkDeferredCanvas*>(canvas.get())->silentFlush(); |
| 801 case kRecord_benchModes: | 574 } else if (NULL != canvas) { |
| 802 canvas = pictureRecordTo.beginRecording(dim.fX, dim. fY, | 575 canvas->flush(); |
| 803 SkPicture::kUsePathBoundsForClip_RecordingFlag); | 576 } |
| 804 canvas->ref(); | 577 |
| 805 break; | |
| 806 case kPictureRecord_benchModes: { | |
| 807 // This sets up picture-to-picture recording. | |
| 808 // The C++ drawing calls for the benchmark are recor ded into | |
| 809 // pictureRecordFrom. As the benchmark, we will time how | |
| 810 // long it takes to playback pictureRecordFrom into | |
| 811 // pictureRecordTo. | |
| 812 SkCanvas* tempCanvas = pictureRecordFrom.beginRecord ing(dim.fX, dim.fY, | |
| 813 SkPicture::kUsePathBoundsForClip_RecordingFlag); | |
| 814 bench->draw(tempCanvas); | |
| 815 pictureRecordFrom.endRecording(); | |
| 816 canvas = pictureRecordTo.beginRecording(dim.fX, dim. fY, | |
| 817 SkPicture::kUsePathBoundsForClip_RecordingFlag); | |
| 818 canvas->ref(); | |
| 819 break; | |
| 820 } | |
| 821 case kNormal_benchModes: | |
| 822 canvas = new SkCanvas(device); | |
| 823 break; | |
| 824 default: | |
| 825 SkASSERT(0); | |
| 826 } | |
| 827 device->unref(); | |
| 828 canvas->clear(SK_ColorWHITE); | |
| 829 } | |
| 830 } | |
| 831 SkAutoUnref canvasUnref(canvas); | |
| 832 if (!setupFailed) { | |
| 833 if (NULL != canvas) { | 578 if (NULL != canvas) { |
| 834 if (doClip) { | 579 canvas->restore(); |
| 835 performClip(canvas, dim.fX, dim.fY); | 580 } |
| 836 } | 581 |
| 837 if (doScale) { | 582 |
| 838 performScale(canvas, dim.fX, dim.fY); | 583 // Stop truncated timers before GL calls complete, and stop the full timers after. |
| 839 } | 584 timer->truncatedEnd(); |
| 840 if (doRotate) { | 585 #if SK_SUPPORT_GPU |
| 841 performRotate(canvas, dim.fX, dim.fY); | 586 if (NULL != glContext) { |
| 842 } | 587 context->flush(); |
| 843 } | 588 SK_GL(*glContext, Finish()); |
| 844 | 589 } |
| 845 if (!loggedBenchStart) { | 590 #endif |
| 846 loggedBenchStart = true; | 591 timer->end(); |
| 847 SkString str; | 592 } while (!kIsDebug && timer->fWall < FLAGS_benchMs); |
| 848 str.printf("running bench [%d %d] %28s", dim.fX, dim.fY, ben ch->getName()); | 593 |
| 849 logger.logProgress(str); | 594 if (kIsDebug) { |
| 850 } | 595 // Lets not mislead ourselves by looking at Debug build bench ti mes! |
|
scroggo
2013/09/03 19:36:43
+1
Should this print out an error message as well
mtklein
2013/09/03 20:04:43
Nah, it's not really an error to run bench in Debu
| |
| 851 | 596 continue; |
| 852 // warm up caches if needed | 597 } |
| 853 if (repeatDraw > 1 && NULL != canvas) { | 598 |
| 854 #if SK_SUPPORT_GPU | 599 // In same order as TimerType, multiplied to normalize times to ms p er 1000 iterations. |
| 855 // purge the GPU resources to reduce variance | 600 const double normalize = 1000.0 / bench->getLoops(); |
| 856 if (NULL != context) { | 601 const double times[] = { |
| 857 context->freeGpuResources(); | 602 normalize * timer->fWall, |
| 858 } | 603 normalize * timer->fTruncatedWall, |
| 859 #endif | 604 normalize * timer->fCpu, |
| 860 SkAutoCanvasRestore acr(canvas, true); | 605 normalize * timer->fTruncatedCpu, |
| 861 if (benchMode == kPictureRecord_benchModes) { | 606 normalize * timer->fGpu, |
| 862 pictureRecordFrom.draw(canvas); | 607 }; |
| 863 } else { | 608 |
| 864 bench->draw(canvas); | 609 uint32_t filteredTimerTypes = timerTypes; |
| 865 } | 610 if (NULL == context) { |
| 866 | 611 filteredTimerTypes &= ~(1<<kGpu_TimerType); |
| 867 if (kDeferredSilent_benchModes == benchMode) { | 612 |
| 868 static_cast<SkDeferredCanvas*>(canvas)->silentFlush(); | 613 } |
| 869 } else { | 614 |
| 870 canvas->flush(); | 615 SkString result; |
| 871 } | 616 result.appendf(" %s:", config.name); |
| 872 #if SK_SUPPORT_GPU | 617 for (size_t i = 0; i < SK_ARRAY_COUNT(TimerType_Name); i++) { |
| 873 if (NULL != context) { | 618 if (filteredTimerTypes & (1<<i) && times[i] > 0) { |
| 874 context->flush(); | 619 result.appendf(" %s = ", TimerType_Name[i]); |
| 875 SK_GL(*glContext, Finish()); | 620 result.appendf(FLAGS_timeFormat[0], times[i]); |
| 876 } | 621 } |
| 877 #endif | 622 } |
| 878 } | 623 logger.logProgress(result); |
| 879 | 624 |
| 880 // record timer values for each repeat, and their sum | 625 if (FLAGS_outDir.count() && kNonRendering_Backend != config.backend) { |
| 881 TimerData timerData(repeatDraw); | 626 saveFile(bench->getName(), |
| 882 for (int i = 0; i < repeatDraw; i++) { | 627 config.name, |
| 883 if ((benchMode == kRecord_benchModes || benchMode == kPictur eRecord_benchModes)) { | 628 FLAGS_outDir[0], |
| 884 // This will clear the recorded commands so that they do not | 629 device->accessBitmap(false)); |
| 885 // accumulate. | 630 } |
| 886 canvas = pictureRecordTo.beginRecording(dim.fX, dim.fY, | 631 } |
| 887 SkPicture::kUsePathBoundsForClip_RecordingFlag); | 632 if (loggedBenchName) { |
| 888 } | 633 logger.logProgress("\n"); |
| 889 | 634 } |
| 890 timer->start(bench->getDurationScale()); | 635 } |
| 891 if (NULL != canvas) { | 636 timers.deleteAll(); |
| 892 canvas->save(); | 637 #if SK_SUPPORT_GPU |
| 893 } | |
| 894 if (benchMode == kPictureRecord_benchModes) { | |
| 895 pictureRecordFrom.draw(canvas); | |
| 896 } else { | |
| 897 bench->draw(canvas); | |
| 898 } | |
| 899 | |
| 900 if (kDeferredSilent_benchModes == benchMode) { | |
| 901 static_cast<SkDeferredCanvas*>(canvas)->silentFlush(); | |
| 902 } else if (NULL != canvas) { | |
| 903 canvas->flush(); | |
| 904 } | |
| 905 | |
| 906 if (NULL != canvas) { | |
| 907 canvas->restore(); | |
| 908 } | |
| 909 | |
| 910 // stop the truncated timer after the last canvas call but | |
| 911 // don't wait for all the GL calls to complete | |
| 912 timer->truncatedEnd(); | |
| 913 #if SK_SUPPORT_GPU | |
| 914 if (NULL != glContext) { | |
| 915 context->flush(); | |
| 916 SK_GL(*glContext, Finish()); | |
| 917 } | |
| 918 #endif | |
| 919 // stop the inclusive and gpu timers once all the GL calls | |
| 920 // have completed | |
| 921 timer->end(); | |
| 922 | |
| 923 SkAssertResult(timerData.appendTimes(timer)); | |
| 924 | |
| 925 } | |
| 926 if (repeatDraw > 1) { | |
| 927 const char* timeFormat; | |
| 928 if (TimerData::kPerIter_Result == timerResult) { | |
| 929 timeFormat = perIterTimeformat.c_str(); | |
| 930 } else { | |
| 931 timeFormat = normalTimeFormat.c_str(); | |
| 932 } | |
| 933 uint32_t filteredTimerTypes = timerTypes; | |
| 934 if (NULL == context) { | |
| 935 filteredTimerTypes &= ~TimerData::kGpu_Flag; | |
| 936 } | |
| 937 SkString result = timerData.getResult(timeFormat, | |
| 938 timerResult, | |
| 939 configName, | |
| 940 filteredTimerTypes); | |
| 941 logger.logProgress(result); | |
| 942 } | |
| 943 if (outDir.size() > 0 && kNonRendering_Backend != backend) { | |
| 944 saveFile(bench->getName(), configName, outDir.c_str(), | |
| 945 device->accessBitmap(false)); | |
| 946 } | |
| 947 } | |
| 948 } | |
| 949 if (loggedBenchStart) { | |
| 950 logger.logProgress(SkString("\n")); | |
| 951 } | |
| 952 } | |
| 953 #if SK_SUPPORT_GPU | |
| 954 #if GR_CACHE_STATS | |
| 955 for (int i = 0; i <= GrContextFactory::kLastGLContextType; ++i) { | |
| 956 GrContextFactory::GLContextType ctxType = (GrContextFactory::GLContextTy pe)i; | |
| 957 GrContext* context = gContextFactory.get(ctxType); | |
| 958 if (NULL != context) { | |
| 959 SkDebugf("Cache Stats for %s context:\n", GrContextFactory::GLContex tTypeName(ctxType)); | |
| 960 context->printCacheStats(); | |
| 961 SkDebugf("\n"); | |
| 962 } | |
| 963 } | |
| 964 #endif | |
| 965 // Destroy the GrContext before the inst tracking printing at main() exit oc curs. | |
| 966 gContextFactory.destroyContexts(); | 638 gContextFactory.destroyContexts(); |
| 967 #endif | 639 #endif |
| 968 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { | |
| 969 SkDELETE(timers[i]); | |
| 970 } | |
| 971 | |
| 972 return 0; | 640 return 0; |
| 973 } | 641 } |
| 974 | 642 |
| 975 #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) | 643 #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) |
| 976 int main(int argc, char * const argv[]) { | 644 int main(int argc, char * const argv[]) { |
| 977 return tool_main(argc, (char**) argv); | 645 return tool_main(argc, (char**) argv); |
| 978 } | 646 } |
| 979 #endif | 647 #endif |
| OLD | NEW |