Add a json_perftest_decodebench program
The existing //base/json/json_perftest.cc, run automatically as part of
continuous integration, benchmarks synthetic JSON data. This program,
run manually, benchmarks real data (e.g. from a web crawl, passed as
command line arguments). Both are useful.
----
This is a re-spin of crrev.com/c/2154626 which failed to compile on
Windows, because the base::CommandLine constructor took a wchar_t*
instead of a char*. The fix was essentially to replace
base::CommandLine command_line(argc, argv);
with
base::CommandLine::Init(argc, argv);
base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
and replace printf(etc, s.c_str()) with cout.
Bug: 1069271
Cq-Include-Trybots: chromium/try:win_x64_archive
Change-Id: Ib932e575fea46358f064f334847a598e439e4927
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2169538
Commit-Queue: Nigel Tao <[email protected]>
Reviewed-by: Nico Weber <[email protected]>
Cr-Commit-Position: refs/heads/master@{#763665}
diff --git a/base/json/json_perftest_decodebench.cc b/base/json/json_perftest_decodebench.cc
new file mode 100644
index 0000000..e0f265d
--- /dev/null
+++ b/base/json/json_perftest_decodebench.cc
@@ -0,0 +1,98 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This program measures the time taken to decode the given JSON files (the
+// command line arguments). It is for manual benchmarking.
+//
+// Usage:
+// $ ninja -C out/foobar json_perftest_decodebench
+// $ out/foobar/json_perftest_decodebench -a -n=10 the/path/to/your/*.json
+//
+// The -n=10 switch controls the number of iterations. It defaults to 1.
+//
+// The -a switch means to print 1 non-comment line per input file (the average
+// iteration time). Without this switch (the default), it prints n non-comment
+// lines per input file (individual iteration times). For a single input file,
+// building and running this program before and after a particular commit can
+// work well with the 'ministat' tool: https://github.com/thorduri/ministat
+
+#include <inttypes.h>
+#include <iomanip>
+#include <iostream>
+
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/json/json_reader.h"
+#include "base/time/time.h"
+
+int main(int argc, char* argv[]) {
+ if (!base::ThreadTicks::IsSupported()) {
+ std::cout << "# base::ThreadTicks is not supported\n";
+ return EXIT_FAILURE;
+ }
+ base::ThreadTicks::WaitUntilInitialized();
+
+ base::CommandLine::Init(argc, argv);
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ bool average = command_line->HasSwitch("a");
+ int iterations = 1;
+ std::string iterations_str = command_line->GetSwitchValueASCII("n");
+ if (!iterations_str.empty()) {
+ iterations = atoi(iterations_str.c_str());
+ if (iterations < 1) {
+ std::cout << "# invalid -n command line switch\n";
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (average) {
+ std::cout << "# Microseconds (μs), n=" << iterations << ", averaged"
+ << std::endl;
+ } else {
+ std::cout << "# Microseconds (μs), n=" << iterations << std::endl;
+ }
+ for (const auto& filename : command_line->GetArgs()) {
+ std::string src;
+ if (!base::ReadFileToString(base::FilePath(filename), &src)) {
+ std::cout << "# could not read " << filename << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ int64_t total_time = 0;
+ std::string error_message;
+ for (int i = 0; i < iterations; ++i) {
+ auto start = base::ThreadTicks::Now();
+ auto v = base::JSONReader::ReadAndReturnValueWithError(src);
+ auto end = base::ThreadTicks::Now();
+ int64_t iteration_time = (end - start).InMicroseconds();
+ total_time += iteration_time;
+
+ if (i == 0) {
+ if (average) {
+ error_message = std::move(v.error_message);
+ } else {
+ std::cout << "# " << filename;
+ if (!v.error_message.empty()) {
+ std::cout << ": " << v.error_message;
+ }
+ std::cout << std::endl;
+ }
+ }
+
+ if (!average) {
+ std::cout << iteration_time << std::endl;
+ }
+ }
+
+ if (average) {
+ int64_t average_time = total_time / iterations;
+ std::cout << std::setw(12) << average_time << "\t# " << filename;
+ if (!error_message.empty()) {
+ std::cout << ": " << error_message;
+ }
+ std::cout << std::endl;
+ }
+ }
+ return EXIT_SUCCESS;
+}