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

Side by Side Diff: bench/nanobench.cpp

Issue 1204153002: Add samplingTime mode to nanobench (Closed) Base URL: https://skia.googlesource.com/skia.git@upload_loopSKP
Patch Set: copyright Created 5 years, 6 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 | « no previous file | tools/Stats.h » ('j') | 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 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 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
48 #include "gl/GrGLDefines.h" 48 #include "gl/GrGLDefines.h"
49 #include "GrCaps.h" 49 #include "GrCaps.h"
50 #include "GrContextFactory.h" 50 #include "GrContextFactory.h"
51 SkAutoTDelete<GrContextFactory> gGrFactory; 51 SkAutoTDelete<GrContextFactory> gGrFactory;
52 #endif 52 #endif
53 53
54 struct GrContextOptions; 54 struct GrContextOptions;
55 55
56 __SK_FORCE_IMAGE_DECODER_LINKING; 56 __SK_FORCE_IMAGE_DECODER_LINKING;
57 57
58 static const int kTimedSampling = 0;
59
58 static const int kAutoTuneLoops = 0; 60 static const int kAutoTuneLoops = 0;
59 61
60 static const int kDefaultLoops = 62 static const int kDefaultLoops =
61 #ifdef SK_DEBUG 63 #ifdef SK_DEBUG
62 1; 64 1;
63 #else 65 #else
64 kAutoTuneLoops; 66 kAutoTuneLoops;
65 #endif 67 #endif
66 68
67 static SkString loops_help_txt() { 69 static SkString loops_help_txt() {
68 SkString help; 70 SkString help;
69 help.printf("Number of times to run each bench. Set this to %d to auto-" 71 help.printf("Number of times to run each bench. Set this to %d to auto-"
70 "tune for each bench. Timings are only reported when auto-tuning .", 72 "tune for each bench. Timings are only reported when auto-tuning .",
71 kAutoTuneLoops); 73 kAutoTuneLoops);
72 return help; 74 return help;
73 } 75 }
74 76
77 static SkString to_string(int n) {
78 SkString str;
79 str.appendS32(n);
80 return str;
81 }
82
75 DEFINE_int32(loops, kDefaultLoops, loops_help_txt().c_str()); 83 DEFINE_int32(loops, kDefaultLoops, loops_help_txt().c_str());
76 84
77 DEFINE_int32(samples, 10, "Number of samples to measure for each bench."); 85 DEFINE_int32(samples, 10, "Number of samples to measure for each bench.");
86 DEFINE_string(samplingTime, "0", "Amount of time to run each bench. Takes preced ence over samples."
87 "Must be \"0\", \"%%lfs\", or \"%%lfms\"");
78 DEFINE_int32(overheadLoops, 100000, "Loops to estimate timer overhead."); 88 DEFINE_int32(overheadLoops, 100000, "Loops to estimate timer overhead.");
79 DEFINE_double(overheadGoal, 0.0001, 89 DEFINE_double(overheadGoal, 0.0001,
80 "Loop until timer overhead is at most this fraction of our measurm ents."); 90 "Loop until timer overhead is at most this fraction of our measurm ents.");
81 DEFINE_double(gpuMs, 5, "Target bench time in millseconds for GPU."); 91 DEFINE_double(gpuMs, 5, "Target bench time in millseconds for GPU.");
82 DEFINE_int32(gpuFrameLag, 5, "If unknown, estimated maximum number of frames GPU allows to lag."); 92 DEFINE_int32(gpuFrameLag, 5, "If unknown, estimated maximum number of frames GPU allows to lag.");
83 DEFINE_bool(gpuCompressAlphaMasks, false, "Compress masks generated from falling back to " 93 DEFINE_bool(gpuCompressAlphaMasks, false, "Compress masks generated from falling back to "
84 "software path rendering."); 94 "software path rendering.");
85 95
86 DEFINE_string(outResultsFile, "", "If given, write results here as JSON."); 96 DEFINE_string(outResultsFile, "", "If given, write results here as JSON.");
87 DEFINE_int32(maxCalibrationAttempts, 3, 97 DEFINE_int32(maxCalibrationAttempts, 3,
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 return false; 272 return false;
263 } 273 }
264 if (!SkImageEncoder::EncodeStream(&stream, bmp, SkImageEncoder::kPNG_Type, 1 00)) { 274 if (!SkImageEncoder::EncodeStream(&stream, bmp, SkImageEncoder::kPNG_Type, 1 00)) {
265 SkDebugf("Can't encode a PNG.\n"); 275 SkDebugf("Can't encode a PNG.\n");
266 return false; 276 return false;
267 } 277 }
268 return true; 278 return true;
269 } 279 }
270 280
271 static int kFailedLoops = -2; 281 static int kFailedLoops = -2;
272 static int cpu_bench(const double overhead, Target* target, Benchmark* bench, do uble* samples) { 282 static int setup_cpu_bench(const double overhead, Target* target, Benchmark* ben ch) {
273 // First figure out approximately how many loops of bench it takes to make o verhead negligible. 283 // First figure out approximately how many loops of bench it takes to make o verhead negligible.
274 double bench_plus_overhead = 0.0; 284 double bench_plus_overhead = 0.0;
275 int round = 0; 285 int round = 0;
276 int loops = bench->calculateLoops(FLAGS_loops); 286 int loops = bench->calculateLoops(FLAGS_loops);
277 if (kAutoTuneLoops == loops) { 287 if (kAutoTuneLoops == loops) {
278 while (bench_plus_overhead < overhead) { 288 while (bench_plus_overhead < overhead) {
279 if (round++ == FLAGS_maxCalibrationAttempts) { 289 if (round++ == FLAGS_maxCalibrationAttempts) {
280 SkDebugf("WARNING: Can't estimate loops for %s (%s vs. %s); skip ping.\n", 290 SkDebugf("WARNING: Can't estimate loops for %s (%s vs. %s); skip ping.\n",
281 bench->getUniqueName(), HUMANIZE(bench_plus_overhead), HUMANIZE(overhead)); 291 bench->getUniqueName(), HUMANIZE(bench_plus_overhead), HUMANIZE(overhead));
282 return kFailedLoops; 292 return kFailedLoops;
(...skipping 20 matching lines...) Expand all
303 // Luckily, this also works well in practice. :) 313 // Luckily, this also works well in practice. :)
304 if (kAutoTuneLoops == loops) { 314 if (kAutoTuneLoops == loops) {
305 const double numer = overhead / FLAGS_overheadGoal - overhead; 315 const double numer = overhead / FLAGS_overheadGoal - overhead;
306 const double denom = bench_plus_overhead - overhead; 316 const double denom = bench_plus_overhead - overhead;
307 loops = (int)ceil(numer / denom); 317 loops = (int)ceil(numer / denom);
308 loops = clamp_loops(loops); 318 loops = clamp_loops(loops);
309 } else { 319 } else {
310 loops = detect_forever_loops(loops); 320 loops = detect_forever_loops(loops);
311 } 321 }
312 322
313 for (int i = 0; i < FLAGS_samples; i++) {
314 samples[i] = time(loops, bench, target) / loops;
315 }
316 return loops; 323 return loops;
317 } 324 }
318 325
319 static int gpu_bench(Target* target, 326 static int setup_gpu_bench(Target* target, Benchmark* bench, int maxGpuFrameLag) {
320 Benchmark* bench,
321 double* samples,
322 int maxGpuFrameLag) {
323 // First, figure out how many loops it'll take to get a frame up to FLAGS_gp uMs. 327 // First, figure out how many loops it'll take to get a frame up to FLAGS_gp uMs.
324 int loops = bench->calculateLoops(FLAGS_loops); 328 int loops = bench->calculateLoops(FLAGS_loops);
325 if (kAutoTuneLoops == loops) { 329 if (kAutoTuneLoops == loops) {
326 loops = 1; 330 loops = 1;
327 double elapsed = 0; 331 double elapsed = 0;
328 do { 332 do {
329 if (1<<30 == loops) { 333 if (1<<30 == loops) {
330 // We're about to wrap. Something's wrong with the bench. 334 // We're about to wrap. Something's wrong with the bench.
331 loops = 0; 335 loops = 0;
332 break; 336 break;
(...skipping 15 matching lines...) Expand all
348 } else { 352 } else {
349 loops = detect_forever_loops(loops); 353 loops = detect_forever_loops(loops);
350 } 354 }
351 355
352 // Pretty much the same deal as the calibration: do some warmup to make 356 // Pretty much the same deal as the calibration: do some warmup to make
353 // sure we're timing steady-state pipelined frames. 357 // sure we're timing steady-state pipelined frames.
354 for (int i = 0; i < maxGpuFrameLag - 1; i++) { 358 for (int i = 0; i < maxGpuFrameLag - 1; i++) {
355 time(loops, bench, target); 359 time(loops, bench, target);
356 } 360 }
357 361
358 // Now, actually do the timing!
359 for (int i = 0; i < FLAGS_samples; i++) {
360 samples[i] = time(loops, bench, target) / loops;
361 }
362
363 return loops; 362 return loops;
364 } 363 }
365 364
366 static SkString to_lower(const char* str) { 365 static SkString to_lower(const char* str) {
367 SkString lower(str); 366 SkString lower(str);
368 for (size_t i = 0; i < lower.size(); i++) { 367 for (size_t i = 0; i < lower.size(); i++) {
369 lower[i] = tolower(lower[i]); 368 lower[i] = tolower(lower[i]);
370 } 369 }
371 return lower; 370 return lower;
372 } 371 }
(...skipping 566 matching lines...) Expand 10 before | Expand all | Expand 10 after
939 #if SK_SUPPORT_GPU 938 #if SK_SUPPORT_GPU
940 GrContextOptions grContextOpts; 939 GrContextOptions grContextOpts;
941 grContextOpts.fDrawPathToCompressedTexture = FLAGS_gpuCompressAlphaMasks; 940 grContextOpts.fDrawPathToCompressedTexture = FLAGS_gpuCompressAlphaMasks;
942 gGrFactory.reset(SkNEW_ARGS(GrContextFactory, (grContextOpts))); 941 gGrFactory.reset(SkNEW_ARGS(GrContextFactory, (grContextOpts)));
943 #endif 942 #endif
944 943
945 if (FLAGS_veryVerbose) { 944 if (FLAGS_veryVerbose) {
946 FLAGS_verbose = true; 945 FLAGS_verbose = true;
947 } 946 }
948 947
948 double samplingTimeMs = 0;
949 if (0 != strcmp("0", FLAGS_samplingTime[0])) {
950 SkSTArray<8, char> timeUnit;
951 timeUnit.push_back_n(static_cast<int>(strlen(FLAGS_samplingTime[0])) + 1 );
952 if (2 != sscanf(FLAGS_samplingTime[0], "%lf%s", &samplingTimeMs, timeUni t.begin()) ||
953 (0 != strcmp("s", timeUnit.begin()) && 0 != strcmp("ms", timeUnit.be gin()))) {
954 SkDebugf("Invalid --samplingTime \"%s\". Must be \"0\", \"%%lfs\", o r \"%%lfms\"\n",
955 FLAGS_samplingTime[0]);
956 exit(0);
957 }
958 if (0 == strcmp("s", timeUnit.begin())) {
959 samplingTimeMs *= 1000;
960 }
961 if (samplingTimeMs) {
962 FLAGS_samples = kTimedSampling;
963 }
964 }
965
949 if (kAutoTuneLoops != FLAGS_loops) { 966 if (kAutoTuneLoops != FLAGS_loops) {
950 FLAGS_samples = 1; 967 FLAGS_samples = 1;
951 FLAGS_gpuFrameLag = 0; 968 FLAGS_gpuFrameLag = 0;
952 } 969 }
953 970
954 if (!FLAGS_writePath.isEmpty()) { 971 if (!FLAGS_writePath.isEmpty()) {
955 SkDebugf("Writing files to %s.\n", FLAGS_writePath[0]); 972 SkDebugf("Writing files to %s.\n", FLAGS_writePath[0]);
956 if (!sk_mkdir(FLAGS_writePath[0])) { 973 if (!sk_mkdir(FLAGS_writePath[0])) {
957 SkDebugf("Could not create %s. Files won't be written.\n", FLAGS_wri tePath[0]); 974 SkDebugf("Could not create %s. Files won't be written.\n", FLAGS_wri tePath[0]);
958 FLAGS_writePath.set(0, NULL); 975 FLAGS_writePath.set(0, NULL);
(...skipping 17 matching lines...) Expand all
976 SkDebugf("ERROR: --key must be passed with an even number of arguments.\ n"); 993 SkDebugf("ERROR: --key must be passed with an even number of arguments.\ n");
977 return 1; 994 return 1;
978 } 995 }
979 for (int i = 1; i < FLAGS_key.count(); i += 2) { 996 for (int i = 1; i < FLAGS_key.count(); i += 2) {
980 log->key(FLAGS_key[i-1], FLAGS_key[i]); 997 log->key(FLAGS_key[i-1], FLAGS_key[i]);
981 } 998 }
982 999
983 const double overhead = estimate_timer_overhead(); 1000 const double overhead = estimate_timer_overhead();
984 SkDebugf("Timer overhead: %s\n", HUMANIZE(overhead)); 1001 SkDebugf("Timer overhead: %s\n", HUMANIZE(overhead));
985 1002
986 SkAutoTMalloc<double> samples(FLAGS_samples); 1003 SkTArray<double> samples;
987 1004
988 if (kAutoTuneLoops != FLAGS_loops) { 1005 if (kAutoTuneLoops != FLAGS_loops) {
989 SkDebugf("Fixed number of loops; times would only be misleading so we wo n't print them.\n"); 1006 SkDebugf("Fixed number of loops; times would only be misleading so we wo n't print them.\n");
990 } else if (FLAGS_verbose) { 1007 } else if (FLAGS_verbose) {
991 // No header. 1008 // No header.
992 } else if (FLAGS_quiet) { 1009 } else if (FLAGS_quiet) {
993 SkDebugf("median\tbench\tconfig\n"); 1010 SkDebugf("median\tbench\tconfig\n");
1011 } else if (kTimedSampling == FLAGS_samples) {
1012 SkDebugf("curr/maxrss\tloops\tmin\tmedian\tmean\tmax\tstddev\tsamples\tc onfig\tbench\n");
994 } else { 1013 } else {
995 SkDebugf("curr/maxrss\tloops\tmin\tmedian\tmean\tmax\tstddev\t%-*s\tconf ig\tbench\n", 1014 SkDebugf("curr/maxrss\tloops\tmin\tmedian\tmean\tmax\tstddev\t%-*s\tconf ig\tbench\n",
996 FLAGS_samples, "samples"); 1015 FLAGS_samples, "samples");
997 } 1016 }
998 1017
999 SkTDArray<Config> configs; 1018 SkTDArray<Config> configs;
1000 create_configs(&configs); 1019 create_configs(&configs);
1001 1020
1002 int runs = 0; 1021 int runs = 0;
1003 BenchmarkStream benchStream; 1022 BenchmarkStream benchStream;
(...skipping 11 matching lines...) Expand all
1015 bench->preDraw(); 1034 bench->preDraw();
1016 } 1035 }
1017 for (int j = 0; j < targets.count(); j++) { 1036 for (int j = 0; j < targets.count(); j++) {
1018 // During HWUI output this canvas may be NULL. 1037 // During HWUI output this canvas may be NULL.
1019 SkCanvas* canvas = targets[j]->getCanvas(); 1038 SkCanvas* canvas = targets[j]->getCanvas();
1020 const char* config = targets[j]->config.name; 1039 const char* config = targets[j]->config.name;
1021 1040
1022 targets[j]->setup(); 1041 targets[j]->setup();
1023 bench->perCanvasPreDraw(canvas); 1042 bench->perCanvasPreDraw(canvas);
1024 1043
1025 int frameLag; 1044 int maxFrameLag;
1026 const int loops = 1045 const int loops = targets[j]->needsFrameTiming(&maxFrameLag)
1027 targets[j]->needsFrameTiming(&frameLag) 1046 ? setup_gpu_bench(targets[j], bench.get(), maxFrameLag)
1028 ? gpu_bench(targets[j], bench.get(), samples.get(), frameLag) 1047 : setup_cpu_bench(overhead, targets[j], bench.get());
1029 : cpu_bench(overhead, targets[j], bench.get(), samples.get()); 1048
1049 if (kTimedSampling != FLAGS_samples) {
1050 samples.reset(FLAGS_samples);
1051 for (int s = 0; s < FLAGS_samples; s++) {
1052 samples[s] = time(loops, bench, targets[j]) / loops;
1053 }
1054 } else if (samplingTimeMs) {
1055 samples.reset();
1056 if (FLAGS_verbose) {
1057 SkDebugf("Begin sampling %s for %ims\n",
1058 bench->getUniqueName(), static_cast<int>(samplingTi meMs));
1059 }
1060 WallTimer timer;
1061 timer.start();
1062 do {
1063 samples.push_back(time(loops, bench, targets[j]) / loops);
1064 timer.end();
1065 } while (timer.fWall < samplingTimeMs);
1066 }
1030 1067
1031 bench->perCanvasPostDraw(canvas); 1068 bench->perCanvasPostDraw(canvas);
1032 1069
1033 if (Benchmark::kNonRendering_Backend != targets[j]->config.backend & & 1070 if (Benchmark::kNonRendering_Backend != targets[j]->config.backend & &
1034 !FLAGS_writePath.isEmpty() && FLAGS_writePath[0]) { 1071 !FLAGS_writePath.isEmpty() && FLAGS_writePath[0]) {
1035 SkString pngFilename = SkOSPath::Join(FLAGS_writePath[0], config ); 1072 SkString pngFilename = SkOSPath::Join(FLAGS_writePath[0], config );
1036 pngFilename = SkOSPath::Join(pngFilename.c_str(), bench->getUniq ueName()); 1073 pngFilename = SkOSPath::Join(pngFilename.c_str(), bench->getUniq ueName());
1037 pngFilename.append(".png"); 1074 pngFilename.append(".png");
1038 write_canvas_png(targets[j], pngFilename); 1075 write_canvas_png(targets[j], pngFilename);
1039 } 1076 }
1040 1077
1041 if (kFailedLoops == loops) { 1078 if (kFailedLoops == loops) {
1042 // Can't be timed. A warning note has already been printed. 1079 // Can't be timed. A warning note has already been printed.
1043 continue; 1080 continue;
1044 } 1081 }
1045 1082
1046 Stats stats(samples.get(), FLAGS_samples); 1083 Stats stats(samples);
1047 log->config(config); 1084 log->config(config);
1048 log->configOption("name", bench->getName()); 1085 log->configOption("name", bench->getName());
1049 benchStream.fillCurrentOptions(log.get()); 1086 benchStream.fillCurrentOptions(log.get());
1050 targets[j]->fillOptions(log.get()); 1087 targets[j]->fillOptions(log.get());
1051 log->metric("min_ms", stats.min); 1088 log->metric("min_ms", stats.min);
1052 if (runs++ % FLAGS_flushEvery == 0) { 1089 if (runs++ % FLAGS_flushEvery == 0) {
1053 log->flush(); 1090 log->flush();
1054 } 1091 }
1055 1092
1056 if (kAutoTuneLoops != FLAGS_loops) { 1093 if (kAutoTuneLoops != FLAGS_loops) {
1057 if (targets.count() == 1) { 1094 if (targets.count() == 1) {
1058 config = ""; // Only print the config if we run the same ben ch on more than one. 1095 config = ""; // Only print the config if we run the same ben ch on more than one.
1059 } 1096 }
1060 SkDebugf("%4d/%-4dMB\t%s\t%s\n" 1097 SkDebugf("%4d/%-4dMB\t%s\t%s\n"
1061 , sk_tools::getCurrResidentSetSizeMB() 1098 , sk_tools::getCurrResidentSetSizeMB()
1062 , sk_tools::getMaxResidentSetSizeMB() 1099 , sk_tools::getMaxResidentSetSizeMB()
1063 , bench->getUniqueName() 1100 , bench->getUniqueName()
1064 , config); 1101 , config);
1065 } else if (FLAGS_verbose) { 1102 } else if (FLAGS_verbose) {
1066 for (int i = 0; i < FLAGS_samples; i++) { 1103 for (int i = 0; i < samples.count(); i++) {
1067 SkDebugf("%s ", HUMANIZE(samples[i])); 1104 SkDebugf("%s ", HUMANIZE(samples[i]));
1068 } 1105 }
1069 SkDebugf("%s\n", bench->getUniqueName()); 1106 SkDebugf("%s\n", bench->getUniqueName());
1070 } else if (FLAGS_quiet) { 1107 } else if (FLAGS_quiet) {
1071 if (targets.count() == 1) { 1108 if (targets.count() == 1) {
1072 config = ""; // Only print the config if we run the same ben ch on more than one. 1109 config = ""; // Only print the config if we run the same ben ch on more than one.
1073 } 1110 }
1074 SkDebugf("%s\t%s\t%s\n", HUMANIZE(stats.median), bench->getUniqu eName(), config); 1111 SkDebugf("%s\t%s\t%s\n", HUMANIZE(stats.median), bench->getUniqu eName(), config);
1075 } else { 1112 } else {
1076 const double stddev_percent = 100 * sqrt(stats.var) / stats.mean ; 1113 const double stddev_percent = 100 * sqrt(stats.var) / stats.mean ;
1077 SkDebugf("%4d/%-4dMB\t%d\t%s\t%s\t%s\t%s\t%.0f%%\t%s\t%s\t%s\n" 1114 SkDebugf("%4d/%-4dMB\t%d\t%s\t%s\t%s\t%s\t%.0f%%\t%s\t%s\t%s\n"
1078 , sk_tools::getCurrResidentSetSizeMB() 1115 , sk_tools::getCurrResidentSetSizeMB()
1079 , sk_tools::getMaxResidentSetSizeMB() 1116 , sk_tools::getMaxResidentSetSizeMB()
1080 , loops 1117 , loops
1081 , HUMANIZE(stats.min) 1118 , HUMANIZE(stats.min)
1082 , HUMANIZE(stats.median) 1119 , HUMANIZE(stats.median)
1083 , HUMANIZE(stats.mean) 1120 , HUMANIZE(stats.mean)
1084 , HUMANIZE(stats.max) 1121 , HUMANIZE(stats.max)
1085 , stddev_percent 1122 , stddev_percent
1086 , stats.plot.c_str() 1123 , kTimedSampling != FLAGS_samples ? stats.plot.c_str()
1124 : to_string(samples.co unt()).c_str()
1087 , config 1125 , config
1088 , bench->getUniqueName() 1126 , bench->getUniqueName()
1089 ); 1127 );
1090 } 1128 }
1091 #if SK_SUPPORT_GPU 1129 #if SK_SUPPORT_GPU
1092 if (FLAGS_gpuStats && 1130 if (FLAGS_gpuStats &&
1093 Benchmark::kGPU_Backend == targets[j]->config.backend) { 1131 Benchmark::kGPU_Backend == targets[j]->config.backend) {
1094 gGrFactory->get(targets[j]->config.ctxType)->printCacheStats(); 1132 gGrFactory->get(targets[j]->config.ctxType)->printCacheStats();
1095 gGrFactory->get(targets[j]->config.ctxType)->printGpuStats(); 1133 gGrFactory->get(targets[j]->config.ctxType)->printGpuStats();
1096 } 1134 }
(...skipping 23 matching lines...) Expand all
1120 1158
1121 return 0; 1159 return 0;
1122 } 1160 }
1123 1161
1124 #if !defined SK_BUILD_FOR_IOS 1162 #if !defined SK_BUILD_FOR_IOS
1125 int main(int argc, char** argv) { 1163 int main(int argc, char** argv) {
1126 SkCommandLineFlags::Parse(argc, argv); 1164 SkCommandLineFlags::Parse(argc, argv);
1127 return nanobench_main(); 1165 return nanobench_main();
1128 } 1166 }
1129 #endif 1167 #endif
OLDNEW
« no previous file with comments | « no previous file | tools/Stats.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698