|
| 1 | +#include <chrono> |
| 2 | +#include <iostream> |
| 3 | +#include <string> |
| 4 | + |
| 5 | +#include "benchmark/benchmark.h" |
| 6 | + |
| 7 | +namespace { |
| 8 | + |
| 9 | +// Macro to create benchmark families with many arguments |
| 10 | +#define CREATE_BENCHMARK_FAMILY(name) \ |
| 11 | + void name(benchmark::State& state) { \ |
| 12 | + for (auto _ : state) {} \ |
| 13 | + } \ |
| 14 | + BENCHMARK(name)->DenseRange(0, 999, 1); |
| 15 | + |
| 16 | +// Create many benchmark families, each with 1000 instances (args 0-999) |
| 17 | +CREATE_BENCHMARK_FAMILY(BM_Alpha) |
| 18 | +CREATE_BENCHMARK_FAMILY(BM_Beta) |
| 19 | +CREATE_BENCHMARK_FAMILY(BM_Gamma) |
| 20 | +CREATE_BENCHMARK_FAMILY(BM_Delta) |
| 21 | +CREATE_BENCHMARK_FAMILY(BM_Epsilon) |
| 22 | +CREATE_BENCHMARK_FAMILY(BM_Zeta) |
| 23 | +CREATE_BENCHMARK_FAMILY(BM_Eta) |
| 24 | +CREATE_BENCHMARK_FAMILY(BM_Theta) |
| 25 | +CREATE_BENCHMARK_FAMILY(BM_Iota) |
| 26 | +CREATE_BENCHMARK_FAMILY(BM_Kappa) |
| 27 | +CREATE_BENCHMARK_FAMILY(BM_Lambda) |
| 28 | +CREATE_BENCHMARK_FAMILY(BM_Mu) |
| 29 | +CREATE_BENCHMARK_FAMILY(BM_Nu) |
| 30 | +CREATE_BENCHMARK_FAMILY(BM_Xi) |
| 31 | +CREATE_BENCHMARK_FAMILY(BM_Omicron) |
| 32 | + |
| 33 | +// The target benchmark we're looking for (also with 1000 instances) |
| 34 | +CREATE_BENCHMARK_FAMILY(BM_TargetBenchmark) |
| 35 | + |
| 36 | +class NullReporter : public benchmark::BenchmarkReporter { |
| 37 | + public: |
| 38 | + bool ReportContext(const Context&) override { return true; } |
| 39 | + void ReportRuns(const std::vector<Run>&) override {} |
| 40 | + void Finalize() override {} |
| 41 | +}; |
| 42 | + |
| 43 | +} // namespace |
| 44 | + |
| 45 | +int main(int argc, char** argv) { |
| 46 | + benchmark::MaybeReenterWithoutASLR(argc, argv); |
| 47 | + |
| 48 | + std::cout << "\n=== Filter Optimization Performance Test ===\n"; |
| 49 | + std::cout << "Total families: 16 (15 non-matching + 1 target)\n"; |
| 50 | + std::cout << "Total instances: 16000 (16 families × 1000 args each)\n\n"; |
| 51 | + |
| 52 | + // Measure time to filter with literal string (optimization applies) |
| 53 | + NullReporter null_reporter; |
| 54 | + |
| 55 | + std::cout << "Testing literal filter \"TargetBenchmark\"...\n"; |
| 56 | + int argc1 = 3; |
| 57 | + const char* argv1[] = {"test", "--benchmark_filter=TargetBenchmark", "--benchmark_list_tests"}; |
| 58 | + benchmark::Initialize(&argc1, const_cast<char**>(argv1)); |
| 59 | + auto start_literal = std::chrono::high_resolution_clock::now(); |
| 60 | + size_t count_literal = benchmark::RunSpecifiedBenchmarks(&null_reporter); |
| 61 | + auto end_literal = std::chrono::high_resolution_clock::now(); |
| 62 | + auto duration_literal = std::chrono::duration_cast<std::chrono::microseconds>(end_literal - start_literal); |
| 63 | + |
| 64 | + std::cout << "Testing regex filter \".*TargetBenchmark.*\"...\n"; |
| 65 | + int argc2 = 3; |
| 66 | + const char* argv2[] = {"test", "--benchmark_filter=.*TargetBenchmark.*", "--benchmark_list_tests"}; |
| 67 | + benchmark::Initialize(&argc2, const_cast<char**>(argv2)); |
| 68 | + auto start_regex = std::chrono::high_resolution_clock::now(); |
| 69 | + size_t count_regex = benchmark::RunSpecifiedBenchmarks(&null_reporter); |
| 70 | + auto end_regex = std::chrono::high_resolution_clock::now(); |
| 71 | + auto duration_regex = std::chrono::duration_cast<std::chrono::microseconds>(end_regex - start_regex); |
| 72 | + |
| 73 | + // Verify both found exactly 1000 benchmarks (all instances of BM_TargetBenchmark) |
| 74 | + if (count_literal != 1000) { |
| 75 | + std::cerr << "ERROR: Literal filter expected 1000 matches, got " << count_literal << "\n"; |
| 76 | + return -1; |
| 77 | + } |
| 78 | + if (count_regex != 1000) { |
| 79 | + std::cerr << "ERROR: Regex filter expected 1000 matches, got " << count_regex << "\n"; |
| 80 | + return -1; |
| 81 | + } |
| 82 | + |
| 83 | + std::cout << "\n=== RESULTS ===\n"; |
| 84 | + std::cout << "Literal filter \"TargetBenchmark\": " << duration_literal.count() << " μs\n"; |
| 85 | + std::cout << "Regex filter \".*TargetBenchmark.*\": " << duration_regex.count() << " μs\n\n"; |
| 86 | + |
| 87 | + if (duration_literal.count() > 0) { |
| 88 | + double speedup = static_cast<double>(duration_regex.count()) / duration_literal.count(); |
| 89 | + std::cout << "Speedup with optimization: " << speedup << "x faster\n\n"; |
| 90 | + |
| 91 | + // Verify optimization provides at least 5x speedup |
| 92 | + if (speedup < 5.0) { |
| 93 | + std::cerr << "ERROR: Expected at least 5x speedup, got " << speedup << "x\n"; |
| 94 | + std::cerr << "Optimization may not be working correctly!\n"; |
| 95 | + return -1; |
| 96 | + } |
| 97 | + } else { |
| 98 | + std::cerr << "ERROR: Literal filter completed too fast to measure accurately\n"; |
| 99 | + return -1; |
| 100 | + } |
| 101 | + |
| 102 | + std::cout << "=== WHY THE DIFFERENCE? ===\n"; |
| 103 | + std::cout << "Literal filter (\"TargetBenchmark\"):\n"; |
| 104 | + std::cout << " - Detects no regex metacharacters\n"; |
| 105 | + std::cout << " - Uses family->name_.find(\"TargetBenchmark\")\n"; |
| 106 | + std::cout << " - Skips 15 families immediately (15000 instances not generated)\n"; |
| 107 | + std::cout << " - Only processes BM_TargetBenchmark family (1000 instances generated)\n\n"; |
| 108 | + |
| 109 | + std::cout << "Regex filter (\".*TargetBenchmark.*\"):\n"; |
| 110 | + std::cout << " - Detects metacharacters (. and *)\n"; |
| 111 | + std::cout << " - Must process ALL 16 families\n"; |
| 112 | + std::cout << " - Generates all 16000 instances and regex-matches each name\n\n"; |
| 113 | + |
| 114 | + return 0; |
| 115 | +} |
0 commit comments