OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 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 <ctype.h> | 8 #include <ctype.h> |
9 | 9 |
10 #include "nanobench.h" | 10 #include "nanobench.h" |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
95 bool Target::init(SkImageInfo info, Benchmark* bench) { | 95 bool Target::init(SkImageInfo info, Benchmark* bench) { |
96 if (Benchmark::kRaster_Backend == config.backend) { | 96 if (Benchmark::kRaster_Backend == config.backend) { |
97 this->surface.reset(SkSurface::NewRaster(info)); | 97 this->surface.reset(SkSurface::NewRaster(info)); |
98 if (!this->surface.get()) { | 98 if (!this->surface.get()) { |
99 return false; | 99 return false; |
100 } | 100 } |
101 } | 101 } |
102 return true; | 102 return true; |
103 } | 103 } |
104 bool Target::capturePixels(SkBitmap* bmp) { | 104 bool Target::capturePixels(SkBitmap* bmp) { |
105 if (!this->surface.get()) { | 105 SkCanvas* canvas = this->getCanvas(); |
106 return false; | |
107 } | |
108 SkCanvas* canvas = this->surface->getCanvas(); | |
109 if (!canvas) { | 106 if (!canvas) { |
110 return false; | 107 return false; |
111 } | 108 } |
112 bmp->setInfo(canvas->imageInfo()); | 109 bmp->setInfo(canvas->imageInfo()); |
113 if (!canvas->readPixels(bmp, 0, 0)) { | 110 if (!canvas->readPixels(bmp, 0, 0)) { |
114 SkDebugf("Can't read canvas pixels.\n"); | 111 SkDebugf("Can't read canvas pixels.\n"); |
115 return false; | 112 return false; |
116 } | 113 } |
117 return true; | 114 return true; |
118 } | 115 } |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
161 SK_GL_RET(*this->gl, version, GetString(GR_GL_VENDOR)); | 158 SK_GL_RET(*this->gl, version, GetString(GR_GL_VENDOR)); |
162 log->configOption("GL_VENDOR", (const char*) version); | 159 log->configOption("GL_VENDOR", (const char*) version); |
163 | 160 |
164 SK_GL_RET(*this->gl, version, GetString(GR_GL_SHADING_LANGUAGE_VERSION))
; | 161 SK_GL_RET(*this->gl, version, GetString(GR_GL_SHADING_LANGUAGE_VERSION))
; |
165 log->configOption("GL_SHADING_LANGUAGE_VERSION", (const char*) version); | 162 log->configOption("GL_SHADING_LANGUAGE_VERSION", (const char*) version); |
166 } | 163 } |
167 }; | 164 }; |
168 | 165 |
169 #endif | 166 #endif |
170 | 167 |
171 static double time(int loops, Benchmark* bench, SkCanvas* canvas, Target* target
) { | 168 static double time(int loops, Benchmark* bench, Target* target) { |
| 169 SkCanvas* canvas = target->getCanvas(); |
172 if (canvas) { | 170 if (canvas) { |
173 canvas->clear(SK_ColorWHITE); | 171 canvas->clear(SK_ColorWHITE); |
174 } | 172 } |
175 WallTimer timer; | 173 WallTimer timer; |
176 timer.start(); | 174 timer.start(); |
177 if (target) { | 175 canvas = target->beginTiming(canvas); |
178 canvas = target->beginTiming(canvas); | 176 bench->draw(loops, canvas); |
179 } | |
180 if (bench) { | |
181 bench->draw(loops, canvas); | |
182 } | |
183 if (canvas) { | 177 if (canvas) { |
184 canvas->flush(); | 178 canvas->flush(); |
185 } | 179 } |
186 if (target) { | 180 target->endTiming(); |
187 target->endTiming(); | |
188 } | |
189 timer.end(); | 181 timer.end(); |
190 return timer.fWall; | 182 return timer.fWall; |
191 } | 183 } |
192 | 184 |
193 static double estimate_timer_overhead() { | 185 static double estimate_timer_overhead() { |
194 double overhead = 0; | 186 double overhead = 0; |
195 for (int i = 0; i < FLAGS_overheadLoops; i++) { | 187 for (int i = 0; i < FLAGS_overheadLoops; i++) { |
196 overhead += time(1, NULL, NULL, NULL); | 188 WallTimer timer; |
| 189 timer.start(); |
| 190 timer.end(); |
| 191 overhead += timer.fWall; |
197 } | 192 } |
198 return overhead / FLAGS_overheadLoops; | 193 return overhead / FLAGS_overheadLoops; |
199 } | 194 } |
200 | 195 |
201 static int detect_forever_loops(int loops) { | 196 static int detect_forever_loops(int loops) { |
202 // look for a magic run-forever value | 197 // look for a magic run-forever value |
203 if (loops < 0) { | 198 if (loops < 0) { |
204 loops = SK_MaxS32; | 199 loops = SK_MaxS32; |
205 } | 200 } |
206 return loops; | 201 return loops; |
(...skipping 10 matching lines...) Expand all Loading... |
217 return FLAGS_maxLoops; | 212 return FLAGS_maxLoops; |
218 } | 213 } |
219 return loops; | 214 return loops; |
220 } | 215 } |
221 | 216 |
222 static bool write_canvas_png(Target* target, const SkString& filename) { | 217 static bool write_canvas_png(Target* target, const SkString& filename) { |
223 | 218 |
224 if (filename.isEmpty()) { | 219 if (filename.isEmpty()) { |
225 return false; | 220 return false; |
226 } | 221 } |
227 if (target->surface.get() && target->surface->getCanvas() && | 222 if (target->getCanvas() && |
228 kUnknown_SkColorType == target->surface->getCanvas()->imageInfo().colorT
ype()) { | 223 kUnknown_SkColorType == target->getCanvas()->imageInfo().colorType()) { |
229 return false; | 224 return false; |
230 } | 225 } |
231 | 226 |
232 SkBitmap bmp; | 227 SkBitmap bmp; |
233 | 228 |
234 if (!target->capturePixels(&bmp)) { | 229 if (!target->capturePixels(&bmp)) { |
235 return false; | 230 return false; |
236 } | 231 } |
237 | 232 |
238 SkString dir = SkOSPath::Dirname(filename.c_str()); | 233 SkString dir = SkOSPath::Dirname(filename.c_str()); |
239 if (!sk_mkdir(dir.c_str())) { | 234 if (!sk_mkdir(dir.c_str())) { |
240 SkDebugf("Can't make dir %s.\n", dir.c_str()); | 235 SkDebugf("Can't make dir %s.\n", dir.c_str()); |
241 return false; | 236 return false; |
242 } | 237 } |
243 SkFILEWStream stream(filename.c_str()); | 238 SkFILEWStream stream(filename.c_str()); |
244 if (!stream.isValid()) { | 239 if (!stream.isValid()) { |
245 SkDebugf("Can't write %s.\n", filename.c_str()); | 240 SkDebugf("Can't write %s.\n", filename.c_str()); |
246 return false; | 241 return false; |
247 } | 242 } |
248 if (!SkImageEncoder::EncodeStream(&stream, bmp, SkImageEncoder::kPNG_Type, 1
00)) { | 243 if (!SkImageEncoder::EncodeStream(&stream, bmp, SkImageEncoder::kPNG_Type, 1
00)) { |
249 SkDebugf("Can't encode a PNG.\n"); | 244 SkDebugf("Can't encode a PNG.\n"); |
250 return false; | 245 return false; |
251 } | 246 } |
252 return true; | 247 return true; |
253 } | 248 } |
254 | 249 |
255 static int kFailedLoops = -2; | 250 static int kFailedLoops = -2; |
256 static int cpu_bench(const double overhead, Benchmark* bench, SkCanvas* canvas,
double* samples) { | 251 static int cpu_bench(const double overhead, Target* target, Benchmark* bench, do
uble* samples) { |
257 // First figure out approximately how many loops of bench it takes to make o
verhead negligible. | 252 // First figure out approximately how many loops of bench it takes to make o
verhead negligible. |
258 double bench_plus_overhead = 0.0; | 253 double bench_plus_overhead = 0.0; |
259 int round = 0; | 254 int round = 0; |
260 if (kAutoTuneLoops == FLAGS_loops) { | 255 if (kAutoTuneLoops == FLAGS_loops) { |
261 while (bench_plus_overhead < overhead) { | 256 while (bench_plus_overhead < overhead) { |
262 if (round++ == FLAGS_maxCalibrationAttempts) { | 257 if (round++ == FLAGS_maxCalibrationAttempts) { |
263 SkDebugf("WARNING: Can't estimate loops for %s (%s vs. %s); skip
ping.\n", | 258 SkDebugf("WARNING: Can't estimate loops for %s (%s vs. %s); skip
ping.\n", |
264 bench->getUniqueName(), HUMANIZE(bench_plus_overhead),
HUMANIZE(overhead)); | 259 bench->getUniqueName(), HUMANIZE(bench_plus_overhead),
HUMANIZE(overhead)); |
265 return kFailedLoops; | 260 return kFailedLoops; |
266 } | 261 } |
267 bench_plus_overhead = time(1, bench, canvas, NULL); | 262 bench_plus_overhead = time(1, bench, target); |
268 } | 263 } |
269 } | 264 } |
270 | 265 |
271 // Later we'll just start and stop the timer once but loop N times. | 266 // Later we'll just start and stop the timer once but loop N times. |
272 // We'll pick N to make timer overhead negligible: | 267 // We'll pick N to make timer overhead negligible: |
273 // | 268 // |
274 // overhead | 269 // overhead |
275 // ------------------------- < FLAGS_overheadGoal | 270 // ------------------------- < FLAGS_overheadGoal |
276 // overhead + N * Bench Time | 271 // overhead + N * Bench Time |
277 // | 272 // |
(...skipping 10 matching lines...) Expand all Loading... |
288 if (kAutoTuneLoops == loops) { | 283 if (kAutoTuneLoops == loops) { |
289 const double numer = overhead / FLAGS_overheadGoal - overhead; | 284 const double numer = overhead / FLAGS_overheadGoal - overhead; |
290 const double denom = bench_plus_overhead - overhead; | 285 const double denom = bench_plus_overhead - overhead; |
291 loops = (int)ceil(numer / denom); | 286 loops = (int)ceil(numer / denom); |
292 loops = clamp_loops(loops); | 287 loops = clamp_loops(loops); |
293 } else { | 288 } else { |
294 loops = detect_forever_loops(loops); | 289 loops = detect_forever_loops(loops); |
295 } | 290 } |
296 | 291 |
297 for (int i = 0; i < FLAGS_samples; i++) { | 292 for (int i = 0; i < FLAGS_samples; i++) { |
298 samples[i] = time(loops, bench, canvas, NULL) / loops; | 293 samples[i] = time(loops, bench, target) / loops; |
299 } | 294 } |
300 return loops; | 295 return loops; |
301 } | 296 } |
302 | 297 |
303 static int gpu_bench(Target* target, | 298 static int gpu_bench(Target* target, |
304 Benchmark* bench, | 299 Benchmark* bench, |
305 SkCanvas* canvas, | |
306 double* samples) { | 300 double* samples) { |
307 // First, figure out how many loops it'll take to get a frame up to FLAGS_gp
uMs. | 301 // First, figure out how many loops it'll take to get a frame up to FLAGS_gp
uMs. |
308 int loops = FLAGS_loops; | 302 int loops = FLAGS_loops; |
309 if (kAutoTuneLoops == loops) { | 303 if (kAutoTuneLoops == loops) { |
310 loops = 1; | 304 loops = 1; |
311 double elapsed = 0; | 305 double elapsed = 0; |
312 do { | 306 do { |
313 if (1<<30 == loops) { | 307 if (1<<30 == loops) { |
314 // We're about to wrap. Something's wrong with the bench. | 308 // We're about to wrap. Something's wrong with the bench. |
315 loops = 0; | 309 loops = 0; |
316 break; | 310 break; |
317 } | 311 } |
318 loops *= 2; | 312 loops *= 2; |
319 // If the GPU lets frames lag at all, we need to make sure we're tim
ing | 313 // If the GPU lets frames lag at all, we need to make sure we're tim
ing |
320 // _this_ round, not still timing last round. We force this by loop
ing | 314 // _this_ round, not still timing last round. We force this by loop
ing |
321 // more times than any reasonable GPU will allow frames to lag. | 315 // more times than any reasonable GPU will allow frames to lag. |
322 for (int i = 0; i < FLAGS_gpuFrameLag; i++) { | 316 for (int i = 0; i < FLAGS_gpuFrameLag; i++) { |
323 elapsed = time(loops, bench, canvas, target); | 317 elapsed = time(loops, bench, target); |
324 } | 318 } |
325 } while (elapsed < FLAGS_gpuMs); | 319 } while (elapsed < FLAGS_gpuMs); |
326 | 320 |
327 // We've overshot at least a little. Scale back linearly. | 321 // We've overshot at least a little. Scale back linearly. |
328 loops = (int)ceil(loops * FLAGS_gpuMs / elapsed); | 322 loops = (int)ceil(loops * FLAGS_gpuMs / elapsed); |
329 loops = clamp_loops(loops); | 323 loops = clamp_loops(loops); |
330 | 324 |
331 // Make sure we're not still timing our calibration. | 325 // Make sure we're not still timing our calibration. |
332 target->fence(); | 326 target->fence(); |
333 } else { | 327 } else { |
334 loops = detect_forever_loops(loops); | 328 loops = detect_forever_loops(loops); |
335 } | 329 } |
336 | 330 |
337 // Pretty much the same deal as the calibration: do some warmup to make | 331 // Pretty much the same deal as the calibration: do some warmup to make |
338 // sure we're timing steady-state pipelined frames. | 332 // sure we're timing steady-state pipelined frames. |
339 for (int i = 0; i < FLAGS_gpuFrameLag; i++) { | 333 for (int i = 0; i < FLAGS_gpuFrameLag; i++) { |
340 time(loops, bench, canvas, target); | 334 time(loops, bench, target); |
341 } | 335 } |
342 | 336 |
343 // Now, actually do the timing! | 337 // Now, actually do the timing! |
344 for (int i = 0; i < FLAGS_samples; i++) { | 338 for (int i = 0; i < FLAGS_samples; i++) { |
345 samples[i] = time(loops, bench, canvas, target) / loops; | 339 samples[i] = time(loops, bench, target) / loops; |
346 } | 340 } |
347 | 341 |
348 return loops; | 342 return loops; |
349 } | 343 } |
350 | 344 |
351 static SkString to_lower(const char* str) { | 345 static SkString to_lower(const char* str) { |
352 SkString lower(str); | 346 SkString lower(str); |
353 for (size_t i = 0; i < lower.size(); i++) { | 347 for (size_t i = 0; i < lower.size(); i++) { |
354 lower[i] = tolower(lower[i]); | 348 lower[i] = tolower(lower[i]); |
355 } | 349 } |
(...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
832 | 826 |
833 SkTDArray<Target*> targets; | 827 SkTDArray<Target*> targets; |
834 create_targets(&targets, bench.get(), configs); | 828 create_targets(&targets, bench.get(), configs); |
835 | 829 |
836 if (!targets.isEmpty()) { | 830 if (!targets.isEmpty()) { |
837 log->bench(bench->getUniqueName(), bench->getSize().fX, bench->getSi
ze().fY); | 831 log->bench(bench->getUniqueName(), bench->getSize().fX, bench->getSi
ze().fY); |
838 bench->preDraw(); | 832 bench->preDraw(); |
839 } | 833 } |
840 for (int j = 0; j < targets.count(); j++) { | 834 for (int j = 0; j < targets.count(); j++) { |
841 // During HWUI output this canvas may be NULL. | 835 // During HWUI output this canvas may be NULL. |
842 SkCanvas* canvas = targets[j]->surface.get() ? targets[j]->surface->
getCanvas() : NULL; | 836 SkCanvas* canvas = targets[j]->getCanvas(); |
843 const char* config = targets[j]->config.name; | 837 const char* config = targets[j]->config.name; |
844 | 838 |
845 targets[j]->setup(); | 839 targets[j]->setup(); |
846 bench->perCanvasPreDraw(canvas); | 840 bench->perCanvasPreDraw(canvas); |
847 | 841 |
848 const int loops = | 842 const int loops = |
849 targets[j]->needsFrameTiming() | 843 targets[j]->needsFrameTiming() |
850 ? gpu_bench(targets[j], bench.get(), canvas, samples.get()) | 844 ? gpu_bench(targets[j], bench.get(), samples.get()) |
851 : cpu_bench(overhead, bench.get(), canvas, samples.get()); | 845 : cpu_bench(overhead, targets[j], bench.get(), samples.get()); |
852 | 846 |
853 bench->perCanvasPostDraw(canvas); | 847 bench->perCanvasPostDraw(canvas); |
854 | 848 |
855 if (Benchmark::kNonRendering_Backend != targets[j]->config.backend &
& | 849 if (Benchmark::kNonRendering_Backend != targets[j]->config.backend &
& |
856 !FLAGS_writePath.isEmpty() && FLAGS_writePath[0]) { | 850 !FLAGS_writePath.isEmpty() && FLAGS_writePath[0]) { |
857 SkString pngFilename = SkOSPath::Join(FLAGS_writePath[0], config
); | 851 SkString pngFilename = SkOSPath::Join(FLAGS_writePath[0], config
); |
858 pngFilename = SkOSPath::Join(pngFilename.c_str(), bench->getUniq
ueName()); | 852 pngFilename = SkOSPath::Join(pngFilename.c_str(), bench->getUniq
ueName()); |
859 pngFilename.append(".png"); | 853 pngFilename.append(".png"); |
860 write_canvas_png(targets[j], pngFilename); | 854 write_canvas_png(targets[j], pngFilename); |
861 } | 855 } |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
940 | 934 |
941 return 0; | 935 return 0; |
942 } | 936 } |
943 | 937 |
944 #if !defined SK_BUILD_FOR_IOS | 938 #if !defined SK_BUILD_FOR_IOS |
945 int main(int argc, char** argv) { | 939 int main(int argc, char** argv) { |
946 SkCommandLineFlags::Parse(argc, argv); | 940 SkCommandLineFlags::Parse(argc, argv); |
947 return nanobench_main(); | 941 return nanobench_main(); |
948 } | 942 } |
949 #endif | 943 #endif |
OLD | NEW |