|
10 | 10 | #include <iostream> // std::cerr
|
11 | 11 | #include <set> // std::set
|
12 | 12 | #include <string> // std::string
|
| 13 | +#include <cmath> // for sqrt |
13 | 14 |
|
14 | 15 | #include "command.h"
|
15 | 16 | #include "utils.h"
|
16 | 17 |
|
| 18 | +// parse unsigned int option, how many loop for benchmarking |
| 19 | +auto benchmark_loop( |
| 20 | + const std::map<std::string, std::vector<std::string>> &options) |
| 21 | + -> size_t { |
| 22 | + |
| 23 | + size_t loop = 1; |
| 24 | + |
| 25 | + if (options.contains("loop")) { |
| 26 | + std::stringstream sstream(options.at("loop").front()); |
| 27 | + sstream >> loop; |
| 28 | + } |
| 29 | + |
| 30 | + return loop; |
| 31 | +} |
| 32 | + |
17 | 33 | // TODO: Add a flag to emit output using the standard JSON Schema output format
|
18 | 34 | // TODO: Add a flag to collect annotations
|
19 | 35 | // TODO: Add a flag to take a pre-compiled schema as input
|
@@ -56,6 +72,7 @@ auto sourcemeta::jsonschema::cli::validate(
|
56 | 72 |
|
57 | 73 | const auto fast_mode{options.contains("f") || options.contains("fast")};
|
58 | 74 | const auto benchmark{options.contains("b") || options.contains("benchmark")};
|
| 75 | + const auto bench_loop{benchmark_loop(options)}; |
59 | 76 | const auto trace{options.contains("t") || options.contains("trace")};
|
60 | 77 |
|
61 | 78 | const sourcemeta::core::JSON bundled{
|
@@ -103,6 +120,7 @@ auto sourcemeta::jsonschema::cli::validate(
|
103 | 120 | const auto duration_us{
|
104 | 121 | std::chrono::duration_cast<std::chrono::microseconds>(
|
105 | 122 | timestamp_end - timestamp_start)};
|
| 123 | + |
106 | 124 | if (subresult) {
|
107 | 125 | std::cout << "took: " << duration_us.count() << "us\n";
|
108 | 126 | } else {
|
@@ -158,15 +176,43 @@ auto sourcemeta::jsonschema::cli::validate(
|
158 | 176 | sourcemeta::core::empty_weak_pointer, frame};
|
159 | 177 | bool subresult{true};
|
160 | 178 | if (benchmark) {
|
161 |
| - const auto timestamp_start{std::chrono::high_resolution_clock::now()}; |
162 |
| - subresult = evaluator.validate(schema_template, instance); |
163 |
| - const auto timestamp_end{std::chrono::high_resolution_clock::now()}; |
164 |
| - const auto duration_us{ |
165 |
| - std::chrono::duration_cast<std::chrono::microseconds>( |
166 |
| - timestamp_end - timestamp_start)}; |
167 |
| - if (subresult) { |
168 |
| - std::cout << "took: " << duration_us.count() << "us\n"; |
169 |
| - } else { |
| 179 | + double sum = 0.0, sum2 = 0.0, empty = 0.0; |
| 180 | + size_t count = 0; |
| 181 | + |
| 182 | + // overhead evaluation, if the compiler is kind enough not to optimize this out! |
| 183 | + for (auto i = bench_loop; i; i--) { |
| 184 | + const auto start{std::chrono::high_resolution_clock::now()}; |
| 185 | + count++; |
| 186 | + const auto end{std::chrono::high_resolution_clock::now()}; |
| 187 | + empty += (double) |
| 188 | + (std::chrono::duration_cast<std::chrono::microseconds>(end - start)).count(); |
| 189 | + } |
| 190 | + assert(count == bench_loop); |
| 191 | + empty /= (double) bench_loop; |
| 192 | + |
| 193 | + // execution time evaluation |
| 194 | + for (auto i = bench_loop; i; i--) { |
| 195 | + const auto start{std::chrono::high_resolution_clock::now()}; |
| 196 | + |
| 197 | + // force fast evaluation |
| 198 | + subresult = evaluator.validate(schema_template, instance); |
| 199 | + |
| 200 | + const auto end{std::chrono::high_resolution_clock::now()}; |
| 201 | + const auto delay = (double) (std::chrono::duration_cast< |
| 202 | + std::chrono::microseconds>(end - start)).count() - empty; |
| 203 | + |
| 204 | + sum += delay; |
| 205 | + sum2 += delay * delay; |
| 206 | + } |
| 207 | + |
| 208 | + // compute and show average execution time and standard deviation |
| 209 | + auto avg = sum / (double) bench_loop; |
| 210 | + auto stdev = sqrt(sum2 / (double) bench_loop - avg * avg); |
| 211 | + std::cout << std::fixed; |
| 212 | + std::cout.precision(3); |
| 213 | + std::cout << "took: " << avg << " +- " << stdev << " us (" << empty << ")\n"; |
| 214 | + |
| 215 | + if (!subresult) { |
170 | 216 | error << "error: Schema validation failure\n";
|
171 | 217 | result = false;
|
172 | 218 | }
|
|
0 commit comments