1find_package(Threads)
2
3include(ExternalProject)
4
5set(LLVM_LINK_COMPONENTS Support)
6
7#==============================================================================
8# Build Google Benchmark
9#==============================================================================
10set(GOOGLE_BENCHMARK_TARGET_FLAGS ${BENCHMARK_DIALECT_FLAG})
11if (LIBCXX_BENCHMARK_GCC_TOOLCHAIN)
12  set(GOOGLE_BENCHMARK_TARGET_FLAGS
13      -gcc-toolchain ${LIBCXX_BENCHMARK_GCC_TOOLCHAIN})
14endif()
15string(REPLACE ";" " " GOOGLE_BENCHMARK_TARGET_FLAGS "${GOOGLE_BENCHMARK_TARGET_FLAGS}")
16
17ExternalProject_Add(google-benchmark
18    EXCLUDE_FROM_ALL ON
19    PREFIX google-benchmark
20    SOURCE_DIR ${LIBC_SOURCE_DIR}/../llvm/utils/benchmark
21    INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/google-benchmark
22    CMAKE_CACHE_ARGS
23        -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON
24        -DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
25        -DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
26        -DCMAKE_CXX_FLAGS:STRING=${GOOGLE_BENCHMARK_TARGET_FLAGS}
27        -DCMAKE_CXX_STANDARD:STRING=14
28        -DCMAKE_BUILD_TYPE:STRING=RELEASE
29        -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
30        -DBENCHMARK_ENABLE_TESTING:BOOL=OFF)
31
32set(GOOGLE_BENCHMARK_LIBC_INSTALL ${CMAKE_CURRENT_BINARY_DIR}/google-benchmark)
33set(GOOGLE_BENCHMARK_LINK_FLAGS    -L${GOOGLE_BENCHMARK_LIBC_INSTALL}/lib/)
34
35#==============================================================================
36# Add Unit Testing Support
37#==============================================================================
38
39function(add_libc_benchmark_unittest target_name)
40  if(NOT LLVM_INCLUDE_TESTS)
41    return()
42  endif()
43
44  cmake_parse_arguments(
45    "LIBC_BENCHMARKS_UNITTEST"
46    "" # No optional arguments
47    "SUITE" # Single value arguments
48    "SRCS;DEPENDS" # Multi-value arguments
49    ${ARGN}
50  )
51
52  add_executable(${target_name}
53    EXCLUDE_FROM_ALL
54    ${LIBC_BENCHMARKS_UNITTEST_SRCS}
55  )
56  target_link_libraries(${target_name}
57    PRIVATE
58    gtest_main
59    gtest
60    ${LIBC_BENCHMARKS_UNITTEST_DEPENDS}
61  )
62
63  add_custom_command(
64    TARGET ${target_name}
65    POST_BUILD
66    COMMAND $<TARGET_FILE:${target_name}>
67  )
68  add_dependencies(libc-benchmark-util-tests ${target_name})
69endfunction()
70
71#==============================================================================
72# Build Google Benchmark for libc
73#==============================================================================
74
75add_custom_target(libc-benchmark-util-tests)
76
77function(fix_rtti target)
78    # TODO: Make this portable and inline with rtti mode from llvm/
79    target_compile_options(${target} PUBLIC -fno-rtti)
80endfunction()
81
82# libc-benchmark
83add_library(libc-benchmark
84    STATIC
85    EXCLUDE_FROM_ALL
86    LibcBenchmark.cpp
87    LibcBenchmark.h
88)
89add_dependencies(libc-benchmark google-benchmark)
90target_include_directories(libc-benchmark
91    SYSTEM PUBLIC
92    "${GOOGLE_BENCHMARK_LIBC_INSTALL}/include"
93)
94target_link_libraries(libc-benchmark
95    PUBLIC
96    "${GOOGLE_BENCHMARK_LINK_FLAGS}" # FIXME: Move to `target_link_options`
97    -lbenchmark                      # FIXME: Move to `target_link_options`
98    LLVMSupport
99    Threads::Threads
100)
101fix_rtti(libc-benchmark)
102
103add_libc_benchmark_unittest(libc-benchmark-test
104    SRCS LibcBenchmarkTest.cpp
105    DEPENDS libc-benchmark
106)
107
108# libc-memory-benchmark
109add_library(libc-memory-benchmark
110    STATIC
111    EXCLUDE_FROM_ALL
112    LibcMemoryBenchmark.cpp
113    LibcMemoryBenchmark.h
114    MemorySizeDistributions.cpp
115    MemorySizeDistributions.h
116)
117target_link_libraries(libc-memory-benchmark PUBLIC libc-benchmark)
118fix_rtti(libc-memory-benchmark)
119
120add_libc_benchmark_unittest(libc-memory-benchmark-test
121    SRCS LibcMemoryBenchmarkTest.cpp
122    DEPENDS libc-memory-benchmark
123)
124
125# json
126add_library(json
127    STATIC
128    EXCLUDE_FROM_ALL
129    JSON.cpp
130    JSON.h
131)
132target_link_libraries(json PUBLIC libc-memory-benchmark)
133fix_rtti(json)
134
135add_libc_benchmark_unittest(json-test
136    SRCS JSONTest.cpp
137    DEPENDS json
138)
139
140#==============================================================================
141# Benchmark tests configuration
142#==============================================================================
143
144function(add_libc_benchmark_analysis conf_target run_target)
145    set(png_file "/tmp/last-${conf_target}.png")
146    set(render_target render-${conf_target})
147    add_custom_target(${render_target}
148        COMMAND python3 render.py3 ${json_file} --headless --output=${png_file}
149        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
150        COMMENT "render ${libc_target} to ${png_file}"
151    )
152    add_dependencies(${render_target} ${run_target})
153
154    set(display_target display-${conf_target})
155    add_custom_target(${display_target}
156        COMMAND python3 render.py3 ${json_file}
157        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
158        COMMENT "display ${libc_target}"
159    )
160    add_dependencies(${display_target} ${run_target})
161endfunction()
162
163function(add_libc_benchmark_configuration target configuration)
164    set(conf_target ${target}-${configuration})
165    set(json_file "/tmp/last-${conf_target}.json")
166    set(run_target run-${conf_target})
167    add_custom_target(${run_target}
168        COMMAND ${libc_target} --conf=configuration_${configuration}.json -o ${json_file}
169        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
170    )
171    add_libc_benchmark_analysis(${conf_target} ${run_target})
172endfunction()
173
174function(add_libc_benchmark name file entrypoint_target)
175    set(libc_target libc-${name}-benchmark)
176    add_executable(${libc_target}
177        EXCLUDE_FROM_ALL
178        ${file}
179        LibcMemoryBenchmarkMain.h
180        LibcMemoryBenchmarkMain.cpp
181    )
182
183    get_target_property(entrypoint_object_file ${entrypoint_target} "OBJECT_FILE_RAW")
184    target_link_libraries(${libc_target} PUBLIC json ${entrypoint_object_file})
185    foreach(configuration "small" "big")
186        add_libc_benchmark_configuration(${libc_target} ${configuration})
187    endforeach()
188endfunction()
189
190add_libc_benchmark(memcpy Memcpy.cpp libc.src.string.memcpy)
191add_libc_benchmark(memset Memset.cpp libc.src.string.memset)
192