1- using System . Globalization ;
2- using System . Text ;
3- using Genbox . FastData . Generator . CPlusPlus . TestHarness . Code ;
4- using Genbox . FastData . InternalShared ;
1+ using Genbox . FastData . Generator . Extensions ;
52using Genbox . FastData . InternalShared . Harness ;
63using Genbox . FastData . InternalShared . Helpers ;
7- using Genbox . FastData . InternalShared . Misc ;
84using Genbox . FastData . InternalShared . TestClasses ;
5+ using static System . Linq . Enumerable ;
6+ using static Genbox . FastData . Generator . Helpers . FormatHelper ;
97
108namespace Genbox . FastData . Generator . CPlusPlus . TestHarness ;
119
12- public sealed class CPlusPlusBenchmark : BenchmarkBase < CPlusPlusBootstrap >
10+ public sealed class CPlusPlusBenchmark ( DockerManager dockerManager ) : BenchmarkBase < CPlusPlusBootstrap > ( new CPlusPlusBootstrap ( HarnessType . Benchmark ) , dockerManager )
1311{
14- private CPlusPlusBenchmark ( ) : base ( new CPlusPlusBootstrap ( HarnessType . Benchmark ) ) { }
15-
16- public static CPlusPlusBenchmark Instance { get ; } = new CPlusPlusBenchmark ( ) ;
17-
18- public override BenchmarkSuite CreateFiles ( IEnumerable < ITestData > data )
19- {
20- List < BenchmarkFile > files = new List < BenchmarkFile > ( ) ;
21-
22- foreach ( ITestData item in data )
23- {
24- item . Generate ( Bootstrap . GeneratorFactory , out GeneratorSpec spec ) ;
25-
26- string filename = "bench_" + spec . Identifier + ".cpp" ;
27- files . Add ( new BenchmarkFile ( filename , $$ """
28- #include <benchmark/benchmark.h>
29- using namespace benchmark;
30-
31- {{ spec . Source }}
32-
33- static void CPlusPlus_{{ spec . Identifier }} (State& state)
34- {
35- for (auto _ : state)
36- {
37- {{ RenderBenchmarkQueries ( item , spec . Identifier ) }}
38- }
39- }
40-
41- BENCHMARK(CPlusPlus_{{ spec . Identifier }} );
42- """ ) ) ;
43- }
44-
45- files . Add ( new BenchmarkFile ( "main.cpp" , """
46- #include <benchmark/benchmark.h>
47-
48- BENCHMARK_MAIN();
49- """ ) ) ;
50-
51- return new BenchmarkSuite ( "CMakeLists.txt" , BuildCMakeLists ( files . Select ( x => x . Filename ) ) , files ) ;
52- }
53-
54- public override void Run ( BenchmarkSuite suite , bool useBencher , bool useShell )
55- {
56- ProcessResult configureResult = ProcessHelper . RunProcess ( "cmake" , "-S . -B build -DCMAKE_CXX_COMPILER=\" " + ClangCompiler . CompilerPath + "\" " , Bootstrap . RootDir , 100_000 ) ;
57-
58- if ( configureResult . ExitCode != 0 )
59- throw new InvalidOperationException ( $ "Failed to configure CMake. Exit code: { configureResult . ExitCode } \n STDOUT:\n { configureResult . StandardOutput } \n STDERR:\n { configureResult . StandardError } ") ;
60-
61- ProcessResult buildResult = ProcessHelper . RunProcess ( "cmake" , "--build build --config Release" , Bootstrap . RootDir , 100_000 ) ;
62-
63- if ( buildResult . ExitCode != 0 )
64- throw new InvalidOperationException ( $ "Failed to build benchmarks. Exit code: { buildResult . ExitCode } \n STDOUT:\n { buildResult . StandardOutput } \n STDERR:\n { buildResult . StandardError } ") ;
65-
66- string executable = Path . Combine ( Bootstrap . RootDir , "build" , "out" , "all_benchmarks.exe" ) ;
67-
68- string args = useShell ? "--benchmark_min_time=5s" : "--benchmark_min_time=5s --benchmark_format=json" ;
69- BenchmarkHelper . RunBenchmark ( executable , args , Bootstrap . RootDir , "--adapter cpp_google --testbed CPlusPlus" , useBencher , useShell ) ;
70- }
71-
72- private string RenderBenchmarkQueries ( ITestData data , string identifier )
73- {
74- StringBuilder sb = new StringBuilder ( ) ;
75-
76- for ( int i = 0 ; i < 25 ; i ++ )
77- sb . AppendLine ( CultureInfo . InvariantCulture , $ " DoNotOptimize({ identifier } ::contains({ data . GetValueLabel ( Bootstrap . Map ) } ));") ;
78-
79- return sb . ToString ( ) ;
80- }
81-
82- private static string BuildCMakeLists ( IEnumerable < string > sources ) =>
12+ protected override string Render ( ITestData data ) =>
8313 $$ """
84- cmake_minimum_required(VERSION 3.20)
85-
86- if(DEFINED ENV{FASTDATA_CLANGXX})
87- set(_clangxx "$ENV{FASTDATA_CLANGXX}")
88- if(IS_DIRECTORY "${_clangxx}")
89- set(_clangxx "${_clangxx}/clang++")
90- endif()
91- if(WIN32 AND NOT EXISTS "${_clangxx}" AND EXISTS "${_clangxx}.exe")
92- set(_clangxx "${_clangxx}.exe")
93- endif()
94- set(CMAKE_CXX_COMPILER "${_clangxx}" CACHE FILEPATH "" FORCE)
95- endif()
96-
97- project(fast_data_benchmarks LANGUAGES CXX)
98- set(CMAKE_CXX_STANDARD 17)
99- set(CMAKE_CXX_STANDARD_REQUIRED ON)
100- set(CMAKE_CXX_EXTENSIONS OFF)
101-
102- set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/out")
103- set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/out")
104- set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/out")
105-
106- add_compile_options(
107- $<$<CONFIG:Release>:/O2>
108- )
109-
110- set(SOURCES
111- {{ string . Join ( Environment . NewLine , sources . Select ( source => $ " { source } ") ) }}
112- )
113-
114- add_executable(all_benchmarks ${SOURCES})
115- include(FetchContent)
116- set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "" FORCE)
117- set(BENCHMARK_ENABLE_GTEST_TESTS OFF CACHE BOOL "" FORCE)
118-
119- FetchContent_Declare(
120- benchmark
121- URL https://github.com/google/benchmark/archive/refs/tags/v1.9.5.zip
122- )
123- FetchContent_MakeAvailable(benchmark)
124- target_link_libraries(all_benchmarks PRIVATE benchmark::benchmark)
14+ #include <array>
15+ #include <chrono>
16+ #include <cstdint>
17+ #include <iomanip>
18+ #include <iostream>
19+ #include <limits>
20+ #include <locale>
21+ #include <string>
22+
23+ template <class T>
24+ inline void DoNotOptimize(T& value) {
25+ asm volatile("" : "+g"(value) : : "memory");
26+ }
27+
28+ {{ data . Generate ( Bootstrap . Generator ) }}
29+
30+ int main()
31+ {
32+ std::uint64_t found_count = 0;
33+ auto keys = std::array{ {{ FormatList ( Range ( 0 , data . QueryCount )
34+ . Select ( _ => data . GetRandomKey ( Bootstrap . Map ) )
35+ . ToArray ( ) , s => s , ", " ) }} };
36+ std::size_t key_index = 0;
37+ auto start = std::chrono::steady_clock::now();
38+
39+ for (int i = 0; i < {{ data . WorkIterations }} ; i++)
40+ {
41+ {{ FormatList ( Range ( 0 , data . QueryCount ) . ToArray ( ) , _ =>
42+ """
43+ {
44+ auto key = keys[key_index];
45+ if (++key_index == keys.size())
46+ key_index = 0;
47+
48+ DoNotOptimize(key);
49+ found_count += fastdata::contains(key) ? 1 : 0;
50+ }
51+ """ , "\n " ) }}
52+ }
53+
54+ auto end = std::chrono::steady_clock::now();
55+ double elapsed_ns = std::chrono::duration<double, std::nano>(end - start).count();
56+ double elapsed_ns_per_call = elapsed_ns / {{ Bootstrap . Map . ToValueLabel ( data . WorkIterations * data . QueryCount ) }} ;
57+
58+ DoNotOptimize(found_count);
59+
60+ std::cout.imbue(std::locale::classic());
61+ std::cout << std::setprecision(std::numeric_limits<double>::max_digits10)
62+ << elapsed_ns_per_call << '\n';
63+
64+ return 0;
65+ }
12566 """ ;
12667}
0 commit comments