1/* 2 * Copyright 2015 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 "VisualLightweightBenchModule.h" 9 10#include "ProcStats.h" 11#include "SkApplication.h" 12#include "SkCanvas.h" 13#include "SkCommandLineFlags.h" 14#include "SkForceLinking.h" 15#include "SkGraphics.h" 16#include "SkGr.h" 17#include "SkImageDecoder.h" 18#include "SkOSFile.h" 19#include "SkStream.h" 20#include "Stats.h" 21#include "gl/GrGLInterface.h" 22 23__SK_FORCE_IMAGE_DECODER_LINKING; 24 25// Between samples we reset context 26// Between frames we swap buffers 27DEFINE_bool2(verbose, v, false, "enable verbose output from the test driver."); 28DEFINE_string(outResultsFile, "", "If given, write results here as JSON."); 29DEFINE_string(key, "", 30 "Space-separated key/value pairs to add to JSON identifying this builder."); 31DEFINE_string(properties, "", 32 "Space-separated key/value pairs to add to JSON identifying this run."); 33DEFINE_int32(samples, 10, "Number of times to time each skp."); 34 35static SkString humanize(double ms) { 36 if (FLAGS_verbose) { 37 return SkStringPrintf("%llu", (uint64_t)(ms*1e6)); 38 } 39 return HumanizeMs(ms); 40} 41 42#define HUMANIZE(time) humanize(time).c_str() 43 44VisualLightweightBenchModule::VisualLightweightBenchModule(VisualBench* owner) 45 : INHERITED(owner) 46 , fCurrentSample(0) 47 , fResults(new ResultsWriter) { 48 // Print header 49 SkDebugf("curr/maxrss\tloops\tmin\tmedian\tmean\tmax\tstddev\t%-*s\tconfig\tbench\n", 50 FLAGS_samples, "samples"); 51 52 // setup json logging if required 53 if (!FLAGS_outResultsFile.isEmpty()) { 54 fResults.reset(new NanoJSONResultsWriter(FLAGS_outResultsFile[0])); 55 } 56 57 if (1 == FLAGS_key.count() % 2) { 58 SkDebugf("ERROR: --key must be passed with an even number of arguments.\n"); 59 } else { 60 for (int i = 1; i < FLAGS_key.count(); i += 2) { 61 fResults->key(FLAGS_key[i - 1], FLAGS_key[i]); 62 } 63 } 64 65 if (1 == FLAGS_properties.count() % 2) { 66 SkDebugf("ERROR: --properties must be passed with an even number of arguments.\n"); 67 } else { 68 for (int i = 1; i < FLAGS_properties.count(); i += 2) { 69 fResults->property(FLAGS_properties[i - 1], FLAGS_properties[i]); 70 } 71 } 72 73 // seed an initial record 74 fRecords.push_back(); 75} 76 77void VisualLightweightBenchModule::renderFrame(SkCanvas* canvas, Benchmark* benchmark, int loops) { 78 benchmark->draw(loops, canvas); 79 canvas->flush(); 80} 81 82void VisualLightweightBenchModule::printStats(Benchmark* benchmark, int loops) { 83 const SkTArray<double>& measurements = fRecords.back().fMeasurements; 84 const char* shortName = benchmark->getUniqueName(); 85 86 // update log 87 // Note: We currently log only the minimum. It would be interesting to log more information 88 SkString configName; 89 if (FLAGS_cpu) { 90 configName.append("cpu"); 91 } else if (FLAGS_nvpr) { 92 if (FLAGS_offscreen) { 93 configName.appendf("nvpr_%d", FLAGS_msaa); 94 } else { 95 configName.appendf("nvpr_msaa_%d", FLAGS_msaa); 96 } 97 } else if (FLAGS_msaa > 0) { 98 if (FLAGS_offscreen) { 99 configName.appendf("offscreen_msaa_%d", FLAGS_msaa); 100 } else { 101 configName.appendf("msaa_%d", FLAGS_msaa); 102 } 103 } else { 104 if (FLAGS_offscreen) { 105 configName.append("offscreen"); 106 } else { 107 configName.append("gpu"); 108 } 109 } 110 // Log bench name 111 fResults->bench(shortName, benchmark->getSize().fX, benchmark->getSize().fY); 112 113 fResults->config(configName.c_str()); 114 fResults->configOption("name", shortName); 115 SkASSERT(measurements.count()); 116 Stats stats(measurements); 117 fResults->metric("min_ms", stats.min); 118 119 // Print output 120 if (FLAGS_verbose) { 121 for (int i = 0; i < measurements.count(); i++) { 122 SkDebugf("%s ", HUMANIZE(measurements[i])); 123 } 124 SkDebugf("%s\n", shortName); 125 } else { 126 const double stdDevPercent = 100 * sqrt(stats.var) / stats.mean; 127 SkDebugf("%4d/%-4dMB\t%d\t%s\t%s\t%s\t%s\t%.0f%%\t%s\t%s\t%s\n", 128 sk_tools::getCurrResidentSetSizeMB(), 129 sk_tools::getMaxResidentSetSizeMB(), 130 loops, 131 HUMANIZE(stats.min), 132 HUMANIZE(stats.median), 133 HUMANIZE(stats.mean), 134 HUMANIZE(stats.max), 135 stdDevPercent, 136 stats.plot.c_str(), 137 configName.c_str(), 138 shortName); 139 } 140} 141 142bool VisualLightweightBenchModule::timingFinished(Benchmark* benchmark, int loops, 143 double measurement) { 144 fRecords.back().fMeasurements.push_back(measurement); 145 if (++fCurrentSample > FLAGS_samples) { 146 this->printStats(benchmark, loops); 147 fRecords.push_back(); 148 fCurrentSample = 0; 149 return true; 150 } 151 return false; 152} 153 154bool VisualLightweightBenchModule::onHandleChar(SkUnichar c) { 155 return true; 156} 157