OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 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 * | |
7 */ | 6 */ |
8 | 7 |
9 #include "VisualLightweightBenchModule.h" | 8 #include "VisualLightweightBenchModule.h" |
10 | 9 |
11 #include "ProcStats.h" | 10 #include "ProcStats.h" |
12 #include "SkApplication.h" | 11 #include "SkApplication.h" |
13 #include "SkCanvas.h" | 12 #include "SkCanvas.h" |
14 #include "SkCommandLineFlags.h" | 13 #include "SkCommandLineFlags.h" |
15 #include "SkForceLinking.h" | 14 #include "SkForceLinking.h" |
16 #include "SkGraphics.h" | 15 #include "SkGraphics.h" |
(...skipping 19 matching lines...) Expand all Loading... |
36 static SkString humanize(double ms) { | 35 static SkString humanize(double ms) { |
37 if (FLAGS_verbose) { | 36 if (FLAGS_verbose) { |
38 return SkStringPrintf("%llu", (uint64_t)(ms*1e6)); | 37 return SkStringPrintf("%llu", (uint64_t)(ms*1e6)); |
39 } | 38 } |
40 return HumanizeMs(ms); | 39 return HumanizeMs(ms); |
41 } | 40 } |
42 | 41 |
43 #define HUMANIZE(time) humanize(time).c_str() | 42 #define HUMANIZE(time) humanize(time).c_str() |
44 | 43 |
45 VisualLightweightBenchModule::VisualLightweightBenchModule(VisualBench* owner) | 44 VisualLightweightBenchModule::VisualLightweightBenchModule(VisualBench* owner) |
46 : fCurrentSample(0) | 45 : INHERITED(owner, true) |
47 , fHasBeenReset(false) | 46 , fCurrentSample(0) |
48 , fOwner(SkRef(owner)) | |
49 , fResults(new ResultsWriter) { | 47 , fResults(new ResultsWriter) { |
50 fBenchmarkStream.reset(new VisualBenchmarkStream); | |
51 | |
52 // Print header | 48 // Print header |
53 SkDebugf("curr/maxrss\tloops\tmin\tmedian\tmean\tmax\tstddev\t%-*s\tbench\n"
, FLAGS_samples, | 49 SkDebugf("curr/maxrss\tloops\tmin\tmedian\tmean\tmax\tstddev\t%-*s\tbench\n"
, FLAGS_samples, |
54 "samples"); | 50 "samples"); |
55 | 51 |
56 // setup json logging if required | 52 // setup json logging if required |
57 if (!FLAGS_outResultsFile.isEmpty()) { | 53 if (!FLAGS_outResultsFile.isEmpty()) { |
58 fResults.reset(new NanoJSONResultsWriter(FLAGS_outResultsFile[0])); | 54 fResults.reset(new NanoJSONResultsWriter(FLAGS_outResultsFile[0])); |
59 } | 55 } |
60 | 56 |
61 if (1 == FLAGS_key.count() % 2) { | 57 if (1 == FLAGS_key.count() % 2) { |
62 SkDebugf("ERROR: --key must be passed with an even number of arguments.\
n"); | 58 SkDebugf("ERROR: --key must be passed with an even number of arguments.\
n"); |
63 } else { | 59 } else { |
64 for (int i = 1; i < FLAGS_key.count(); i += 2) { | 60 for (int i = 1; i < FLAGS_key.count(); i += 2) { |
65 fResults->key(FLAGS_key[i - 1], FLAGS_key[i]); | 61 fResults->key(FLAGS_key[i - 1], FLAGS_key[i]); |
66 } | 62 } |
67 } | 63 } |
68 | 64 |
69 if (1 == FLAGS_properties.count() % 2) { | 65 if (1 == FLAGS_properties.count() % 2) { |
70 SkDebugf("ERROR: --properties must be passed with an even number of argu
ments.\n"); | 66 SkDebugf("ERROR: --properties must be passed with an even number of argu
ments.\n"); |
71 } else { | 67 } else { |
72 for (int i = 1; i < FLAGS_properties.count(); i += 2) { | 68 for (int i = 1; i < FLAGS_properties.count(); i += 2) { |
73 fResults->property(FLAGS_properties[i - 1], FLAGS_properties[i]); | 69 fResults->property(FLAGS_properties[i - 1], FLAGS_properties[i]); |
74 } | 70 } |
75 } | 71 } |
| 72 |
| 73 // seed an initial record |
| 74 fRecords.push_back(); |
76 } | 75 } |
77 | 76 |
78 inline void VisualLightweightBenchModule::renderFrame(SkCanvas* canvas) { | 77 void VisualLightweightBenchModule::renderFrame(SkCanvas* canvas, Benchmark* benc
hmark, int loops) { |
79 fBenchmark->draw(fTSM.loops(), canvas); | 78 benchmark->draw(loops, canvas); |
80 canvas->flush(); | 79 canvas->flush(); |
81 fOwner->present(); | |
82 } | 80 } |
83 | 81 |
84 void VisualLightweightBenchModule::printStats() { | 82 void VisualLightweightBenchModule::printStats(Benchmark* benchmark, int loops) { |
85 const SkTArray<double>& measurements = fRecords.back().fMeasurements; | 83 const SkTArray<double>& measurements = fRecords.back().fMeasurements; |
86 const char* shortName = fBenchmark->getUniqueName(); | 84 const char* shortName = benchmark->getUniqueName(); |
87 | 85 |
88 // update log | 86 // update log |
89 // Note: We currently log only the minimum. It would be interesting to log
more information | 87 // Note: We currently log only the minimum. It would be interesting to log
more information |
90 SkString configName; | 88 SkString configName; |
91 if (FLAGS_msaa > 0) { | 89 if (FLAGS_msaa > 0) { |
92 configName.appendf("msaa_%d", FLAGS_msaa); | 90 configName.appendf("msaa_%d", FLAGS_msaa); |
93 } else { | 91 } else { |
94 configName.appendf("gpu"); | 92 configName.appendf("gpu"); |
95 } | 93 } |
| 94 // Log bench name |
| 95 fResults->bench(shortName, benchmark->getSize().fX, benchmark->getSize().fY)
; |
| 96 |
96 fResults->config(configName.c_str()); | 97 fResults->config(configName.c_str()); |
97 fResults->configOption("name", shortName); | 98 fResults->configOption("name", shortName); |
98 SkASSERT(measurements.count()); | 99 SkASSERT(measurements.count()); |
99 Stats stats(measurements); | 100 Stats stats(measurements); |
100 fResults->metric("min_ms", stats.min); | 101 fResults->metric("min_ms", stats.min); |
101 | 102 |
102 // Print output | 103 // Print output |
103 if (FLAGS_verbose) { | 104 if (FLAGS_verbose) { |
104 for (int i = 0; i < measurements.count(); i++) { | 105 for (int i = 0; i < measurements.count(); i++) { |
105 SkDebugf("%s ", HUMANIZE(measurements[i])); | 106 SkDebugf("%s ", HUMANIZE(measurements[i])); |
106 } | 107 } |
107 SkDebugf("%s\n", shortName); | 108 SkDebugf("%s\n", shortName); |
108 } else { | 109 } else { |
109 const double stdDevPercent = 100 * sqrt(stats.var) / stats.mean; | 110 const double stdDevPercent = 100 * sqrt(stats.var) / stats.mean; |
110 SkDebugf("%4d/%-4dMB\t%d\t%s\t%s\t%s\t%s\t%.0f%%\t%s\t%s\n", | 111 SkDebugf("%4d/%-4dMB\t%d\t%s\t%s\t%s\t%s\t%.0f%%\t%s\t%s\n", |
111 sk_tools::getCurrResidentSetSizeMB(), | 112 sk_tools::getCurrResidentSetSizeMB(), |
112 sk_tools::getMaxResidentSetSizeMB(), | 113 sk_tools::getMaxResidentSetSizeMB(), |
113 fTSM.loops(), | 114 loops, |
114 HUMANIZE(stats.min), | 115 HUMANIZE(stats.min), |
115 HUMANIZE(stats.median), | 116 HUMANIZE(stats.median), |
116 HUMANIZE(stats.mean), | 117 HUMANIZE(stats.mean), |
117 HUMANIZE(stats.max), | 118 HUMANIZE(stats.max), |
118 stdDevPercent, | 119 stdDevPercent, |
119 stats.plot.c_str(), | 120 stats.plot.c_str(), |
120 shortName); | 121 shortName); |
121 } | 122 } |
122 } | 123 } |
123 | 124 |
124 bool VisualLightweightBenchModule::advanceRecordIfNecessary(SkCanvas* canvas) { | 125 bool VisualLightweightBenchModule::timingFinished(Benchmark* benchmark, int loop
s, |
125 if (fBenchmark) { | 126 double measurement) { |
| 127 fRecords.back().fMeasurements.push_back(measurement); |
| 128 if (++fCurrentSample > FLAGS_samples) { |
| 129 this->printStats(benchmark, loops); |
| 130 fRecords.push_back(); |
| 131 fCurrentSample = 0; |
126 return true; | 132 return true; |
127 } | 133 } |
128 | 134 return false; |
129 fBenchmark.reset(fBenchmarkStream->next()); | |
130 if (!fBenchmark) { | |
131 return false; | |
132 } | |
133 | |
134 fOwner->clear(canvas, SK_ColorWHITE, 2); | |
135 | |
136 fRecords.push_back(); | |
137 | |
138 // Log bench name | |
139 fResults->bench(fBenchmark->getUniqueName(), fBenchmark->getSize().fX, | |
140 fBenchmark->getSize().fY); | |
141 | |
142 fBenchmark->delayedSetup(); | |
143 fBenchmark->preTimingHooks(canvas); | |
144 return true; | |
145 } | |
146 | |
147 void VisualLightweightBenchModule::draw(SkCanvas* canvas) { | |
148 if (!this->advanceRecordIfNecessary(canvas)) { | |
149 SkDebugf("Exiting VisualBench successfully\n"); | |
150 fOwner->closeWindow(); | |
151 return; | |
152 } | |
153 | |
154 if (fHasBeenReset) { | |
155 fHasBeenReset = false; | |
156 fBenchmark->preTimingHooks(canvas); | |
157 } | |
158 | |
159 this->renderFrame(canvas); | |
160 TimingStateMachine::ParentEvents event = fTSM.nextFrame(true); | |
161 switch (event) { | |
162 case TimingStateMachine::kReset_ParentEvents: | |
163 fBenchmark->postTimingHooks(canvas); | |
164 fOwner->reset(); | |
165 fHasBeenReset = true; | |
166 break; | |
167 case TimingStateMachine::kTiming_ParentEvents: | |
168 break; | |
169 case TimingStateMachine::kTimingFinished_ParentEvents: | |
170 fBenchmark->postTimingHooks(canvas); | |
171 fOwner->reset(); | |
172 fRecords.back().fMeasurements.push_back(fTSM.lastMeasurement()); | |
173 if (++fCurrentSample > FLAGS_samples) { | |
174 this->printStats(); | |
175 fTSM.nextBenchmark(canvas, fBenchmark); | |
176 fCurrentSample = 0; | |
177 fBenchmark.reset(nullptr); | |
178 } else { | |
179 fHasBeenReset = true; | |
180 } | |
181 break; | |
182 } | |
183 } | 135 } |
184 | 136 |
185 bool VisualLightweightBenchModule::onHandleChar(SkUnichar c) { | 137 bool VisualLightweightBenchModule::onHandleChar(SkUnichar c) { |
186 return true; | 138 return true; |
187 } | 139 } |
OLD | NEW |