Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(10)

Side by Side Diff: tools/kilobench/kilobench.cpp

Issue 1594553003: Modify kilobench to run each sample in its own process (Closed) Base URL: https://skia.googlesource.com/skia.git@kilobench-2-setupcanvas
Patch Set: check return values of pipe, read, write Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « gyp/most.gyp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2016 Google Inc. 2 * Copyright 2016 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "GrCaps.h" 8 #include "GrCaps.h"
9 #include "GrContextFactory.h" 9 #include "GrContextFactory.h"
10 #include "Benchmark.h" 10 #include "Benchmark.h"
11 #include "ResultsWriter.h"
11 #include "SkCommandLineFlags.h" 12 #include "SkCommandLineFlags.h"
12 #include "SkOSFile.h" 13 #include "SkOSFile.h"
13 #include "SkStream.h" 14 #include "SkStream.h"
14 #include "SkSurface.h" 15 #include "SkSurface.h"
15 #include "SkTime.h" 16 #include "SkTime.h"
16 #include "Stats.h" 17 #include "Stats.h"
17 #include "Timer.h" 18 #include "Timer.h"
18 #include "VisualSKPBench.h" 19 #include "VisualSKPBench.h"
19 #include "gl/GrGLDefines.h" 20 #include "gl/GrGLDefines.h"
20 21
22 // posix only for now
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <sys/wait.h>
26
21 /* 27 /*
22 * This is an experimental GPU only benchmarking program. The initial implement ation will only 28 * This is an experimental GPU only benchmarking program. The initial implement ation will only
23 * support SKPs. 29 * support SKPs.
24 */ 30 */
25 31
26 // To get image decoders linked in we have to do the below magic 32 // To get image decoders linked in we have to do the below magic
27 #include "SkForceLinking.h" 33 #include "SkForceLinking.h"
28 #include "SkImageDecoder.h" 34 #include "SkImageDecoder.h"
29 __SK_FORCE_IMAGE_DECODER_LINKING; 35 __SK_FORCE_IMAGE_DECODER_LINKING;
30 36
(...skipping 25 matching lines...) Expand all
56 "^ and $ requires an exact match\n" 62 "^ and $ requires an exact match\n"
57 "If a bench does not match any list entry,\n" 63 "If a bench does not match any list entry,\n"
58 "it is skipped unless some list entry starts with ~"); 64 "it is skipped unless some list entry starts with ~");
59 DEFINE_int32(gpuFrameLag, 5, "If unknown, estimated maximum number of frames GPU allows to lag."); 65 DEFINE_int32(gpuFrameLag, 5, "If unknown, estimated maximum number of frames GPU allows to lag.");
60 DEFINE_int32(samples, 10, "Number of samples to measure for each bench."); 66 DEFINE_int32(samples, 10, "Number of samples to measure for each bench.");
61 DEFINE_int32(maxLoops, 1000000, "Never run a bench more times than this."); 67 DEFINE_int32(maxLoops, 1000000, "Never run a bench more times than this.");
62 DEFINE_int32(loops, kDefaultLoops, loops_help_txt().c_str()); 68 DEFINE_int32(loops, kDefaultLoops, loops_help_txt().c_str());
63 DEFINE_double(gpuMs, 5, "Target bench time in millseconds for GPU."); 69 DEFINE_double(gpuMs, 5, "Target bench time in millseconds for GPU.");
64 DEFINE_string2(writePath, w, "", "If set, write bitmaps here as .pngs."); 70 DEFINE_string2(writePath, w, "", "If set, write bitmaps here as .pngs.");
65 71
72 static SkString humanize(double ms) {
73 return HumanizeMs(ms);
74 }
75 #define HUMANIZE(ms) humanize(ms).c_str()
76
66 namespace kilobench { 77 namespace kilobench {
67 class BenchmarkStream { 78 class BenchmarkStream {
68 public: 79 public:
69 BenchmarkStream() : fCurrentSKP(0) { 80 BenchmarkStream() : fCurrentSKP(0) {
70 for (int i = 0; i < FLAGS_skps.count(); i++) { 81 for (int i = 0; i < FLAGS_skps.count(); i++) {
71 if (SkStrEndsWith(FLAGS_skps[i], ".skp")) { 82 if (SkStrEndsWith(FLAGS_skps[i], ".skp")) {
72 fSKPs.push_back() = FLAGS_skps[i]; 83 fSKPs.push_back() = FLAGS_skps[i];
73 } else { 84 } else {
74 SkOSFile::Iter it(FLAGS_skps[i], ".skp"); 85 SkOSFile::Iter it(FLAGS_skps[i], ".skp");
75 SkString path; 86 SkString path;
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after
315 326
316 // Pretty much the same deal as the calibration: do some warmup to make 327 // Pretty much the same deal as the calibration: do some warmup to make
317 // sure we're timing steady-state pipelined frames. 328 // sure we're timing steady-state pipelined frames.
318 for (int i = 0; i < maxGpuFrameLag - 1; i++) { 329 for (int i = 0; i < maxGpuFrameLag - 1; i++) {
319 time(loops, bench, target); 330 time(loops, bench, target);
320 } 331 }
321 332
322 return loops; 333 return loops;
323 } 334 }
324 335
325 static SkString humanize(double ms) { 336 struct AutoSetupContextBenchAndTarget {
326 return HumanizeMs(ms); 337 AutoSetupContextBenchAndTarget(Benchmark* bench) : fBenchmark(bench) {
327 } 338 GrContextOptions grContextOpts;
328 #define HUMANIZE(ms) humanize(ms).c_str() 339 fCtxFactory.reset(new GrContextFactory(grContextOpts));
329 340
330 void benchmark_inner_loop(Benchmark* bench, GrContextFactory* ctxFactory) { 341 SkAssertResult(fTarget.init(bench, fCtxFactory, false,
331 SkTArray<double> samples; 342 GrContextFactory::kNative_GLContextType,
332 GPUTarget target; 343 GrContextFactory::kNone_GLContextOptions, 0) );
333 SkAssertResult(target.init(bench, ctxFactory, false,
334 GrContextFactory::kNative_GLContextType,
335 GrContextFactory::kNone_GLContextOptions, 0));
336 344
337 SkCanvas* canvas = target.getCanvas(); 345 fCanvas = fTarget.getCanvas();
338 target.setup(); 346 fTarget.setup();
339 347
340 bench->perCanvasPreDraw(canvas); 348 bench->perCanvasPreDraw(fCanvas);
341 int maxFrameLag; 349 fTarget.needsFrameTiming(&fMaxFrameLag);
342 target.needsFrameTiming(&maxFrameLag);
343 int loops = setup_gpu_bench(&target, bench, maxFrameLag);
344
345 samples.reset(FLAGS_samples);
346 for (int s = 0; s < FLAGS_samples; s++) {
347 samples[s] = time(loops, bench, &target) / loops;
348 } 350 }
349 351
350 bench->perCanvasPostDraw(canvas); 352 int getLoops() { return setup_gpu_bench(&fTarget, fBenchmark, fMaxFrameLag); }
351 353
352 Stats stats(samples); 354 double timeSample(int loops) {
353 const double stddev_percent = 100 * sqrt(stats.var) / stats.mean; 355 for (int i = 0; i < fMaxFrameLag; i++) {
354 SkDebugf("%d\t%s\t%s\t%s\t%s\t%.0f%%\t%s\t%s\t%s\n" 356 time(loops, fBenchmark, &fTarget);
355 , loops 357 }
356 , HUMANIZE(stats.min) 358
357 , HUMANIZE(stats.median) 359 return time(loops, fBenchmark, &fTarget) / loops;
358 , HUMANIZE(stats.mean) 360 }
359 , HUMANIZE(stats.max) 361 void teardownBench() { fBenchmark->perCanvasPostDraw(fCanvas); }
360 , stddev_percent 362
361 , stats.plot.c_str() 363 SkAutoTDelete<GrContextFactory> fCtxFactory;
362 , "gpu" 364 GPUTarget fTarget;
363 , bench->getUniqueName() 365 SkCanvas* fCanvas;
364 ); 366 Benchmark* fBenchmark;
367 int fMaxFrameLag;
368 };
369
370 int setup_loops(Benchmark* bench) {
371 AutoSetupContextBenchAndTarget ascbt(bench);
372 int loops = ascbt.getLoops();
373 ascbt.teardownBench();
365 374
366 if (!FLAGS_writePath.isEmpty() && FLAGS_writePath[0]) { 375 if (!FLAGS_writePath.isEmpty() && FLAGS_writePath[0]) {
367 SkString pngFilename = SkOSPath::Join(FLAGS_writePath[0], "gpu"); 376 SkString pngFilename = SkOSPath::Join(FLAGS_writePath[0], "gpu");
368 pngFilename = SkOSPath::Join(pngFilename.c_str(), bench->getUniqueName() ); 377 pngFilename = SkOSPath::Join(pngFilename.c_str(), bench->getUniqueName() );
369 pngFilename.append(".png"); 378 pngFilename.append(".png");
370 write_canvas_png(&target, pngFilename); 379 write_canvas_png(&ascbt.fTarget, pngFilename);
371 } 380 }
381 return loops;
382 }
383
384 double time_sample(Benchmark* bench, int loops) {
385 AutoSetupContextBenchAndTarget ascbt(bench);
386 double sample = ascbt.timeSample(loops);
387 ascbt.teardownBench();
388
389 return sample;
372 } 390 }
373 391
374 } // namespace kilobench 392 } // namespace kilobench
375 393
394 static const int kOutResultSize = 1024;
395
376 int kilobench_main() { 396 int kilobench_main() {
377 SkAutoTDelete<GrContextFactory> ctxFactory;
378
379 GrContextOptions grContextOpts;
380 ctxFactory.reset(new GrContextFactory(grContextOpts));
381
382 kilobench::BenchmarkStream benchStream; 397 kilobench::BenchmarkStream benchStream;
383 398
384 SkDebugf("loops\tmin\tmedian\tmean\tmax\tstddev\t%-*s\tconfig\tbench\n", 399 SkDebugf("loops\tmin\tmedian\tmean\tmax\tstddev\t%-*s\tconfig\tbench\n",
385 FLAGS_samples, "samples"); 400 FLAGS_samples, "samples");
386 401
402 int descriptors[2];
403 if (pipe(descriptors) != 0) {
404 SkFAIL("Failed to open a pipe\n");
405 }
406
387 while (Benchmark* b = benchStream.next()) { 407 while (Benchmark* b = benchStream.next()) {
388 SkAutoTDelete<Benchmark> bench(b); 408 SkAutoTDelete<Benchmark> bench(b);
389 kilobench::benchmark_inner_loop(bench.get(), ctxFactory.get()); 409
410 int loops;
411 SkTArray<double> samples;
412 for (int i = 0; i < FLAGS_samples + 1; i++) {
413 // We fork off a new process to setup the grcontext and run the test while we wait
414 int childPid = fork();
415 if (childPid > 0) {
416 char result[kOutResultSize];
417 if (read(descriptors[0], result, kOutResultSize) < 0) {
418 SkFAIL("Failed to read from pipe\n");
419 }
420
421 // if samples == 0 then parse # of loops
422 // else parse float
423 if (i == 0) {
424 sscanf(result, "%d", &loops);
425 } else {
426 sscanf(result, "%lf", &samples.push_back());
427 }
428
429 // wait until exit
430 int status;
431 waitpid(childPid, &status, 0);
432 } else if (0 == childPid) {
433 char result[kOutResultSize];
434 if (i == 0) {
435 sprintf(result, "%d", kilobench::setup_loops(bench));
436 } else {
437 sprintf(result, "%lf", kilobench::time_sample(bench, loops)) ;
438 }
439
440 // Make sure to write the null terminator
441 if (write(descriptors[1], result, strlen(result) + 1) < 0) {
442 SkFAIL("Failed to write to pipe\n");
443 }
444 return 0;
445 } else {
446 SkFAIL("Fork failed\n");
447 }
448 }
449
450 Stats stats(samples);
451 const double stddev_percent = 100 * sqrt(stats.var) / stats.mean;
452 SkDebugf("%d\t%s\t%s\t%s\t%s\t%.0f%%\t%s\t%s\t%s\n"
453 , loops
454 , HUMANIZE(stats.min)
455 , HUMANIZE(stats.median)
456 , HUMANIZE(stats.mean)
457 , HUMANIZE(stats.max)
458 , stddev_percent
459 , stats.plot.c_str()
460 , "gpu"
461 , bench->getUniqueName()
462 );
463
390 } 464 }
391
392 // Make sure we clean up the global GrContextFactory here, otherwise we migh t race with the
393 // SkEventTracer destructor
394 ctxFactory.reset(nullptr);
395 return 0; 465 return 0;
396 } 466 }
397 467
398 #if !defined SK_BUILD_FOR_IOS 468 #if !defined SK_BUILD_FOR_IOS
399 int main(int argc, char** argv) { 469 int main(int argc, char** argv) {
400 SkCommandLineFlags::Parse(argc, argv); 470 SkCommandLineFlags::Parse(argc, argv);
401 return kilobench_main(); 471 return kilobench_main();
402 } 472 }
403 #endif 473 #endif
OLDNEW
« no previous file with comments | « gyp/most.gyp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698